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)); }
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); }
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); }
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)); } }
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)); } }
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); }
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); }
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); }