public void NonStringValueAsStringIsNull()
        {
            var values = new LdValue[]
            {
                LdValue.Null,
                aTrueBoolValue,
                aTrueBoolValueFromJToken,
                anIntValue,
                anIntValueFromJToken,
                aFloatValue,
                aFloatValueFromJToken,
                anArrayValue,
                anArrayValueFromJToken,
                anObjectValue,
                anObjectValueFromJToken
            };

            foreach (var value in values)
            {
                Assert.NotEqual(LdValueType.String, value.Type);
                Assert.Null(value.AsString);
                Assert.Null(LdValue.Convert.String.ToType(value));
            }
        }
        public void CustomEventIsQueuedWithUser()
        {
            var mockSender = MakeMockSender();
            var captured   = EventCapture.From(mockSender);

            using (var ep = MakeProcessor(_config, mockSender))
            {
                var ce = new TestCustomEventProperties
                {
                    Timestamp   = _fixedTimestamp,
                    User        = _user,
                    Key         = "eventkey",
                    Data        = LdValue.Of(3),
                    MetricValue = 1.5
                };
                RecordCustom(ep, ce);
                ep.Flush();
                ep.WaitUntilInactive();

                Assert.Collection(captured.Events,
                                  item => CheckIndexEvent(item, ce.Timestamp, _userJson),
                                  item => CheckCustomEvent(item, ce, LdValue.Null));
            }
        }
        public void DiagnosticDisablerEnabledInitialDiagnostics()
        {
            var expectedStats       = LdValue.BuildObject().Add("stats", "testValue").Build();
            var expectedInit        = LdValue.BuildObject().Add("init", "testValue").Build();
            var mockDiagnosticStore = MakeDiagnosticStore(new DiagnosticEvent(expectedStats),
                                                          new DiagnosticEvent(expectedInit), new DiagnosticEvent(LdValue.Null));

            var mockDiagnosticDisabler = new Mock <IDiagnosticDisabler>(MockBehavior.Strict);

            mockDiagnosticDisabler.Setup(diagDisabler => diagDisabler.Disabled).Returns(false);

            var mockSender          = MakeMockSender();
            var eventCapture        = EventCapture.From(mockSender);
            var diagnosticCapture   = EventCapture.DiagnosticsFrom(mockSender);
            var diagnosticCountdown = new CountdownEvent(1);

            using (var ep = MakeProcessor(_config, mockSender, mockDiagnosticStore.Object, mockDiagnosticDisabler.Object, diagnosticCountdown))
            {
                diagnosticCountdown.Wait();

                Assert.Equal(expectedStats, diagnosticCapture.EventsQueue.Take());
                Assert.Equal(expectedInit, diagnosticCapture.EventsQueue.Take());
            }
        }
        public void CanUnregisterListeners()
        {
            var manager   = Manager();
            var listener1 = new FlagChangedEventSink();
            var listener2 = new FlagChangedEventSink();

            manager.FlagChanged += listener1.Handler;
            manager.FlagChanged += listener2.Handler;

            manager.FlagChanged -= listener1.Handler;

            manager.FlagWasUpdated(INT_FLAG, LdValue.Of(7), LdValue.Of(6));

            var e = listener2.Await();

            Assert.Equal(INT_FLAG, e.Key);
            Assert.Equal(7, e.NewValue.AsInt);
            Assert.Equal(6, e.OldValue.AsInt);

            // This is pretty hacky, but since we're testing for the *lack* of a call, there's no signal we can wait on.
            Thread.Sleep(100);

            Assert.True(listener1.IsEmpty);
        }
        private void ExecuteVariationCheck(string flagName, Action <LdValue> callback, ref LdValue valueDefault)
        {
            if (isMockMode)
            {
                Debug.LogWarning("LaunchDarklyClientBehavior.ExecuteVariationCheck: Instance in 'mock mode'; returning default value.");
                callback(valueDefault);
            }

            LdValue flagValue = LdValue.Null;

            switch (valueDefault.Type)
            {
            case LdValueType.Array:
            case LdValueType.Object:
                flagValue = ldClient.JsonVariation(flagName, valueDefault);
                break;

            case LdValueType.Bool:
                flagValue = LdValue.Of(ldClient.BoolVariation(flagName, valueDefault.AsBool));
                break;

            case LdValueType.Number:
                flagValue = LdValue.Of(ldClient.FloatVariation(flagName, valueDefault.AsFloat));
                break;

            case LdValueType.String:
                flagValue = LdValue.Of(ldClient.StringVariation(flagName, valueDefault.AsString));
                break;

            case LdValueType.Null:
            default:
                break;
            }

            callback(flagValue);
        }
