Example #1
0
        internal static SegmentRule ReadSegmentRule(ref JReader reader)
        {
            ImmutableList <Clause> clauses = null;
            int?          weight           = null;
            UserAttribute?bucketBy         = null;

            for (var obj = reader.Object(); obj.Next(ref reader);)
            {
                switch (obj.Name)
                {
                case var n when n == "clauses":
                    clauses = SerializationHelpers.ReadClauses(ref reader);
                    break;

                case var n when n == "weight":
                    weight = reader.IntOrNull();
                    break;

                case var n when n == "bucketBy":
                    var s = reader.StringOrNull();
                    bucketBy = s is null ? (UserAttribute?)null : UserAttribute.ForName(s);
                    break;
                }
            }
            return(new SegmentRule(clauses, weight, bucketBy));
        }
Example #2
0
        public void TestBucketUserByFloatAttr()
        {
            var user   = User.Builder("userKey").Custom("floatAttr", 999.999F).Build();
            var bucket = Bucketing.BucketUser(user, "hashKey", UserAttribute.ForName("floatAttr"), "saltyA");

            Assert.Equal(0, bucket, 15);
        }
        public void CanSetValuePerUser()
        {
            _td.Update(_td.Flag("flag")
                       .Variations(LdValue.Of("red"), LdValue.Of("green"), LdValue.Of("blue"))
                       .Variation(LdValue.Of("red"))
                       .VariationForUser("user1", LdValue.Of("green"))
                       .VariationForUser("user2", LdValue.Of("blue"))
                       .VariationFunc(user =>
                                      user.GetAttribute(UserAttribute.ForName("favoriteColor"))
                                      ));
            var user1 = User.WithKey("user1");
            var user2 = User.WithKey("user2");
            var user3 = User.Builder("user3").Custom("favoriteColor", "green").Build();

            using (var client = LdClient.Init(_config, user1, TimeSpan.FromSeconds(1)))
            {
                Assert.Equal("green", client.StringVariation("flag", ""));

                client.Identify(user2, TimeSpan.FromSeconds(1));

                Assert.Equal("blue", client.StringVariation("flag", ""));

                client.Identify(user3, TimeSpan.FromSeconds(1));

                Assert.Equal("green", client.StringVariation("flag", ""));
            }
        }
Example #4
0
 /// <summary>
 /// Marks a set of attribute names as private.
 /// </summary>
 /// <remarks>
 /// <para>
 /// Any users sent to LaunchDarkly with this configuration active will have attributes with these
 /// names removed. This is in addition to any attributes that were marked as private for an
 /// individual user with <see cref="UserBuilder"/> methods.
 /// </para>
 /// <para>
 /// Using <see cref="PrivateAttributes(UserAttribute[])"/> is preferable to avoid the possibility of
 /// misspelling a built-in attribute.
 /// </para>
 /// </remarks>
 /// <param name="attributes">a set of names that will be removed from user data set to LaunchDarkly</param>
 /// <returns>the builder</returns>
 /// <seealso cref="PrivateAttributes(UserAttribute[])"/>
 public EventProcessorBuilder PrivateAttributeNames(params string[] attributes)
 {
     foreach (var a in attributes)
     {
         _privateAttributes.Add(UserAttribute.ForName(a));
     }
     return(this);
 }
        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 PrivateAttributeNames()
        {
            var b = _tester.New();

            Assert.Empty(b._privateAttributes);
            b.PrivateAttributeNames("name");
            b.PrivateAttributeNames("email", "other");
            Assert.Equal(new HashSet <UserAttribute> {
                UserAttribute.Name, UserAttribute.Email, UserAttribute.ForName("other")
            }, b._privateAttributes);
        }
