private FeatureFlag BuildFlag()
        {
            var clause  = new ClauseBuilder().Attribute("name").Op("in").Values(new JValue("x")).Negate(true).Build();
            var wv      = new WeightedVariation(0, 50);
            var rollout = new Rollout(new List <WeightedVariation> {
                wv
            }, "key");
            var rule = new RuleBuilder().Id("ruleid").Variation(0).Rollout(rollout).Clauses(clause)
                       .TrackEvents(true).Build();
            var target = new Target(new List <string> {
                "userkey"
            }, 0);

            return(new FeatureFlagBuilder("flagkey")
                   .DebugEventsUntilDate(100000)
                   .Deleted(true)
                   .Fallthrough(new VariationOrRollout(0, rollout))
                   .OffVariation(0)
                   .On(true)
                   .Prerequisites(new Prerequisite("prereq", 1))
                   .Rules(rule)
                   .Salt("NaCl")
                   .Targets(target)
                   .TrackEvents(true)
                   .TrackEventsFallthrough(true)
                   .Variations(new JValue("value"))
                   .Version(100)
                   .Build());
        }
        public void EventTrackingAndReasonAreNotForcedIfFlagIsNotSetForMatchingRule()
        {
            var clause0 = ClauseBuilder.ShouldNotMatchUser(user);
            var clause1 = ClauseBuilder.ShouldMatchUser(user);
            var rule0   = new RuleBuilder().Id("id0").Variation(1).Clauses(clause0).TrackEvents(true).Build();
            var rule1   = new RuleBuilder().Id("id1").Variation(1).Clauses(clause1).TrackEvents(false).Build();
            var flag    = new FeatureFlagBuilder("flag")
                          .On(true)
                          .Rules(rule0, rule1)
                          .OffVariation(0)
                          .Variations(new JValue("off"), new JValue("on"))
                          .Build();

            featureStore.Upsert(VersionedDataKind.Features, flag);

            client.StringVariation("flag", user, "default");

            // It matched rule1, which has trackEvents: false, so we don't get the override behavior

            Assert.Equal(1, eventSink.Events.Count);
            var e = Assert.IsType <FeatureRequestEvent>(eventSink.Events[0]);

            Assert.False(e.TrackEvents);
            Assert.Null(e.Reason);
        }
        public void ClauseWithUnknownOperatorDoesNotMatch()
        {
            var clause = new ClauseBuilder().Attribute("name").Op("invalidOp").Values(new JValue("Bob")).Build();
            var f      = BooleanFlagWithClauses(clause);
            var user   = User.Builder("key").Name("Bob").Build();

            Assert.Equal(LdValue.Of(false), f.Evaluate(user, featureStore, EventFactory.Default).Result.Value);
        }
        public void ClauseReturnsFalseForMissingAttribute()
        {
            var clause = new ClauseBuilder().Attribute("legs").Op("in").Values(new JValue(4)).Build();
            var f      = BooleanFlagWithClauses(clause);
            var user   = User.Builder("key").Name("bob").Build();

            Assert.Equal(LdValue.Of(false), f.Evaluate(user, featureStore, EventFactory.Default).Result.Value);
        }
        public void ClauseCanMatchCustomAttribute()
        {
            var clause = new ClauseBuilder().Attribute("legs").Op("in").Values(new JValue(4)).Build();
            var f      = BooleanFlagWithClauses(clause);
            var user   = User.Builder("key").Custom("legs", 4).Build();

            Assert.Equal(LdValue.Of(true), f.Evaluate(user, featureStore, EventFactory.Default).Result.Value);
        }
        public void ClauseCanBeNegated()
        {
            var clause = new ClauseBuilder().Attribute("name").Op("in").Values(new JValue("Bob"))
                         .Negate(true).Build();
            var f    = BooleanFlagWithClauses(clause);
            var user = User.Builder("key").Name("Bob").Build();

            Assert.Equal(LdValue.Of(false), f.Evaluate(user, featureStore, EventFactory.Default).Result.Value);
        }
        public void MatchingRuleWithZeroRollout()
        {
            var clause = new ClauseBuilder().Attribute("email").Op("in").Values(JValue.CreateString("*****@*****.**")).Build();
            var rule   = new SegmentRule(new List <Clause> {
                clause
            }, 0, null);
            var s = new Segment("test", 1, null, null, null, new List <SegmentRule> {
                rule
            }, false);
            var u = User.Builder("foo").Email("*****@*****.**").Build();

            Assert.False(s.MatchesUser(u));
        }
        public void NonMatchingRuleWithMultipleClauses()
        {
            var clause1 = new ClauseBuilder().Attribute("email").Op("in").Values(JValue.CreateString("*****@*****.**")).Build();
            var clause2 = new ClauseBuilder().Attribute("name").Op("in").Values(JValue.CreateString("bill")).Build();
            var rule    = new SegmentRule(new List <Clause> {
                clause1, clause2
            }, null, null);
            var s = new Segment("test", 1, null, null, null, new List <SegmentRule> {
                rule
            }, false);
            var u = User.Builder("foo").Email("*****@*****.**").Name("bob").Build();

            Assert.False(s.MatchesUser(u));
        }