Beispiel #6
0
        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").Version(1)
                         .On(true)
                         .Rules(rule)
                         .OffVariation(0)
                         .Variations(LdValue.Of("off"), LdValue.Of("on"))
                         .Build();

            testData.UsePreconfiguredFlag(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 <EvaluationEvent>(eventSink.Events[0]);

            Assert.True(e.TrackEvents);
            Assert.Equal(EvaluationReason.RuleMatchReason(0, "rule-id"), e.Reason);
        }
        public void NonArrayValuesReturnEmptyOrList()
        {
            var values = new LdValue[]
            {
                LdValue.Null,
                aTrueBoolValue,
                anIntValue,
                aFloatValue,
                aStringValue,
                anObjectValue
            };
            var emptyArray = new JArray();

            foreach (var value in values)
            {
                var emptyList = value.AsList(LdValue.Convert.Bool);
                Assert.Equal(0, emptyList.Count);
                Assert.Throws <IndexOutOfRangeException>(() => emptyList[0]);
                foreach (var n in emptyList)
                {
                    Assert.True(false, "should not have enumerated an element");
                }
            }
        }
        public void EqualsUsesDeepEqualityForObjects()
        {
            var o0 = LdValue.BuildObject()
                     .Add("a", "b")
                     .Add("c", LdValue.BuildObject().Add("d", "e").Build())
                     .Build();
            var o1 = LdValue.FromSafeValue(new JObject {
                { "a", new JValue("b") },
                { "c", new JObject {
                      { "d", new JValue("e") }
                  } }
            });

            AssertValueAndHashEqual(o0, o1);

            var o2 = LdValue.BuildObject()
                     .Add("a", "b")
                     .Build();

            AssertValueAndHashNotEqual(o0, o2);

            var o3 = LdValue.BuildObject()
                     .Add("a", "b")
                     .Add("c", LdValue.BuildObject().Add("d", "e").Build())
                     .Add("f", "g")
                     .Build();

            AssertValueAndHashNotEqual(o0, o3);

            var o4 = LdValue.BuildObject()
                     .Add("a", "b")
                     .Add("c", LdValue.BuildObject().Add("d", "f").Build())
                     .Build();

            AssertValueAndHashNotEqual(o0, o4);
        }
        public static ItemDescriptor MakeFlagThatReturnsVariationForSegmentMatch(int version, int variation)
        {
            var flagJson = LdValue.BuildObject()
                           .Add("key", FlagKey)
                           .Add("version", version)
                           .Add("on", true)
                           .Add("variations", LdValue.ArrayOf(GoodValue1, GoodValue2, BadValue))
                           .Add("fallthrough", LdValue.BuildObject().Add("variation", BadVariation).Build())
                           .Add("rules", LdValue.BuildArray()
                                .Add(LdValue.BuildObject()
                                     .Add("variation", variation)
                                     .Add("clauses", LdValue.BuildArray()
                                          .Add(LdValue.BuildObject()
                                               .Add("attribute", "")
                                               .Add("op", "segmentMatch")
                                               .Add("values", LdValue.ArrayOf(LdValue.Of(SegmentKey)))
                                               .Build())
                                          .Build())
                                     .Build())
                                .Build())
                           .Build().ToJsonString();

            return(DataModel.Features.Deserialize(flagJson));
        }
        public void FlagConfigByVariationIndex()
        {
            LdValue aVal = LdValue.Of("a"), bVal = LdValue.Of("b");
            int     aIndex = 0, bIndex = 1;
            var     ab      = new LdValue[] { aVal, bVal };
            var     expectA = FlagValueAssertion(LdValue.Of("a"), aIndex);
            var     expectB = FlagValueAssertion(LdValue.Of("b"), bIndex);

            VerifyFlag(f => f.Variations(ab), expectA);
            VerifyFlag(f => f.Variations(ab).Variation(aIndex), expectA);
            VerifyFlag(f => f.Variations(ab).Variation(bIndex), expectB);

            VerifyFlag(f => f.Variations(ab).Variation(aIndex).VariationForUser(_initialUser.Key, bIndex), expectB);
            VerifyFlag(f => f.Variations(ab).Variation(bIndex).VariationForUser(_initialUser.Key, aIndex), expectA);

            VerifyFlag(f => f.Variations(ab).Variation(aIndex).VariationFunc(u => bIndex), expectB);
            VerifyFlag(f => f.Variations(ab).Variation(bIndex).VariationFunc(u => aIndex), expectA);

            // VariationForUser takes precedence over VariationFunc
            VerifyFlag(f => f.Variations(ab).Variation(aIndex).VariationForUser(_initialUser.Key, bIndex)
                       .VariationFunc(u => aIndex), expectB);
            VerifyFlag(f => f.Variations(ab).Variation(bIndex).VariationForUser(_initialUser.Key, aIndex)
                       .VariationFunc(u => bIndex), expectA);
        }
