public void CanBucketByIntAttributeSameAsString()
        {
            var user = User.Builder("key")
                       .Custom("stringattr", "33333")
                       .Custom("intattr", 33333)
                       .Build();
            var resultForString = Bucketing.BucketUser(null, user, "key", UserAttribute.ForName("stringattr"), "salt");
            var resultForInt    = Bucketing.BucketUser(null, user, "key", UserAttribute.ForName("intattr"), "salt");

            Assert.Equal((double)resultForInt, (double)resultForString, 10);
        }
        public void FlagKeyAndSaltDoNotMatterWhenSeedIsUsed()
        {
            var          user = User.WithKey("userkey");
            const string flagKey1 = "flagkey", flagKey2 = "flagkey2";
            const string salt1 = "salt", salt2 = "salt2";
            const int    seed = 123;

            var bucketValue1 = Bucketing.BucketUser(seed, user, flagKey1, UserAttribute.Key, salt1);
            var bucketValue2 = Bucketing.BucketUser(seed, user, flagKey2, UserAttribute.Key, salt2);

            Assert.Equal(bucketValue1, bucketValue2);
        }
        public void DifferentSeedsProduceDifferentAssignment()
        {
            var          user = User.WithKey("userkey");
            const string flagKey = "flagkey";
            const string salt = "salt";
            const int    seed1 = 123, seed2 = 456;

            var bucketValue1 = Bucketing.BucketUser(seed1, user, flagKey, UserAttribute.Key, salt);
            var bucketValue2 = Bucketing.BucketUser(seed2, user, flagKey, UserAttribute.Key, salt);

            Assert.NotEqual(bucketValue1, bucketValue2);
        }
        public void UsingSeedIsDifferentThanSalt()
        {
            var          user    = User.WithKey("userkey");
            const string flagKey = "flagkey";
            const string salt    = "salt";
            const int    seed    = 123;

            var bucketValue1 = Bucketing.BucketUser(null, user, flagKey, UserAttribute.Key, salt);
            var bucketValue2 = Bucketing.BucketUser(seed, user, flagKey, UserAttribute.Key, salt);

            Assert.NotEqual(bucketValue1, bucketValue2);
        }
        public void UserSecondaryKeyAffectsBucketValue()
        {
            var          user1   = User.WithKey("key");
            var          user2   = User.Builder("key").Secondary("other").Build();
            const string flagKey = "flagkey";
            const string salt    = "salt";

            var result1 = Bucketing.BucketUser(null, user1, flagKey, UserAttribute.Key, salt);
            var result2 = Bucketing.BucketUser(null, user2, flagKey, UserAttribute.Key, salt);

            Assert.NotEqual(result1, result2);
        }
Example #6
0
        public void BucketUserByKeyTest()
        {
            var user1  = User.WithKey("userKeyA");
            var point1 = Bucketing.BucketUser(noSeed, user1, "hashKey", UserAttribute.Key, "saltyA");

            Assert.Equal(0.42157587, point1, decimalPlacesOfEquality);

            var user2  = User.WithKey("userKeyB");
            var point2 = Bucketing.BucketUser(noSeed, user2, "hashKey", UserAttribute.Key, "saltyA");

            Assert.Equal(0.6708485, point2, decimalPlacesOfEquality);

            var user3  = User.WithKey("userKeyC");
            var point3 = Bucketing.BucketUser(noSeed, user3, "hashKey", UserAttribute.Key, "saltyA");

            Assert.Equal(0.10343106, point3, decimalPlacesOfEquality);
        }
        public void LastBucketIsUsedIfBucketValueEqualsTotalWeight()
        {
            var          user    = User.WithKey("userkey");
            const string flagKey = "flagkey";
            const string salt    = "salt";

            // We'll construct a list of variations that stops right at the target bucket value
            int bucketValue = (int)(Bucketing.BucketUser(null, user, flagKey, UserAttribute.Key, salt) * 100000);

            var variations = new List <WeightedVariation>()
            {
                new WeightedVariation(0, bucketValue, true)
            };
            var rollout = new Rollout(RolloutKind.Rollout, null, variations, null);

            AssertVariationIndexFromRollout(0, rollout, user, flagKey, salt);
        }
 public void CannotBucketByOtherDataTypes()
 {
     foreach (var attributeValue in new LdValue[] {
         LdValue.Null,
         LdValue.Of(true),
         LdValue.Of(33333.5)
     })
     {
         var user = User.Builder("key")
                    .Custom("badattr", attributeValue)
                    .Build();
         var result = Bucketing.BucketUser(null, user, "key", UserAttribute.ForName("badattr"), "salt");
         if (result != 0f)
         {
             Assert.True(false, "got unexpected value " + result + " for attribute value " + attributeValue);
         }
     }
 }