Example #7
0
        public void TestBucketUserByIntAttr()
        {
            var user   = User.Builder("userKey").Custom("intAttr", 33333).Build();
            var bucket = Bucketing.BucketUser(user, "hashKey", UserAttribute.ForName("intAttr"), "saltyA");

            Assert.Equal(0.54771423, bucket, 7);

            user = User.Builder("userKey").Custom("stringAttr", "33333").Build();
            var bucket2 = Bucketing.BucketUser(user, "hashKey", UserAttribute.ForName("stringAttr"), "saltyA");

            Assert.Equal(bucket, bucket2, 15);
        }
        private void TestPrivateAttribute(string privateAttrName, bool globallyPrivate)
        {
            var builder = User.Builder("userkey")
                .Anonymous(true)
                .Secondary("s");
            var topJsonBuilder = LdValue.BuildObject()
                .Add("key", "userkey")
                .Add("anonymous", true)
                .Add("secondary", "s");
            var customJsonBuilder = LdValue.BuildObject();
            Action<string, Func<string, IUserBuilderCanMakeAttributePrivate>, string, LdValue.ObjectBuilder> setAttr =
                (attrName, setter, value, jsonBuilder) =>
                {
                    if (attrName == privateAttrName)
                    {
                        if (globallyPrivate)
                        {
                            setter(value);
                        }
                        else
                        {
                            setter(value).AsPrivateAttribute();
                        }
                    }
                    else
                    {
                        setter(value);
                        jsonBuilder.Add(attrName, value);
                    }
                };
            setAttr("avatar", builder.Avatar, "http://avatar", topJsonBuilder);
            setAttr("country", builder.Country, "US", topJsonBuilder);
            setAttr("custom1", v => builder.Custom("custom1", v), "value1", customJsonBuilder);
            setAttr("custom2", v => builder.Custom("custom2", v), "value2", customJsonBuilder);
            setAttr("email", builder.Email, "*****@*****.**", topJsonBuilder);
            setAttr("firstName", builder.FirstName, "first", topJsonBuilder);
            setAttr("ip", builder.IPAddress, "1.2.3.4", topJsonBuilder);
            setAttr("lastName", builder.LastName, "last", topJsonBuilder);
            setAttr("name", builder.Name, "me", topJsonBuilder);

            topJsonBuilder.Add("custom", customJsonBuilder.Build());
            topJsonBuilder.Add("privateAttrs", LdValue.ArrayOf(LdValue.Of(privateAttrName)));
            var userJson = topJsonBuilder.Build();
            var config = new EventsConfiguration();
            if (globallyPrivate)
            {
                config.PrivateAttributeNames = ImmutableHashSet.Create<UserAttribute>(
                    UserAttribute.ForName(privateAttrName));
            };

            TestInlineUserSerialization(builder.Build(), userJson, config);
        }
Example #9
0
        public EventUser Build()
        {
            _result.Key       = _user.Key;
            _result.Secondary = StringAttrIfNotPrivate(UserAttribute.Secondary);
            _result.Anonymous = _user.Anonymous ? (bool?)true : null;
            _result.IPAddress = StringAttrIfNotPrivate(UserAttribute.IPAddress);
            _result.Country   = StringAttrIfNotPrivate(UserAttribute.Country);
            _result.FirstName = StringAttrIfNotPrivate(UserAttribute.FirstName);
            _result.LastName  = StringAttrIfNotPrivate(UserAttribute.LastName);
            _result.Name      = StringAttrIfNotPrivate(UserAttribute.Name);
            _result.Avatar    = StringAttrIfNotPrivate(UserAttribute.Avatar);
            _result.Email     = StringAttrIfNotPrivate(UserAttribute.Email);

            // With the custom attributes, for efficiency's sake we would like to reuse the same ImmutableDictionary
            // whenever possible. So, we'll lazily create a new collection only if it turns out that there are any
            // changes needed (i.e. if one of the custom attributes turns out to be private).
            ImmutableDictionary <string, LdValue> .Builder customAttrsBuilder = null;
            foreach (var kv in _user.Custom)
            {
                if (!CheckPrivateAttr(UserAttribute.ForName(kv.Key)))
                {
                    if (customAttrsBuilder is null)
                    {
                        // This is the first private custom attribute we've found. Lazily create the builder
                        // by first copying all of the ones we've already iterated over. We can rely on the
                        // iteration order being the same because it's immutable.
                        customAttrsBuilder = ImmutableDictionary.CreateBuilder <string, LdValue>();
                        foreach (var kv1 in _user.Custom)
                        {
                            if (kv1.Key == kv.Key)
                            {
                                break;
                            }
                            customAttrsBuilder[kv1.Key] = kv1.Value;
                        }
                    }
                }
                else
                {
                    // It's not a private attribute.
                    if (customAttrsBuilder != null)
                    {
                        customAttrsBuilder[kv.Key] = kv.Value;
                    }
                }
            }
            var custom = customAttrsBuilder is null ? _user.Custom : customAttrsBuilder.ToImmutable();

            _result.Custom       = custom.Count == 0 ? null : custom;
            _result.PrivateAttrs = _privateAttrs is null ? null : _privateAttrs.ToImmutable();
            return(_result);
        }
        public static void UsersEqualExcludingAutoProperties(User expected, User actual)
        {
            var builder = User.Builder(expected);

            foreach (var autoProp in new string[] { "device", "os" })
            {
                if (!actual.GetAttribute(UserAttribute.ForName(autoProp)).IsNull)
                {
                    builder.Custom(autoProp, actual.GetAttribute(UserAttribute.ForName(autoProp)));
                }
            }
            UsersEqual(builder.Build(), actual);
        }
        internal static Rollout?ReadRollout(ref JReader r)
        {
            ImmutableList <WeightedVariation> variations = null;
            UserAttribute?bucketBy = null;
            var           obj      = r.ObjectOrNull();

            if (!obj.IsDefined)
            {
                return(null);
            }
            while (obj.Next(ref r))
            {
                switch (obj.Name)
                {
                case var n when n == "variations":
                    var listBuilder = ImmutableList.CreateBuilder <WeightedVariation>();
                    for (var arr = r.ArrayOrNull(); arr.Next(ref r);)
                    {
                        int variation = 0, weight = 0;
                        for (var wvObj = r.Object(); wvObj.Next(ref r);)
                        {
                            switch (wvObj.Name)
                            {
                            case var nn when nn == "variation":
                                variation = r.Int();
                                break;

                            case var nn when nn == "weight":
                                weight = r.Int();
                                break;
                            }
                        }
                        listBuilder.Add(new WeightedVariation(variation, weight));
                    }
                    variations = listBuilder.ToImmutable();
                    break;

                case var n when n == "bucketBy":
                    var s = r.StringOrNull();
                    bucketBy = s is null ? (UserAttribute?)null : UserAttribute.ForName(s);
                    break;
                }
            }
            return(new Rollout(variations, bucketBy));
        }
 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 #13