Beispiel #11
0
 /// <inheritdoc/>
 public EvaluationDetail <float> FloatVariationDetail(string key, User user, float defaultValue)
 {
     return(Evaluate(key, user, LdValue.Of(defaultValue), LdValue.Convert.Float, true, EventFactory.DefaultWithReasons));
 }
Beispiel #12
0
 /// <inheritdoc/>
 public EvaluationDetail <bool> BoolVariationDetail(string key, User user, bool defaultValue)
 {
     return(Evaluate(key, user, LdValue.Of(defaultValue), LdValue.Convert.Bool, true, EventFactory.DefaultWithReasons));
 }
 public EvaluationDetail <LdValue> JsonVariationDetail(string key, LdValue defaultValue) =>
 throw new System.NotImplementedException();
 /// <inheritdoc/>
 public LdValue DescribeConfiguration(BasicConfiguration basic) =>
 LdValue.BuildObject()
 .WithHttpProperties(MakeHttpProperties(basic))
 .Build();
Beispiel #15
0
        public void NonBooleanFlags()
        {
            _td.Update(_td.Flag("flag").Variations(LdValue.Of("red"), LdValue.Of("green"), LdValue.Of("blue"))
                       .OffVariation(0).FallthroughVariation(2)
                       .VariationForUser("user1", 1)
                       .IfMatch(UserAttribute.Name, LdValue.Of("Mina")).ThenReturn(1));

            using (var client = new LdClient(_config))
            {
                Assert.Equal("green", client.StringVariation("flag", User.Builder("user1").Name("Lucy").Build(), ""));
                Assert.Equal("green", client.StringVariation("flag", User.Builder("user2").Name("Mina").Build(), ""));
                Assert.Equal("blue", client.StringVariation("flag", User.Builder("user3").Name("Quincy").Build(), ""));

                _td.Update(_td.Flag("flag").On(false));

                Assert.Equal("red", client.StringVariation("flag", User.Builder("user1").Name("Lucy").Build(), ""));
            }
        }
