示例#1
0
        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);
        }
示例#2
0
        /// <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);
            }
        }
示例#3
0
        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));
            }
        }
示例#4
0
        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));
        }
示例#5
0
        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));
        }
示例#6
0
        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)));
        }
示例#7
0
        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);
        }
示例#8
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);
        }
示例#9
0
        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));
        }
示例#10
0
        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));
        }
示例#11
0
        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));
        }
示例#12
0
 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);
 }
示例#13
0
        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);
        }
示例#14
0
        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].");
        }
示例#15
0
        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);
            }
        }
示例#16
0
        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].");
        }
示例#17
0
        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);
        }
示例#18
0
        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);
        }
示例#19
0
        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].");
        }
示例#20
0
 public EventBuilder(Bucketer bucketer, ILogger logger = null)
 {
     Bucketer = bucketer;
     Logger   = logger ?? new DefaultLogger();
     ResetParams();
 }
示例#21
0
 public EventBuilder(Bucketer bucketer)
 {
     Bucketer = bucketer;
     ResetParams();
 }