Example #9
0
        public void CanMatchUserBySegment()
        {
            var segment = new Segment("segment1", 1, new List <string> {
                user.Key
            }, null, "", null, false);

            featureStore.Upsert(VersionedDataKind.Segments, segment);

            var clause  = new ClauseBuilder().Op("segmentMatch").Values(new JValue("segment1")).Build();
            var feature = new FeatureFlagBuilder("feature").BooleanWithClauses(clause).Build();

            featureStore.Upsert(VersionedDataKind.Features, feature);

            Assert.True(client.BoolVariation("feature", user, false));
        }
        public void RuleWithNoVariationOrRolloutReturnsMalformedFlagError()
        {
            var user   = User.WithKey("userkey");
            var clause = ClauseBuilder.ShouldMatchUser(user);
            var rule   = new RuleBuilder().Id("ruleid").Clauses(clause).Build();
            var f      = FeatureFlagWithRules(rule);

            var result = f.Evaluate(user, featureStore, EventFactory.Default);

            var expected = new EvaluationDetail <LdValue>(LdValue.Null, null,
                                                          EvaluationReason.ErrorReason(EvaluationErrorKind.MALFORMED_FLAG));

            Assert.Equal(expected, result.Result);
            Assert.Equal(0, result.PrerequisiteEvents.Count);
        }
        public void FlagMatchesUserFromRules()
        {
            var user    = User.WithKey("userkey");
            var clause0 = ClauseBuilder.ShouldNotMatchUser(user);
            var clause1 = ClauseBuilder.ShouldMatchUser(user);
            var rule0   = new RuleBuilder().Id("ruleid0").Variation(2).Clauses(clause0).Build();
            var rule1   = new RuleBuilder().Id("ruleid1").Variation(2).Clauses(clause1).Build();
            var f       = FeatureFlagWithRules(rule0, rule1);

            var result = f.Evaluate(user, featureStore, EventFactory.Default);

            var expected = new EvaluationDetail <LdValue>(LdValue.Of("on"), 2,
                                                          EvaluationReason.RuleMatchReason(1, "ruleid1"));

            Assert.Equal(expected, result.Result);
            Assert.Equal(0, result.PrerequisiteEvents.Count);
        }
        private Segment BuildSegment()
        {
            var clause = new ClauseBuilder().Attribute("name").Op("in").Values(new JValue("x")).Negate(true).Build();
            var rule   = new SegmentRule(new List <Clause> {
                clause
            }, 50, "key");

            return(new Segment(
                       "segkey",
                       100,
                       new List <string> {
                "includeme"
            },
                       new List <string> {
                "excludeme"
            },
                       "NaCl",
                       new List <SegmentRule> {
                rule
            },
                       true
                       ));
        }
        public void EventTrackingAndReasonCanBeForcedForRule()
        {
            var clause = ClauseBuilder.ShouldMatchUser(user);
            var rule   = new RuleBuilder().Id("rule-id").Variation(1).Clauses(clause).TrackEvents(true).Build();
            var flag   = new FeatureFlagBuilder("flag")
                         .On(true)
                         .Rules(rule)
                         .OffVariation(0)
                         .Variations(new JValue("off"), new JValue("on"))
                         .Build();

            featureStore.Upsert(VersionedDataKind.Features, flag);

            client.StringVariation("flag", user, "default");

            // Note, we did not call StringVariationDetail and the flag is not tracked, but we should still get
            // tracking and a reason, because the rule-level trackEvents flag is on for the matched rule.

            Assert.Equal(1, eventSink.Events.Count);
            var e = Assert.IsType <FeatureRequestEvent>(eventSink.Events[0]);

            Assert.True(e.TrackEvents);
            Assert.Equal(EvaluationReason.RuleMatchReason(0, "rule-id"), e.Reason);
        }
        private FeatureFlag SegmentMatchBooleanFlag(string segmentKey)
        {
            var clause = new ClauseBuilder().Op("segmentMatch").Values(new JValue(segmentKey)).Build();

            return(BooleanFlagWithClauses(clause));
        }