public void TestBucketLogsCorrectlyWhenUserProfileFailsToSave() { Experiment experiment = ProjectConfig.Experiments[6]; Variation variation = experiment.Variations[0]; Decision decision = new Decision(variation.Id); Bucketer bucketer = new Bucketer(LoggerMock.Object); UserProfileServiceMock.Setup(up => up.Save(It.IsAny <Dictionary <string, object> >())).Throws(new System.Exception()); var experimentBucketMap = new Dictionary <string, Decision>(); experimentBucketMap[experiment.Id] = decision; UserProfile expectedUserProfile = new UserProfile(UserProfileId, experimentBucketMap); UserProfile saveUserProfile = new UserProfile(UserProfileId, new Dictionary <string, Decision>()); DecisionService decisionService = new DecisionService(bucketer, ErrorHandlerMock.Object, ProjectConfig, UserProfileServiceMock.Object, LoggerMock.Object); decisionService.SaveVariation(experiment, variation, saveUserProfile); LoggerMock.Verify(l => l.Log(LogLevel.ERROR, string.Format ("Failed to save variation \"{0}\" of experiment \"{1}\" for user \"{2}\".", variation.Id, experiment.Id, UserProfileId)) , Times.Once); ErrorHandlerMock.Verify(er => er.HandleError(It.IsAny <OptimizelySDK.Exceptions.OptimizelyRuntimeException>()), Times.Once); }
/// <summary> /// Optimizely constructor for managing Full Stack .NET projects. /// </summary> /// <param name="datafile">string JSON string representing the project</param> /// <param name="eventDispatcher">EventDispatcherInterface</param> /// <param name="logger">LoggerInterface</param> /// <param name="errorHandler">ErrorHandlerInterface</param> /// <param name="skipJsonValidation">boolean representing whether JSON schema validation needs to be performed</param> public Optimizely(string datafile, IEventDispatcher eventDispatcher = null, ILogger logger = null, IErrorHandler errorHandler = null, UserProfileService userProfileService = null, bool skipJsonValidation = false) { IsValid = false; // invalid until proven valid Logger = logger ?? new NoOpLogger(); EventDispatcher = eventDispatcher ?? new DefaultEventDispatcher(Logger); ErrorHandler = errorHandler ?? new NoOpErrorHandler(); Bucketer = new Bucketer(Logger); EventBuilder = new EventBuilder(Bucketer, Logger); UserProfileService = userProfileService; NotificationCenter = new NotificationCenter(Logger); try { if (!ValidateInputs(datafile, skipJsonValidation)) { Logger.Log(LogLevel.ERROR, "Provided 'datafile' has invalid schema."); return; } Config = ProjectConfig.Create(datafile, Logger, ErrorHandler); IsValid = true; DecisionService = new DecisionService(Bucketer, ErrorHandler, Config, userProfileService, Logger); } catch (Exception ex) { Logger.Log(LogLevel.ERROR, "Provided 'datafile' is in an invalid format. " + ex.Message); } }
public void TestGenerateBucketValue() { var bucketer = new Bucketer(LoggerMock.Object); foreach (var item in new[] { new BucketerTestItem { UserId = "ppid1", ExperimentId = "1886780721", ExpectedBucketValue = 5254 }, new BucketerTestItem { UserId = "ppid2", ExperimentId = "1886780721", ExpectedBucketValue = 4299 }, new BucketerTestItem { UserId = "ppid2", ExperimentId = "1886780722", ExpectedBucketValue = 2434 }, new BucketerTestItem { UserId = "ppid3", ExperimentId = "1886780721", ExpectedBucketValue = 5439 }, new BucketerTestItem { UserId = "a very very very very very very very very very very very very very very very long ppd string", ExperimentId = "1886780721", ExpectedBucketValue = 6128 }, }) { int result = bucketer.GenerateBucketValue(item.BucketingId); Assert.AreEqual(item.ExpectedBucketValue, result, string.Format("Unexpected Bucket Value: [{0}] for [{1}]", result, item)); } }
public void TestGetForcedVariationReturnsNullWhenUserIsNotWhitelisted() { Bucketer bucketer = new Bucketer(LoggerMock.Object); DecisionService decisionService = new DecisionService(bucketer, ErrorHandlerMock.Object, ProjectConfig, null, LoggerMock.Object); Assert.IsNull(decisionService.GetWhitelistedVariation(WhitelistedExperiment, GenericUserId)); }
public void TestBucketVariationInvalidExperimentsWithBucketingId() { var bucketer = new Bucketer(LoggerMock.Object); var expectedVariation = new Variation(); Assert.AreEqual(expectedVariation, bucketer.Bucket(Config, Config.GetExperimentFromKey("invalid_experiment"), TestBucketingIdVariation, TestUserId)); }
public void TestBucketRolloutRule() { var bucketer = new Bucketer(LoggerMock.Object); var rollout = Config.GetRolloutFromId("166660"); var rolloutRule = rollout.Experiments[1]; var expectedVariation = Config.GetVariationFromId(rolloutRule.Key, "177773"); Assert.True(TestData.CompareObjects(expectedVariation, bucketer.Bucket(Config, rolloutRule, "testBucketingId", TestUserId))); }
public void TestBucketVariationInvalidExperimentsWithBucketingId() { var bucketer = new Bucketer(LoggerMock.Object); var expectedVariation = new Variation(); var variationResult = bucketer.Bucket(Config, Config.GetExperimentFromKey("invalid_experiment"), TestBucketingIdVariation, TestUserId); Assert.AreEqual(expectedVariation, variationResult.ResultObject); Assert.AreEqual(variationResult.DecisionReasons.ToReport().Count, 0); }
public void TestBucketInvalidExperiment() { var bucketer = new Bucketer(LoggerMock.Object); Assert.AreEqual(new Variation { }, bucketer.Bucket(Config, new Experiment(), TestBucketingIdControl, TestUserId)); LoggerMock.Verify(l => l.Log(It.IsAny <LogLevel>(), It.IsAny <string>()), Times.Never); }
public void TestBucketValidExperimentInGroupUserInForcedVariation() { var bucketer = new Bucketer(LoggerMock.Object); Assert.AreEqual(new Variation { Id = "7722260071", Key = "group_exp_1_var_1" }, bucketer.Bucket(Config, Config.GetExperimentFromKey("group_experiment_1"), TestBucketingIdControl, "user1")); LoggerMock.Verify(l => l.Log(LogLevel.INFO, "User [user1] is forced into variation [group_exp_1_var_1].")); LoggerMock.Verify(l => l.Log(It.IsAny <LogLevel>(), It.IsAny <string>()), Times.Exactly(1)); }
public void TestBucketVariationGroupedExperimentsWithBucketingId() { var bucketer = new Bucketer(LoggerMock.Object); var expectedVariation = new Variation(); var expectedGroupVariation = new Variation { Id = "7725250007", Key = "group_exp_2_var_2" }; Assert.AreEqual(expectedGroupVariation, bucketer.Bucket(Config, Config.GetExperimentFromKey("group_experiment_2"), TestBucketingIdGroupExp2Var2, TestUserIdBucketsToNoGroup)); }
public void TestBucketWithBucketingId() { var bucketer = new Bucketer(LoggerMock.Object); var experiment = Config.GetExperimentFromKey("test_experiment"); var expectedVariation = new Variation { Id = "7722370027", Key = "control" }; var expectedVariation2 = new Variation { Id = "7721010009", Key = "variation" }; // make sure that the bucketing ID is used for the variation bucketing and not the user ID Assert.AreEqual(expectedVariation, bucketer.Bucket(Config, experiment, TestBucketingIdControl, TestUserIdBucketsToVariation)); }
private void InitializeComponents(IEventDispatcher eventDispatcher = null, ILogger logger = null, IErrorHandler errorHandler = null, UserProfileService userProfileService = null, NotificationCenter notificationCenter = null, EventProcessor eventProcessor = null) { Logger = logger ?? new NoOpLogger(); EventDispatcher = eventDispatcher ?? new DefaultEventDispatcher(Logger); ErrorHandler = errorHandler ?? new NoOpErrorHandler(); Bucketer = new Bucketer(Logger); EventBuilder = new EventBuilder(Bucketer, Logger); UserProfileService = userProfileService; NotificationCenter = notificationCenter ?? new NotificationCenter(Logger); DecisionService = new DecisionService(Bucketer, ErrorHandler, userProfileService, Logger); EventProcessor = eventProcessor ?? new ForwardingEventProcessor(EventDispatcher, NotificationCenter, Logger); }
public void TestGetStoredVariationLogsWhenLookupReturnsNull() { Experiment experiment = ProjectConfig.Experiments[6]; UserProfileService userProfileService = UserProfileServiceMock.Object; UserProfile userProfile = new UserProfile(UserProfileId, new Dictionary <string, Decision>()); Bucketer bucketer = new Bucketer(LoggerMock.Object); UserProfileServiceMock.Setup(_ => _.Lookup(UserProfileId)).Returns(userProfile.ToMap()); DecisionService decisionService = new DecisionService(bucketer, ErrorHandlerMock.Object, ProjectConfig, userProfileService, LoggerMock.Object); Assert.IsNull(decisionService.GetStoredVariation(experiment, userProfile)); LoggerMock.Verify(l => l.Log(LogLevel.INFO, string.Format("No previously activated variation of experiment \"{0}\" for user \"{1}\" found in user profile." , experiment.Key, UserProfileId)), Times.Once); }
public void TestBucketRolloutRule() { var bucketer = new Bucketer(LoggerMock.Object); var rollout = Config.GetRolloutFromId("166660"); var rolloutRule = rollout.Experiments[1]; var expectedVariation = Config.GetVariationFromId(rolloutRule.Key, "177773"); var variationResult = bucketer.Bucket(Config, rolloutRule, "testBucketingId", TestUserId); Assert.True(TestData.CompareObjects(expectedVariation, variationResult.ResultObject)); Assert.AreEqual(variationResult.DecisionReasons.ToReport().Count, 0); var variationsResult = bucketer.Bucket(Config, rolloutRule, "testBucketingId", TestUserId); Assert.True(TestData.CompareObjects(expectedVariation, variationsResult.ResultObject)); Assert.AreEqual(variationsResult.DecisionReasons.ToReport(true).Count, 1); Assert.AreEqual(variationsResult.DecisionReasons.ToReport(true)[0], "User [testUserId] is in variation [177773] of experiment [177772]."); }
public void OnBeforeQuery(ITable table) { // Find approximate 10th and 90th percentile values for this query PercentilesQuery pq = new PercentilesQuery(); pq.Column = this.Column; pq.TableName = this.TableName; pq.Where = this.Where; pq.Percentiles = new double[] { 0.10, 0.90 }; DataBlockResult result = table.Query(pq); if (result.Values != null) { // Try to choose buckets if the 10th and 90th percentile values were returned [returns null for unsupported types] Bucketer bucketer = NativeContainer.CreateTypedInstance <Bucketer>(typeof(Bucketer <>), ((Table)table).GetColumnType(this.Column)); this.Buckets = bucketer.GetBuckets(result.Values, this.Inclusive, this.BucketCount); } }
public void TestBucketVariationGroupedExperimentsWithBucketingId() { var bucketer = new Bucketer(LoggerMock.Object); var expectedVariation = new Variation(); var expectedGroupVariation = new Variation { Id = "7725250007", Key = "group_exp_2_var_2" }; var variationResult = bucketer.Bucket(Config, Config.GetExperimentFromKey("group_experiment_2"), TestBucketingIdGroupExp2Var2, TestUserIdBucketsToNoGroup); Assert.AreEqual(expectedGroupVariation, variationResult.ResultObject); Assert.AreEqual(variationResult.DecisionReasons.ToReport().Count, 0); bucketer.Bucket(Config, Config.GetExperimentFromKey("group_experiment_2"), TestBucketingIdGroupExp2Var2, TestUserIdBucketsToNoGroup); var report = variationResult.DecisionReasons.ToReport(true); Assert.AreEqual(report.Count, 2); Assert.AreEqual(report[0], "User [testUserId] is in experiment [group_experiment_2] of group [7722400015]."); Assert.AreEqual(report[1], "User [testUserId] is in variation [group_exp_2_var_2] of experiment [group_experiment_2]."); }
public DataBlockResult Compute(Partition p) { if (p == null) { throw new ArgumentNullException("p"); } DataBlockResult result = new DataBlockResult(this); // Verify the column exists if (!p.ContainsColumn(this.Column)) { result.Details.AddError(ExecutionDetails.ColumnDoesNotExist, this.Column); return(result); } // Verify we were able to get percentile values if (this.Buckets == null) { result.Details.AddError(ExecutionDetails.ColumnDoesNotSupportOperator, "percentile", this.Column); return(result); } // Find the set of items matching the where clause ShortSet whereSet = new ShortSet(p.Count); this.Where.TryEvaluate(p, whereSet, result.Details); IUntypedColumn column = p.Columns[this.Column]; if (result.Details.Succeeded) { Bucketer bucketer = NativeContainer.CreateTypedInstance <Bucketer>(typeof(Bucketer <>), column.ColumnType); result.Values = bucketer.Bucket(column.InnerColumn, whereSet, this.Buckets, this.Inclusive); result.Total = whereSet.Count(); } return(result); }
public void TestGetStoredVariationReturnsNullWhenVariationIsNoLongerInConfig() { Experiment experiment = ProjectConfig.Experiments[6]; string storedVariationId = "missingVariation"; Decision storedDecision = new Decision(storedVariationId); var storedDecisions = new Dictionary <string, Decision>(); storedDecisions[experiment.Id] = storedDecision; UserProfile storedUserProfile = new UserProfile(UserProfileId, storedDecisions); Bucketer bucketer = new Bucketer(LoggerMock.Object); UserProfileServiceMock.Setup(up => up.Lookup(UserProfileId)).Returns(storedUserProfile.ToMap()); DecisionService decisionService = new DecisionService(bucketer, ErrorHandlerMock.Object, ProjectConfig, UserProfileServiceMock.Object, LoggerMock.Object); Assert.IsNull(decisionService.GetStoredVariation(experiment, storedUserProfile)); LoggerMock.Verify(l => l.Log(LogLevel.INFO, string.Format("User \"{0}\" was previously bucketed into variation with ID \"{1}\" for experiment \"{2}\", but no matching variation was found for that user. We will re-bucket the user." , UserProfileId, storedVariationId, experiment.Id)), Times.Once); }
public void TestBucketWithBucketingId() { var bucketer = new Bucketer(LoggerMock.Object); var experiment = Config.GetExperimentFromKey("test_experiment"); var expectedVariation = new Variation { Id = "7722370027", Key = "control" }; var expectedVariation2 = new Variation { Id = "7721010009", Key = "variation" }; // make sure that the bucketing ID is used for the variation bucketing and not the user ID var variationResult = bucketer.Bucket(Config, experiment, TestBucketingIdControl, TestUserIdBucketsToVariation); Assert.AreEqual(expectedVariation, variationResult.ResultObject); Assert.AreEqual(variationResult.DecisionReasons.ToReport().Count, 0); variationResult = bucketer.Bucket(Config, experiment, TestBucketingIdControl, TestUserIdBucketsToVariation); Assert.AreEqual(expectedVariation, variationResult.ResultObject); Assert.AreEqual(variationResult.DecisionReasons.ToReport(true).Count, 1); Assert.AreEqual(variationResult.DecisionReasons.ToReport(true)[0], "User [bucketsToVariation!] is in variation [control] of experiment [test_experiment]."); }
public EventBuilder(Bucketer bucketer, ILogger logger = null) { Bucketer = bucketer; Logger = logger ?? new DefaultLogger(); ResetParams(); }
public EventBuilder(Bucketer bucketer) { Bucketer = bucketer; ResetParams(); }