Exemple #1
0
        private void TestTypeConversion <T, U>(T fromValue, U toValue, Func <T, LdValue> constructor,
                                               LdValue.Converter <U> converter, Func <LdValue, U> getter)
        {
            var value = constructor(fromValue);

            Assert.Equal(toValue, getter(value));
            Assert.Equal(toValue, converter.ToType(value));
        }
Exemple #2
0
        private void TestConvertIntegerToNumericType <T>(LdValue.Converter <T> converter, Func <LdValue, T> getter)
        {
            var t_2 = (T)Convert.ChangeType(2, typeof(T));

            TestTypeConversion((int)2, t_2, n => LdValue.Of(n), converter, getter);
            TestTypeConversion((long)2, t_2, n => LdValue.Of(n), converter, getter);
            TestTypeConversion((float)2, t_2, n => LdValue.Of(n), converter, getter);
            TestTypeConversion((double)2, t_2, n => LdValue.Of(n), converter, getter);
        }
Exemple #3
0
        private void TestConvertNonIntegerToIntegerType <T>(LdValue.Converter <T> converter, Func <LdValue, T> getter)
        {
            var t_2       = (T)Convert.ChangeType(2, typeof(T));
            var t_3       = (T)Convert.ChangeType(3, typeof(T));
            var t_minus_2 = (T)Convert.ChangeType(-2, typeof(T));
            var t_minus_3 = (T)Convert.ChangeType(-3, typeof(T));

            TestTypeConversion((float)2.25, t_2, n => LdValue.Of(n), converter, getter);
            TestTypeConversion((double)2.25, t_2, n => LdValue.Of(n), converter, getter);
            TestTypeConversion((float)2.75, t_3, n => LdValue.Of(n), converter, getter);
            TestTypeConversion((double)2.75, t_3, n => LdValue.Of(n), converter, getter);
            TestTypeConversion((float)-2.25, t_minus_2, n => LdValue.Of(n), converter, getter);
            TestTypeConversion((double)-2.25, t_minus_2, n => LdValue.Of(n), converter, getter);
            TestTypeConversion((float)-2.75, t_minus_3, n => LdValue.Of(n), converter, getter);
            TestTypeConversion((double)-2.75, t_minus_3, n => LdValue.Of(n), converter, getter);
        }
Exemple #4
0
        private void TestNonNumericValueAsNumericTypeIsZero <T>(LdValue.Converter <T> converter,
                                                                Func <LdValue, T> getter, T zero)
        {
            var values = new LdValue[]
            {
                LdValue.Null,
                aTrueBoolValue,
                aStringValue,
                aNumericLookingStringValue,
                anArrayValue,
                anObjectValue
            };

            foreach (var value in values)
            {
                Assert.Equal(zero, getter(value));
                Assert.Equal(zero, converter.ToType(value));
            }
        }
Exemple #5
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));
            }
        }
Exemple #6
0
        EvaluationDetail <T> VariationInternal <T>(string featureKey, LdValue defaultJson, LdValue.Converter <T> converter, bool checkType, EventFactory eventFactory)
        {
            T defaultValue = converter.ToType(defaultJson);

            EvaluationDetail <T> errorResult(EvaluationErrorKind kind) =>
            new EvaluationDetail <T>(defaultValue, null, EvaluationReason.ErrorReason(kind));

            var flag = flagCacheManager.FlagForUser(featureKey, User);

            if (flag == null)
            {
                if (!Initialized)
                {
                    Log.Warn("LaunchDarkly client has not yet been initialized. Returning default value");
                    SendEventIfOnline(eventFactory.NewUnknownFeatureRequestEvent(featureKey, User, defaultJson,
                                                                                 EvaluationErrorKind.CLIENT_NOT_READY));
                    return(errorResult(EvaluationErrorKind.CLIENT_NOT_READY));
                }
                else
                {
                    Log.InfoFormat("Unknown feature flag {0}; returning default value", featureKey);
                    SendEventIfOnline(eventFactory.NewUnknownFeatureRequestEvent(featureKey, User, defaultJson,
                                                                                 EvaluationErrorKind.FLAG_NOT_FOUND));
                    return(errorResult(EvaluationErrorKind.FLAG_NOT_FOUND));
                }
            }
            else
            {
                if (!Initialized)
                {
                    Log.Warn("LaunchDarkly client has not yet been initialized. Returning cached value");
                }
            }

            FeatureFlagEvent     featureFlagEvent = new FeatureFlagEvent(featureKey, flag);
            EvaluationDetail <T> result;
            LdValue valueJson;

            if (flag.value.IsNull)
            {
                valueJson = defaultJson;
                result    = new EvaluationDetail <T>(defaultValue, flag.variation, flag.reason);
            }
            else
            {
                if (checkType && !defaultJson.IsNull && flag.value.Type != defaultJson.Type)
                {
                    valueJson = defaultJson;
                    result    = new EvaluationDetail <T>(defaultValue, null, EvaluationReason.ErrorReason(EvaluationErrorKind.WRONG_TYPE));
                }
                else
                {
                    valueJson = flag.value;
                    result    = new EvaluationDetail <T>(converter.ToType(flag.value), flag.variation, flag.reason);
                }
            }
            var featureEvent = eventFactory.NewFeatureRequestEvent(featureFlagEvent, User,
                                                                   new EvaluationDetail <LdValue>(valueJson, flag.variation, flag.reason), defaultJson);

            SendEventIfOnline(featureEvent);
            return(result);
        }