Example #9
0
        public void BucketUserWithSeedTest()
        {
            const int seed = 61;

            var user1  = User.WithKey("userKeyA");
            var point1 = Bucketing.BucketUser(seed, user1, "hashKey", UserAttribute.Key, "saltyA");

            Assert.Equal(0.09801207, point1, decimalPlacesOfEquality);

            var user2  = User.WithKey("userKeyB");
            var point2 = Bucketing.BucketUser(seed, user2, "hashKey", UserAttribute.Key, "saltyA");

            Assert.Equal(0.14483777, point2, decimalPlacesOfEquality);

            var user3  = User.WithKey("userKeyC");
            var point3 = Bucketing.BucketUser(seed, user3, "hashKey", UserAttribute.Key, "saltyA");

            Assert.Equal(0.9242641, point3, decimalPlacesOfEquality);
        }
Example #10
0
            private EvaluationDetail <LdValue> GetValueForVariationOrRollout(int?variation, Rollout?rollout, EvaluationReason reason)
            {
                if (variation.HasValue)
                {
                    return(GetVariation(variation.Value, reason));
                }

                if (rollout.HasValue && rollout.Value.Variations.Count() > 0)
                {
                    WeightedVariation?selectedVariation = null;
                    var   bucketBy = rollout.Value.BucketBy.GetValueOrDefault(UserAttribute.Key);
                    float bucket   = Bucketing.BucketUser(rollout.Value.Seed, _user, _flag.Key, bucketBy, _flag.Salt);
                    float sum      = 0F;
                    foreach (WeightedVariation wv in rollout.Value.Variations)
                    {
                        sum += (float)wv.Weight / 100000F;
                        if (bucket < sum)
                        {
                            selectedVariation = wv;
                            break;
                        }
                    }
                    if (!selectedVariation.HasValue)
                    {
                        // The user's bucket value was greater than or equal to the end of the last bucket. This could happen due
                        // to a rounding error, or due to the fact that we are scaling to 100000 rather than 99999, or the flag
                        // data could contain buckets that don't actually add up to 100000. Rather than returning an error in
                        // this case (or changing the scaling, which would potentially change the results for *all* users), we
                        // will simply put the user in the last bucket.
                        selectedVariation = rollout.Value.Variations.Last();
                    }
                    var inExperiment = (rollout.Value.Kind == RolloutKind.Experiment) && !selectedVariation.Value.Untracked;
                    return(GetVariation(selectedVariation.Value.Variation,
                                        inExperiment ? reason.WithInExperiment(true) : reason));
                }
                else
                {
                    _parent._logger.Error("Data inconsistency in feature flag \"{0}\": variation/rollout object with no variation or rollout", _flag.Key);
                    return(ErrorResult(EvaluationErrorKind.MalformedFlag));
                }
            }
Example #11
0
            private bool MatchSegmentRule(Segment segment, SegmentRule segmentRule)
            {
                foreach (var c in segmentRule.Clauses)
                {
                    if (!MatchClauseNoSegments(c))
                    {
                        return(false);
                    }
                }

                // If the Weight is absent, this rule matches
                if (!segmentRule.Weight.HasValue)
                {
                    return(true);
                }

                // All of the clauses are met. See if the user buckets in
                var    by     = segmentRule.BucketBy.GetValueOrDefault(UserAttribute.Key);
                double bucket = Bucketing.BucketUser(null, _user, segment.Key, by, segment.Salt);
                double weight = (double)segmentRule.Weight / 100000F;

                return(bucket < weight);
            }
        public void VariationIndexForBucket()
        {
            var          user    = User.WithKey("userkey");
            const string flagKey = "flagkey";
            const string salt    = "salt";

            // First verify that with our test inputs, the bucket value will be greater than zero and less than 100000,
            // so we can construct a rollout whose second bucket just barely contains that value
            var bucketValue = (int)(Bucketing.BucketUser(null, user, flagKey, UserAttribute.Key, salt) * 100000);

            Assert.InRange(bucketValue, 1, 99999);

            const int badVariationA = 0, matchedVariation = 1, badVariationB = 2;
            var       variations = new List <WeightedVariation>()
            {
                new WeightedVariation(badVariationA, bucketValue, true), // end of bucket range is not inclusive, so it will *not* match the target value
                new WeightedVariation(matchedVariation, 1, true),        // size of this bucket is 1, so it only matches that specific value
                new WeightedVariation(badVariationB, 100000 - (bucketValue + 1), true)
            };
            var rollout = new Rollout(RolloutKind.Rollout, null, variations, null);

            AssertVariationIndexFromRollout(matchedVariation, rollout, user, flagKey, salt);
        }