0
        internal static ImmutableList <Clause> ReadClauses(ref JReader r)
        {
            var builder = ImmutableList.CreateBuilder <Clause>();

            for (var arr = r.ArrayOrNull(); arr.Next(ref r);)
            {
                UserAttribute           attribute = new UserAttribute();
                Operator                op        = null;
                ImmutableList <LdValue> values    = null;
                bool negate = false;
                for (var obj = r.Object(); obj.Next(ref r);)
                {
                    switch (obj.Name)
                    {
                    case var n when n == "attribute":
                        attribute = UserAttribute.ForName(r.String());
                        break;

                    case var n when n == "op":
                        op = Operator.ForName(r.String());
                        // Operator.ForName never returns null - unrecognized operators return a stub object
                        break;

                    case var n when n == "values":
                        values = ReadValues(ref r);
                        break;

                    case var n when n == "negate":
                        negate = r.Bool();
                        break;
                    }
                }
                builder.Add(new Clause(attribute, op, values, negate));
            }
            return(builder.ToImmutable());
        }
Example #14
0
        internal static Rollout?ReadRollout(ref JReader r)
        {
            ImmutableList <WeightedVariation> variations = null;
            UserAttribute?bucketBy = null;
            RolloutKind   kind     = RolloutKind.Rollout;
            int?          seed     = null;
            var           obj      = r.ObjectOrNull();

            if (!obj.IsDefined)
            {
                return(null);
            }
            while (obj.Next(ref r))
            {
                switch (obj.Name)
                {
                case var n when n == "variations":
                    var listBuilder = ImmutableList.CreateBuilder <WeightedVariation>();
                    for (var arr = r.ArrayOrNull(); arr.Next(ref r);)
                    {
                        int  variation = 0, weight = 0;
                        bool untracked = false;
                        for (var wvObj = r.Object(); wvObj.Next(ref r);)
                        {
                            switch (wvObj.Name)
                            {
                            case var nn when nn == "variation":
                                variation = r.Int();
                                break;

                            case var nn when nn == "weight":
                                weight = r.Int();
                                break;

                            case var nn when nn == "untracked":
                                untracked = r.Bool();
                                break;
                            }
                        }
                        listBuilder.Add(new WeightedVariation(variation, weight, untracked));
                    }
                    variations = listBuilder.ToImmutable();
                    break;

                case var n when n == "bucketBy":
                    var s = r.StringOrNull();
                    bucketBy = s is null ? (UserAttribute?)null : UserAttribute.ForName(s);
                    break;

                case var n when n == "kind":
                    var kindStr = r.StringOrNull();
                    kind = "experiment".Equals(kindStr) ? RolloutKind.Experiment : RolloutKind.Rollout;
                    break;

                case var n when n == "seed":
                    seed = r.IntOrNull();
                    break;
                }
            }
            return(new Rollout(kind, seed, variations, bucketBy));
        }
Example #15
0
 public ClauseBuilder Attribute(string attribute) =>
 Attribute(UserAttribute.ForName(attribute));