Beispiel #16
0
 /// <inheritdoc/>
 public void Track(string name, User user, LdValue data) =>
 TrackInternal(name, user, data, null);
Beispiel #17
0
 /// <inheritdoc/>
 public EvaluationDetail <LdValue> JsonVariationDetail(string key, User user, LdValue defaultValue)
 {
     return(Evaluate(key, user, defaultValue, LdValue.Convert.Json, false, EventFactory.DefaultWithReasons));
 }
Beispiel #18
0
 /// <inheritdoc/>
 public EvaluationDetail <double> DoubleVariationDetail(string key, User user, double defaultValue)
 {
     return(Evaluate(key, user, LdValue.Of(defaultValue), LdValue.Convert.Double, true, EventFactory.DefaultWithReasons));
 }
Beispiel #19
0
 /// <inheritdoc/>
 public EvaluationDetail <string> StringVariationDetail(string key, User user, string defaultValue)
 {
     return(Evaluate(key, user, LdValue.Of(defaultValue), LdValue.Convert.String, true, EventFactory.DefaultWithReasons));
 }
Beispiel #20
0
 /// <inheritdoc/>
 public bool BoolVariation(string key, User user, bool defaultValue = false)
 {
     return(Evaluate(key, user, LdValue.Of(defaultValue), LdValue.Convert.Bool, true, EventFactory.Default).Value);
 }
Beispiel #21
0
        private EvaluationDetail <T> Evaluate <T>(string featureKey, User user, LdValue defaultValue, LdValue.Converter <T> converter,
                                                  bool checkType, EventFactory eventFactory)
        {
            T defaultValueOfType = converter.ToType(defaultValue);

            if (!Initialized)
            {
                if (_dataStore.Initialized())
                {
                    _evalLog.Warn("Flag evaluation before client initialized; using last known values from data store");
                }
                else
                {
                    _evalLog.Warn("Flag evaluation before client initialized; data store unavailable, returning default value");
                    return(new EvaluationDetail <T>(defaultValueOfType, null,
                                                    EvaluationReason.ErrorReason(EvaluationErrorKind.ClientNotReady)));
                }
            }

            FeatureFlag featureFlag = null;

            try
            {
                featureFlag = GetFlag(featureKey);
                if (featureFlag == null)
                {
                    _evalLog.Info("Unknown feature flag \"{0}\"; returning default value",
                                  featureKey);
                    _eventProcessor.RecordEvaluationEvent(eventFactory.NewUnknownFlagEvaluationEvent(
                                                              featureKey, user, defaultValue, EvaluationErrorKind.FlagNotFound));
                    return(new EvaluationDetail <T>(defaultValueOfType, null,
                                                    EvaluationReason.ErrorReason(EvaluationErrorKind.FlagNotFound)));
                }

                if (user == null || user.Key == null)
                {
                    _evalLog.Warn("Null user or null user key when evaluating flag \"{0}\"; returning default value", featureKey);
                    _eventProcessor.RecordEvaluationEvent(eventFactory.NewDefaultValueEvaluationEvent(
                                                              featureFlag, user, defaultValue, EvaluationErrorKind.UserNotSpecified));
                    return(new EvaluationDetail <T>(defaultValueOfType, null,
                                                    EvaluationReason.ErrorReason(EvaluationErrorKind.UserNotSpecified)));
                }

                Evaluator.EvalResult evalResult = _evaluator.Evaluate(featureFlag, user, eventFactory);
                if (!IsOffline())
                {
                    foreach (var prereqEvent in evalResult.PrerequisiteEvents)
                    {
                        _eventProcessor.RecordEvaluationEvent(prereqEvent);
                    }
                }
                var evalDetail = evalResult.Result;
                EvaluationDetail <T> returnDetail;
                if (evalDetail.VariationIndex == null)
                {
                    returnDetail = new EvaluationDetail <T>(defaultValueOfType, null, evalDetail.Reason);
                    evalDetail   = new EvaluationDetail <LdValue>(defaultValue, null, evalDetail.Reason);
                }
                else
                {
                    if (checkType && !defaultValue.IsNull && evalDetail.Value.Type != defaultValue.Type)
                    {
                        _evalLog.Error("Expected type {0} but got {1} when evaluating feature flag \"{2}\"; returning default value",
                                       defaultValue.Type,
                                       evalDetail.Value.Type,
                                       featureKey);

                        _eventProcessor.RecordEvaluationEvent(eventFactory.NewDefaultValueEvaluationEvent(
                                                                  featureFlag, user, defaultValue, EvaluationErrorKind.WrongType));
                        return(new EvaluationDetail <T>(defaultValueOfType, null,
                                                        EvaluationReason.ErrorReason(EvaluationErrorKind.WrongType)));
                    }
                    returnDetail = new EvaluationDetail <T>(converter.ToType(evalDetail.Value),
                                                            evalDetail.VariationIndex, evalDetail.Reason);
                }
                _eventProcessor.RecordEvaluationEvent(eventFactory.NewEvaluationEvent(
                                                          featureFlag, user, evalDetail, defaultValue));
                return(returnDetail);
            }
            catch (Exception e)
            {
                LogHelpers.LogException(_evalLog,
                                        string.Format("Exception when evaluating feature flag \"{0}\"", featureKey),
                                        e);
                var reason = EvaluationReason.ErrorReason(EvaluationErrorKind.Exception);
                if (featureFlag == null)
                {
                    _eventProcessor.RecordEvaluationEvent(eventFactory.NewUnknownFlagEvaluationEvent(
                                                              featureKey, user, defaultValue, EvaluationErrorKind.Exception));
                }
                else
                {
                    _eventProcessor.RecordEvaluationEvent(eventFactory.NewEvaluationEvent(
                                                              featureFlag, user, new EvaluationDetail <LdValue>(defaultValue, null, reason), defaultValue));
                }
                return(new EvaluationDetail <T>(defaultValueOfType, null, reason));
            }
        }