Exemple #7
0
        private void TestCustomAttribute <T>(T value,
                                             Func <IUserBuilder, string, T, IUserBuilderCanMakeAttributePrivate> setter, LdValue.Converter <T> converter)
        {
            var user0 = setter(User.Builder(key), "foo", value).Build();

            Assert.Equal(value, converter.ToType(user0.Custom["foo"]));
            Assert.Empty(user0.PrivateAttributeNames);

            var user1 = setter(User.Builder(key), "bar", value).AsPrivateAttribute().Build();

            Assert.Equal(value, converter.ToType(user1.Custom["bar"]));
            Assert.Equal(new HashSet <string> {
                "bar"
            }, user1.PrivateAttributeNames);
        }
Exemple #8
0
        EvaluationDetail <T> VariationInternal <T>(string featureKey, LdValue defaultJson, LdValue.Converter <T> converter, bool checkType, EventFactory eventFactory)
        {
            T defaultValue = converter.ToType(defaultJson);

            EvaluationDetail <T> errorResult(EvaluationErrorKind kind) =>
            new EvaluationDetail <T>(defaultValue, null, EvaluationReason.ErrorReason(kind));

            var flag = _dataStore.Get(featureKey)?.Item;

            if (flag == null)
            {
                if (!Initialized)
                {
                    _log.Warn("LaunchDarkly client has not yet been initialized. Returning default value");
                    SendEvaluationEventIfOnline(eventFactory.NewUnknownFlagEvaluationEvent(featureKey, User, defaultJson,
                                                                                           EvaluationErrorKind.ClientNotReady));
                    return(errorResult(EvaluationErrorKind.ClientNotReady));
                }
                else
                {
                    _log.Info("Unknown feature flag {0}; returning default value", featureKey);
                    SendEvaluationEventIfOnline(eventFactory.NewUnknownFlagEvaluationEvent(featureKey, User, defaultJson,
                                                                                           EvaluationErrorKind.FlagNotFound));
                    return(errorResult(EvaluationErrorKind.FlagNotFound));
                }
            }
            else
            {
                if (!Initialized)
                {
                    _log.Warn("LaunchDarkly client has not yet been initialized. Returning cached value");
                }
            }

            EvaluationDetail <T> result;
            LdValue valueJson;

            if (flag.Value.IsNull)
            {
                valueJson = defaultJson;
                result    = new EvaluationDetail <T>(defaultValue, flag.Variation, flag.Reason ?? EvaluationReason.OffReason);
            }
            else
            {
                if (checkType && !defaultJson.IsNull && flag.Value.Type != defaultJson.Type)
                {
                    valueJson = defaultJson;
                    result    = new EvaluationDetail <T>(defaultValue, null, EvaluationReason.ErrorReason(EvaluationErrorKind.WrongType));
                }
                else
                {
                    valueJson = flag.Value;
                    result    = new EvaluationDetail <T>(converter.ToType(flag.Value), flag.Variation, flag.Reason ?? EvaluationReason.OffReason);
                }
            }
            var featureEvent = eventFactory.NewEvaluationEvent(featureKey, flag, User,
                                                               new EvaluationDetail <LdValue>(valueJson, flag.Variation, flag.Reason ?? EvaluationReason.OffReason), defaultJson);

            SendEvaluationEventIfOnline(featureEvent);
            return(result);
        }