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); }
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); }
/// <inheritdoc/> public EvaluationDetail <float> FloatVariationDetail(string key, User user, float defaultValue) { return(Evaluate(key, user, LdValue.Of(defaultValue), LdValue.Convert.Float, true, EventFactory.DefaultWithReasons)); }
/// <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();
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(), "")); } }
/// <inheritdoc/> public void Track(string name, User user, LdValue data) => TrackInternal(name, user, data, null);
/// <inheritdoc/> public EvaluationDetail <LdValue> JsonVariationDetail(string key, User user, LdValue defaultValue) { return(Evaluate(key, user, defaultValue, LdValue.Convert.Json, false, EventFactory.DefaultWithReasons)); }
/// <inheritdoc/> public EvaluationDetail <double> DoubleVariationDetail(string key, User user, double defaultValue) { return(Evaluate(key, user, LdValue.Of(defaultValue), LdValue.Convert.Double, true, EventFactory.DefaultWithReasons)); }
/// <inheritdoc/> public EvaluationDetail <string> StringVariationDetail(string key, User user, string defaultValue) { return(Evaluate(key, user, LdValue.Of(defaultValue), LdValue.Convert.String, true, EventFactory.DefaultWithReasons)); }
/// <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); }
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)); } }
/// <inheritdoc/> public int IntVariation(string key, User user, int defaultValue) { return(Evaluate(key, user, LdValue.Of(defaultValue), LdValue.Convert.Int, true, EventFactory.Default).Value); }
/// <inheritdoc/> public void Track(string name, User user, LdValue data, double metricValue) => TrackInternal(name, user, data, metricValue);
/// <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");
/// <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();
/// <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();
/// <inheritdoc/> public LdValue JsonVariation(string key, User user, LdValue defaultValue) { return(Evaluate(key, user, defaultValue, LdValue.Convert.Json, false, EventFactory.Default).Value); }