Beispiel #22
0
 /// <inheritdoc/>
 public int IntVariation(string key, User user, int defaultValue)
 {
     return(Evaluate(key, user, LdValue.Of(defaultValue), LdValue.Convert.Int, true, EventFactory.Default).Value);
 }
Beispiel #23
0
 /// <inheritdoc/>
 public void Track(string name, User user, LdValue data, double metricValue) =>
 TrackInternal(name, user, data, metricValue);
Beispiel #24
0
 /// <inheritdoc/>
 public float FloatVariation(string key, User user, float defaultValue)
 {
     return(Evaluate(key, user, LdValue.Of(defaultValue), LdValue.Convert.Float, true, EventFactory.Default).Value);
 }
 public LdValue DescribeConfiguration(BasicConfiguration _) => LdValue.Of("memory");
Beispiel #26
0
 /// <inheritdoc/>
 public double DoubleVariation(string key, User user, double defaultValue)
 {
     return(Evaluate(key, user, LdValue.Of(defaultValue), LdValue.Convert.Double, true, EventFactory.Default).Value);
 }
 public LdValue JsonVariation(string key, LdValue defaultValue) =>
 throw new System.NotImplementedException();
Beispiel #28
0
 /// <inheritdoc/>
 public string StringVariation(string key, User user, string defaultValue)
 {
     return(Evaluate(key, user, LdValue.Of(defaultValue), LdValue.Convert.String, true, EventFactory.Default).Value);
 }
 public void Track(string eventName, LdValue data, double metricValue) =>
 throw new System.NotImplementedException();
Beispiel #30
0
 /// <inheritdoc/>
 public LdValue JsonVariation(string key, User user, LdValue defaultValue)
 {
     return(Evaluate(key, user, defaultValue, LdValue.Convert.Json, false, EventFactory.Default).Value);
 }