示例#1
0
        public void VariationDetailSendsFeatureEventWithReasonForValidFlag()
        {
            var flag = new FeatureFlagBuilder().Value(LdValue.Of("a")).Variation(1).Version(1000)
                       .TrackEvents(true).DebugEventsUntilDate(UnixMillisecondTime.OfMillis(2000))
                       .Reason(EvaluationReason.OffReason).Build();

            _testData.Update(_testData.Flag("flag").PreconfiguredFlag(flag));
            using (LdClient client = MakeClient(user))
            {
                EvaluationDetail <string> result = client.StringVariationDetail("flag", "b");
                Assert.Equal("a", result.Value);
                Assert.Equal(EvaluationReason.OffReason, result.Reason);
                Assert.Collection(eventProcessor.Events,
                                  e => CheckIdentifyEvent(e, user),
                                  e => {
                    EvaluationEvent fe = Assert.IsType <EvaluationEvent>(e);
                    Assert.Equal("flag", fe.FlagKey);
                    Assert.Equal("a", fe.Value.AsString);
                    Assert.Equal(1, fe.Variation);
                    Assert.Equal(1000, fe.FlagVersion);
                    Assert.Equal("b", fe.Default.AsString);
                    Assert.True(fe.TrackEvents);
                    Assert.Equal(UnixMillisecondTime.OfMillis(2000), fe.DebugEventsUntilDate);
                    Assert.Equal(EvaluationReason.OffReason, fe.Reason);
                    Assert.NotEqual(0, fe.Timestamp.Value);
                });
            }
        }
        /// <summary>
        /// Parses the user index from a JSON representation. If the JSON string is null or
        /// empty, it returns an empty user index.
        /// </summary>
        /// <param name="json">the JSON representation</param>
        /// <returns>the parsed data</returns>
        /// <exception cref="FormatException">if the JSON is malformed</exception>
        public static UserIndex Deserialize(string json)
        {
            if (string.IsNullOrEmpty(json))
            {
                return(new UserIndex());
            }
            var builder = ImmutableList.CreateBuilder <IndexEntry>();

            try
            {
                var r = JReader.FromString(json);
                for (var ar0 = r.Array(); ar0.Next(ref r);)
                {
                    var ar1 = r.Array();
                    if (ar1.Next(ref r))
                    {
                        var userId = r.String();
                        if (ar1.Next(ref r))
                        {
                            var timeMillis = r.Long();
                            builder.Add(new IndexEntry {
                                UserId = userId, Timestamp = UnixMillisecondTime.OfMillis(timeMillis)
                            });
                            ar1.Next(ref r);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                throw new FormatException("invalid stored user index", e);
            }
            return(new UserIndex(builder.ToImmutable()));
        }
示例#3
0
        public void SummarizeEventIncrementsCounters()
        {
            var     time = UnixMillisecondTime.OfMillis(1000);
            string  flag1Key = "flag1", flag2Key = "flag2", unknownFlagKey = "badkey";
            int     flag1Version = 100, flag2Version = 200;
            int     variation1 = 1, variation2 = 2;
            LdValue value1 = LdValue.Of("value1"), value2 = LdValue.Of("value2"),
                    value99 = LdValue.Of("value99"),
                    default1 = LdValue.Of("default1"), default2 = LdValue.Of("default2"),
                    default3   = LdValue.Of("default3");
            EventSummarizer es = new EventSummarizer();

            es.SummarizeEvent(time, flag1Key, flag1Version, variation1, value1, default1);
            es.SummarizeEvent(time, flag1Key, flag1Version, variation2, value2, default1);
            es.SummarizeEvent(time, flag2Key, flag2Version, variation1, value99, default2);
            es.SummarizeEvent(time, flag1Key, flag1Version, variation1, value1, default1);
            es.SummarizeEvent(time, unknownFlagKey, null, null, default3, default3);
            EventSummary data = es.Snapshot();

            Dictionary <EventsCounterKey, EventsCounterValue> expected = new Dictionary <EventsCounterKey, EventsCounterValue>();

            Assert.Equal(new EventsCounterValue(2, value1, default1),
                         data.Counters[new EventsCounterKey(flag1Key, flag1Version, variation1)]);
            Assert.Equal(new EventsCounterValue(1, value2, default1),
                         data.Counters[new EventsCounterKey(flag1Key, flag1Version, variation2)]);
            Assert.Equal(new EventsCounterValue(1, value99, default2),
                         data.Counters[new EventsCounterKey(flag2Key, flag2Version, variation1)]);
            Assert.Equal(new EventsCounterValue(1, default3, default3),
                         data.Counters[new EventsCounterKey(unknownFlagKey, null, null)]);
        }
        public void AllFlagsStateReturnsStateWithReasons()
        {
            var flag1 = new FeatureFlagBuilder("key1").Version(100)
                        .OffVariation(0).Variations(LdValue.Of("value1"))
                        .Build();
            var flag2 = new FeatureFlagBuilder("key2").Version(200)
                        .OffVariation(1).Variations(LdValue.Of("x"), LdValue.Of("value2"))
                        .TrackEvents(true).DebugEventsUntilDate(UnixMillisecondTime.OfMillis(1000))
                        .Build();

            testData.UsePreconfiguredFlag(flag1);
            testData.UsePreconfiguredFlag(flag2);

            var state = client.AllFlagsState(user, FlagsStateOption.WithReasons);

            Assert.True(state.Valid);

            var expectedString = @"{""key1"":""value1"",""key2"":""value2"",
                ""$flagsState"":{
                  ""key1"":{
                    ""variation"":0,""version"":100,""reason"":{""kind"":""OFF""}
                  },""key2"":{
                    ""variation"":1,""version"":200,""reason"":{""kind"":""OFF""},""trackEvents"":true,""debugEventsUntilDate"":1000
                  }
                },
                ""$valid"":true
            }";
            var actualString   = LdJsonSerialization.SerializeObject(state);

            AssertHelpers.JsonEqual(expectedString, actualString);
        }
示例#5
0
        public void SerializeFlagWithAllProperties()
        {
            var flag1 = new FeatureFlagBuilder()
                        .Version(1)
                        .Value(LdValue.Of(false))
                        .Variation(2)
                        .FlagVersion(3)
                        .Reason(EvaluationReason.OffReason)
                        .TrackEvents(true)
                        .DebugEventsUntilDate(UnixMillisecondTime.OfMillis(1234))
                        .Build();

            AssertJsonEqual(@"{""version"":1,""value"":false,""variation"":2,""flagVersion"":3," +
                            @"""reason"":{""kind"":""OFF""},""trackEvents"":true,""debugEventsUntilDate"":1234}",
                            DataModelSerialization.SerializeFlag(flag1));

            // make sure we're treating trackReason separately from trackEvents
            var flag2 = new FeatureFlagBuilder()
                        .Version(1)
                        .Value(LdValue.Of(false))
                        .Reason(EvaluationReason.OffReason)
                        .Variation(2)
                        .FlagVersion(3)
                        .TrackReason(true)
                        .Build();

            AssertJsonEqual(@"{""version"":1,""value"":false,""variation"":2,""flagVersion"":3," +
                            @"""reason"":{""kind"":""OFF""},""trackReason"":true}",
                            DataModelSerialization.SerializeFlag(flag2));
        }
        public object ReadJson(ref JReader reader)
        {
            var valid = true;
            var flags = new Dictionary <string, FlagState>();

            for (var topLevelObj = reader.Object(); topLevelObj.Next(ref reader);)
            {
                var key = topLevelObj.Name.ToString();
                switch (key)
                {
                case "$valid":
                    valid = reader.Bool();
                    break;

                case "$flagsState":
                    for (var flagsObj = reader.Object(); flagsObj.Next(ref reader);)
                    {
                        var subKey = flagsObj.Name.ToString();
                        var flag   = flags.ContainsKey(subKey) ? flags[subKey] : new FlagState();
                        for (var metaObj = reader.Object(); metaObj.Next(ref reader);)
                        {
                            switch (metaObj.Name.ToString())
                            {
                            case "variation":
                                flag.Variation = reader.IntOrNull();
                                break;

                            case "version":
                                flag.Version = reader.IntOrNull();
                                break;

                            case "trackEvents":
                                flag.TrackEvents = reader.Bool();
                                break;

                            case "debugEventsUntilDate":
                                var n = reader.LongOrNull();
                                flag.DebugEventsUntilDate = n.HasValue ? UnixMillisecondTime.OfMillis(n.Value) :
                                                            (UnixMillisecondTime?)null;
                                break;

                            case "reason":
                                flag.Reason = EvaluationReasonConverter.ReadJsonNullableValue(ref reader);
                                break;
                            }
                        }
                        flags[subKey] = flag;
                    }
                    break;

                default:
                    var flagForValue = flags.ContainsKey(key) ? flags[key] : new FlagState();
                    flagForValue.Value = LdValueConverter.ReadJsonValue(ref reader);
                    flags[key]         = flagForValue;
                    break;
                }
            }
            return(new FeatureFlagsState(valid, flags));
        }
        public void SetIndex()
        {
            var index = new UserIndex().UpdateTimestamp("user1", UnixMillisecondTime.OfMillis(1000));

            _wrapper.SetIndex(index);

            var serializedData = _persistentStore.GetValue(ExpectedEnvironmentNamespace, ExpectedIndexKey);

            AssertJsonEqual(index.Serialize(), serializedData);
        }
        public void Serialize()
        {
            var ui = new UserIndex()
                     .UpdateTimestamp("user1", UnixMillisecondTime.OfMillis(1000))
                     .UpdateTimestamp("user2", UnixMillisecondTime.OfMillis(2000));

            var json     = ui.Serialize();
            var expected = @"[[""user1"",1000],[""user2"",2000]]";

            AssertJsonEqual(expected, json);
        }
        public void UpdateTimestampForExistingUser()
        {
            var ui = new UserIndex()
                     .UpdateTimestamp("user1", UnixMillisecondTime.OfMillis(1000))
                     .UpdateTimestamp("user2", UnixMillisecondTime.OfMillis(2000));

            ui = ui.UpdateTimestamp("user1", UnixMillisecondTime.OfMillis(2001));

            Assert.Collection(ui.Data,
                              AssertEntry("user2", 2000),
                              AssertEntry("user1", 2001));
        }
        public void PruneWhenLimitIsNotExceeded()
        {
            var ui = new UserIndex()
                     .UpdateTimestamp("user1", UnixMillisecondTime.OfMillis(1000))
                     .UpdateTimestamp("user2", UnixMillisecondTime.OfMillis(2000));

            Assert.Same(ui, ui.Prune(3, out var removed1));
            Assert.Empty(removed1);

            Assert.Same(ui, ui.Prune(2, out var removed2));
            Assert.Empty(removed2);
        }
        public void SummaryEventIsSerialized()
        {
            var summary = new EventSummary();
            summary.NoteTimestamp(UnixMillisecondTime.OfMillis(1001));

            summary.IncrementCounter("first", 1, 11, LdValue.Of("value1a"), LdValue.Of("default1"));

            summary.IncrementCounter("second", 1, 21, LdValue.Of("value2a"), LdValue.Of("default2"));

            summary.IncrementCounter("first", 1, 11, LdValue.Of("value1a"), LdValue.Of("default1"));
            summary.IncrementCounter("first", 1, 12, LdValue.Of("value1a"), LdValue.Of("default1"));

            summary.IncrementCounter("second", 2, 21, LdValue.Of("value2b"), LdValue.Of("default2"));
            summary.IncrementCounter("second", null, 21, LdValue.Of("default2"), LdValue.Of("default2")); // flag exists (has version), but eval failed (no variation)

            summary.IncrementCounter("third", null, null, LdValue.Of("default3"), LdValue.Of("default3")); // flag doesn't exist (no version)

            summary.NoteTimestamp(UnixMillisecondTime.OfMillis(1000));
            summary.NoteTimestamp(UnixMillisecondTime.OfMillis(1002));

            var f = new EventOutputFormatter(new EventsConfiguration());
            var outputEvent = LdValue.Parse(f.SerializeOutputEvents(new object[0], summary, out var count)).Get(0);
            Assert.Equal(1, count);

            Assert.Equal("summary", outputEvent.Get("kind").AsString);
            Assert.Equal(1000, outputEvent.Get("startDate").AsInt);
            Assert.Equal(1002, outputEvent.Get("endDate").AsInt);

            var featuresJson = outputEvent.Get("features");
            Assert.Equal(3, featuresJson.Count);

            var firstJson = featuresJson.Get("first");
            Assert.Equal("default1", firstJson.Get("default").AsString);
            TestUtil.AssertContainsInAnyOrder(firstJson.Get("counters").AsList(LdValue.Convert.Json),
                LdValue.Parse(@"{""value"":""value1a"",""variation"":1,""version"":11,""count"":2}"),
                LdValue.Parse(@"{""value"":""value1a"",""variation"":1,""version"":12,""count"":1}"));

            var secondJson = featuresJson.Get("second");
            Assert.Equal("default2", secondJson.Get("default").AsString);
            TestUtil.AssertContainsInAnyOrder(secondJson.Get("counters").AsList(LdValue.Convert.Json),
                LdValue.Parse(@"{""value"":""value2a"",""variation"":1,""version"":21,""count"":1}"),
                LdValue.Parse(@"{""value"":""value2b"",""variation"":2,""version"":21,""count"":1}"),
                LdValue.Parse(@"{""value"":""default2"",""version"":21,""count"":1}"));

            var thirdJson = featuresJson.Get("third");
            Assert.Equal("default3", thirdJson.Get("default").AsString);
            TestUtil.AssertContainsInAnyOrder(thirdJson.Get("counters").AsList(LdValue.Convert.Json),
                LdValue.Parse(@"{""unknown"":true,""value"":""default3"",""count"":1}"));
        }
示例#12
0
        public void SummarizeEventSetsStartAndEndDates()
        {
            var             time1 = UnixMillisecondTime.OfMillis(1000);
            var             time2 = UnixMillisecondTime.OfMillis(2000);
            var             time3 = UnixMillisecondTime.OfMillis(3000);
            EventSummarizer es    = new EventSummarizer();

            es.SummarizeEvent(time2, "flag", null, null, LdValue.Null, LdValue.Null);
            es.SummarizeEvent(time1, "flag", null, null, LdValue.Null, LdValue.Null);
            es.SummarizeEvent(time3, "flag", null, null, LdValue.Null, LdValue.Null);
            EventSummary data = es.Snapshot();

            Assert.Equal(time1, data.StartDate);
            Assert.Equal(time3, data.EndDate);
        }
        public void PruneRemovesLeastRecentUsers()
        {
            var ui = new UserIndex()
                     .UpdateTimestamp("user1", UnixMillisecondTime.OfMillis(1000))
                     .UpdateTimestamp("user2", UnixMillisecondTime.OfMillis(2000))
                     .UpdateTimestamp("user3", UnixMillisecondTime.OfMillis(1111)) // deliberately out of order
                     .UpdateTimestamp("user4", UnixMillisecondTime.OfMillis(3000))
                     .UpdateTimestamp("user5", UnixMillisecondTime.OfMillis(4000));

            var ui1 = ui.Prune(3, out var removed);

            Assert.Equal(ImmutableList.Create("user1", "user3"), removed);
            Assert.Collection(ui1.Data,
                              AssertEntry("user2", 2000),
                              AssertEntry("user4", 3000),
                              AssertEntry("user5", 4000));
        }
 internal static DateTime?ValueToDate(LdValue value)
 {
     if (value.IsString)
     {
         try
         {
             return(DateTime.Parse(value.AsString).ToUniversalTime());
         }
         catch (FormatException)
         {
             return(null);
         }
     }
     if (value.IsNumber)
     {
         return(UnixMillisecondTime.OfMillis(value.AsLong).AsDateTime);
     }
     return(null);
 }
        public void UsePreconfiguredFlag()
        {
            CreateAndStart();
            _updates.ExpectInit(_initialUser);

            var flag = new FeatureFlagBuilder().Version(1).Value(true).Variation(0).Reason(EvaluationReason.OffReason)
                       .TrackEvents(true).TrackReason(true).DebugEventsUntilDate(UnixMillisecondTime.OfMillis(123)).Build();

            _td.Update(_td.Flag("flag1").PreconfiguredFlag(flag));

            var item1 = _updates.ExpectUpsert(_initialUser, "flag1");

            Assert.Equal(flag, item1.Item);

            _td.Update(_td.Flag("flag1").PreconfiguredFlag(flag));

            var item2       = _updates.ExpectUpsert(_initialUser, "flag1");
            var updatedFlag = new FeatureFlagBuilder(flag).Version(2).Build();

            Assert.Equal(updatedFlag, item2.Item);
        }
示例#16
0
        public async Task <StoreMetadata?> GetMetadataAsync()
        {
            var db = _redis.GetDatabase();

            var value = await db.StringGetAsync(_syncTimeKey);

            if (value.IsNull)
            {
                return(null);
            }
            if (value == "")
            {
                return(new StoreMetadata {
                    LastUpToDate = null
                });
            }
            var millis = long.Parse(value);

            return(new StoreMetadata {
                LastUpToDate = UnixMillisecondTime.OfMillis(millis)
            });
        }
        public async Task <StoreMetadata?> GetMetadataAsync()
        {
            var key     = PrefixedNamespace(MetadataKey);
            var request = new GetItemRequest(_tableName, MakeKeysMap(key, key), true);
            var result  = await _client.GetItemAsync(request);

            if (result.Item is null || result.Item.Count == 0)
            {
                return(null);
            }
            if (!result.Item.TryGetValue(SyncTimeAttr, out var syncTimeValue) || string.IsNullOrEmpty(syncTimeValue.N))
            {
                return(new StoreMetadata {
                    LastUpToDate = null
                });
            }
            if (!long.TryParse(syncTimeValue.N, out var milliseconds))
            {
                throw new InvalidOperationException("Invalid data in DynamoDB: non-numeric timestamp");
            }
            return(new StoreMetadata {
                LastUpToDate = UnixMillisecondTime.OfMillis(milliseconds)
            });
        }
示例#18
0
        public void CanDeserializeFromJson()
        {
            var state = FeatureFlagsState.Builder(FlagsStateOption.WithReasons)
                        .AddFlag("key1", LdValue.Of("value1"), 0, EvaluationReason.OffReason, 100, false, null)
                        .AddFlag("key2", LdValue.Of("value2"), 1, EvaluationReason.FallthroughReason, 200, true, UnixMillisecondTime.OfMillis(1000))
                        .Build();

            var jsonString = LdJsonSerialization.SerializeObject(state);
            var state1     = LdJsonSerialization.DeserializeObject <FeatureFlagsState>(jsonString);

            Assert.Equal(state, state1);
        }
        private void AssertFlagHasAllProperties(FeatureFlag flag)
        {
            Assert.Equal("flag-key", flag.Key);
            Assert.Equal(99, flag.Version);
            Assert.True(flag.On);
            Assert.Equal("123", flag.Salt);

            Assert.Collection(flag.Prerequisites,
                              p =>
            {
                Assert.Equal("prereqkey", p.Key);
                Assert.Equal(3, p.Variation);
            });

            Assert.Collection(flag.Targets,
                              t =>
            {
                Assert.Equal(1, t.Variation);
                Assert.Equal(ImmutableList.Create("key1", "key2"), t.Values);
            });

            Assert.Collection(flag.Rules,
                              r =>
            {
                Assert.Equal("id0", r.Id);
                Assert.True(r.TrackEvents);
                Assert.Equal(2, r.Variation);
                Assert.Null(r.Rollout);
                Assert.Collection(r.Clauses,
                                  c =>
                {
                    Assert.Equal(UserAttribute.Name, c.Attribute);
                    Assert.Equal(Operator.In, c.Op);
                    Assert.Equal(ImmutableList.Create(LdValue.Of("Lucy"), LdValue.Of("Mina")), c.Values);
                    Assert.True(c.Negate);
                });
            },
                              r =>
            {
                Assert.Equal("id1", r.Id);
                Assert.False(r.TrackEvents);
                Assert.Null(r.Variation);
                Assert.NotNull(r.Rollout);
                Assert.Collection(r.Rollout.Value.Variations,
                                  v =>
                {
                    Assert.Equal(2, v.Variation);
                    Assert.Equal(40000, v.Weight);
                    Assert.False(v.Untracked);
                },
                                  v =>
                {
                    Assert.Equal(1, v.Variation);
                    Assert.Equal(60000, v.Weight);
                    Assert.True(v.Untracked);
                });
                Assert.Equal(UserAttribute.Email, r.Rollout.Value.BucketBy);
                Assert.Equal(RolloutKind.Experiment, r.Rollout.Value.Kind);
                Assert.Equal(123, r.Rollout.Value.Seed);
                Assert.Empty(r.Clauses);
            });

            Assert.Equal(1, flag.Fallthrough.Variation);
            Assert.Null(flag.Fallthrough.Rollout);
            Assert.Equal(2, flag.OffVariation);
            Assert.Equal(ImmutableList.Create(LdValue.Of("a"), LdValue.Of("b"), LdValue.Of("c")), flag.Variations);
            Assert.True(flag.ClientSide);
            Assert.True(flag.TrackEvents);
            Assert.True(flag.TrackEventsFallthrough);
            Assert.Equal(UnixMillisecondTime.OfMillis(1000), flag.DebugEventsUntilDate);
        }
            public static FeatureFlag ReadJsonValue(ref JReader reader)
            {
                LdValue             value                = LdValue.Null;
                int                 version              = 0;
                int?                flagVersion          = null;
                int?                variation            = null;
                EvaluationReason?   reason               = null;
                bool                trackEvents          = false;
                bool                trackReason          = false;
                UnixMillisecondTime?debugEventsUntilDate = null;

                for (var or = reader.Object(); or.Next(ref reader);)
                {
                    // The use of multiple == tests instead of switch allows for a slight optimization on
                    // some platforms where it wouldn't always need to allocate a string for or.Name. See:
                    // https://github.com/launchdarkly/dotnet-jsonstream/blob/master/src/LaunchDarkly.JsonStream/PropertyNameToken.cs
                    var name = or.Name;
                    if (name == "value")
                    {
                        value = LdJsonConverters.LdValueConverter.ReadJsonValue(ref reader);
                    }
                    else if (name == "version")
                    {
                        version = reader.Int();
                    }
                    else if (name == "flagVersion")
                    {
                        flagVersion = reader.IntOrNull();
                    }
                    else if (name == "variation")
                    {
                        variation = reader.IntOrNull();
                    }
                    else if (name == "reason")
                    {
                        reason = LdJsonConverters.EvaluationReasonConverter.ReadJsonNullableValue(ref reader);
                    }
                    else if (name == "trackEvents")
                    {
                        trackEvents = reader.Bool();
                    }
                    else if (name == "trackReason")
                    {
                        trackReason = reader.Bool();
                    }
                    else if (name == "debugEventsUntilDate")
                    {
                        var dt = reader.LongOrNull();
                        if (dt.HasValue)
                        {
                            debugEventsUntilDate = UnixMillisecondTime.OfMillis(dt.Value);
                        }
                    }
                }

                return(new FeatureFlag(
                           value,
                           variation,
                           reason,
                           version,
                           flagVersion,
                           trackEvents,
                           trackReason,
                           debugEventsUntilDate
                           ));
            }
        public void NonTrackedEventsAreSummarized()
        {
            var mockSender = MakeMockSender();
            var captured   = EventCapture.From(mockSender);

            using (var ep = MakeProcessor(_config, mockSender))
            {
                var flag1 = new TestFlagProperties {
                    Key = "flagkey1", Version = 11
                };
                var flag2 = new TestFlagProperties {
                    Key = "flagkey2", Version = 22
                };
                var value1       = LdValue.Of("value1");
                var value2       = LdValue.Of("value2");
                var default1     = LdValue.Of("default1");
                var default2     = LdValue.Of("default2");
                var earliestTime = UnixMillisecondTime.OfMillis(10000);
                var latestTime   = UnixMillisecondTime.OfMillis(20000);
                RecordEval(ep, flag1, new TestEvalProperties
                {
                    Timestamp    = earliestTime,
                    User         = _user,
                    Variation    = 1,
                    Value        = value1,
                    DefaultValue = default1
                });
                RecordEval(ep, flag1, new TestEvalProperties
                {
                    Timestamp    = UnixMillisecondTime.OfMillis(earliestTime.Value + 10),
                    User         = _user,
                    Variation    = 1,
                    Value        = value1,
                    DefaultValue = default1
                });
                RecordEval(ep, flag1, new TestEvalProperties
                {
                    Timestamp    = UnixMillisecondTime.OfMillis(earliestTime.Value + 20),
                    User         = _user,
                    Variation    = 2,
                    Value        = value2,
                    DefaultValue = default1
                });
                RecordEval(ep, flag2, new TestEvalProperties
                {
                    Timestamp    = latestTime,
                    User         = _user,
                    Variation    = 2,
                    Value        = value2,
                    DefaultValue = default2
                });
                ep.Flush();
                ep.WaitUntilInactive();

                Assert.Collection(captured.Events,
                                  item => CheckIndexEvent(item, earliestTime, _userJson),
                                  item => CheckSummaryEventDetails(item,
                                                                   earliestTime,
                                                                   latestTime,
                                                                   MustHaveFlagSummary(flag1.Key, default1,
                                                                                       MustHaveFlagSummaryCounter(value1, 1, flag1.Version, 2),
                                                                                       MustHaveFlagSummaryCounter(value2, 2, flag1.Version, 1)
                                                                                       ),
                                                                   MustHaveFlagSummary(flag2.Key, default2,
                                                                                       MustHaveFlagSummaryCounter(value2, 2, flag2.Version, 1)
                                                                                       )
                                                                   )
                                  );
            }
        }
 private Action <UserIndex.IndexEntry> AssertEntry(string id, int millis) =>
 e =>
 {
     Assert.Equal(id, e.UserId);
     Assert.Equal(UnixMillisecondTime.OfMillis(millis), e.Timestamp);
 };
示例#23
0
        public void CanSerializeToJson()
        {
            var state = FeatureFlagsState.Builder(FlagsStateOption.WithReasons)
                        .AddFlag("key1", LdValue.Of("value1"), 0, EvaluationReason.OffReason, 100, false, null)
                        .AddFlag("key2", LdValue.Of("value2"), 1, EvaluationReason.FallthroughReason, 200, true, UnixMillisecondTime.OfMillis(1000))
                        .Build();

            var expectedString = @"{""key1"":""value1"",""key2"":""value2"",
                ""$flagsState"":{
                  ""key1"":{
                    ""variation"":0,""version"":100,""reason"":{""kind"":""OFF""}
                  },""key2"":{
                    ""variation"":1,""version"":200,""reason"":{""kind"":""FALLTHROUGH""},""trackEvents"":true,""debugEventsUntilDate"":1000
                  }
                },
                ""$valid"":true
            }";
            var actualString   = LdJsonSerialization.SerializeObject(state);

            AssertHelpers.JsonEqual(expectedString, actualString);
        }
示例#24
0
        public object ReadJson(ref JReader reader)
        {
            string key     = null;
            int    version = 0;
            bool   deleted = false;
            bool   on      = false;
            ImmutableList <Prerequisite> prerequisites = null;
            ImmutableList <Target>       targets       = null;
            ImmutableList <FlagRule>     rules         = null;
            string             salt        = null;
            VariationOrRollout fallthrough = new VariationOrRollout();
            int?offVariation = null;
            ImmutableList <LdValue> variations = null;
            bool trackEvents = false, trackEventsFallthrough = false;
            UnixMillisecondTime?debugEventsUntilDate = null;
            bool clientSide = false;

            for (var obj = reader.Object().WithRequiredProperties(_requiredProperties); obj.Next(ref reader);)
            {
                switch (obj.Name)
                {
                case var n when n == "key":
                    key = reader.String();
                    break;

                case var n when n == "version":
                    version = reader.Int();
                    break;

                case var n when n == "deleted":
                    deleted = reader.Bool();
                    break;

                case var n when n == "on":
                    on = reader.Bool();
                    break;

                case var n when n == "prerequisites":
                    var prereqsBuilder = ImmutableList.CreateBuilder <Prerequisite>();
                    for (var arr = reader.ArrayOrNull(); arr.Next(ref reader);)
                    {
                        prereqsBuilder.Add(ReadPrerequisite(ref reader));
                    }
                    prerequisites = prereqsBuilder.ToImmutable();
                    break;

                case var n when n == "targets":
                    var targetsBuilder = ImmutableList.CreateBuilder <Target>();
                    for (var arr = reader.ArrayOrNull(); arr.Next(ref reader);)
                    {
                        targetsBuilder.Add(ReadTarget(ref reader));
                    }
                    targets = targetsBuilder.ToImmutable();
                    break;

                case var n when n == "rules":
                    var rulesBuilder = ImmutableList.CreateBuilder <FlagRule>();
                    for (var arr = reader.ArrayOrNull(); arr.Next(ref reader);)
                    {
                        rulesBuilder.Add(ReadFlagRule(ref reader));
                    }
                    rules = rulesBuilder.ToImmutable();
                    break;

                case var n when n == "fallthrough":
                    fallthrough = ReadVariationOrRollout(ref reader);
                    break;

                case var n when n == "offVariation":
                    offVariation = reader.IntOrNull();
                    break;

                case var n when n == "variations":
                    variations = SerializationHelpers.ReadValues(ref reader);
                    break;

                case var n when n == "salt":
                    salt = reader.StringOrNull();
                    break;

                case var n when n == "trackEvents":
                    trackEvents = reader.Bool();
                    break;

                case var n when n == "trackEventsFallthrough":
                    trackEventsFallthrough = reader.Bool();
                    break;

                case var n when n == "debugEventsUntilDate":
                    var dt = reader.LongOrNull();
                    debugEventsUntilDate = dt.HasValue ? UnixMillisecondTime.OfMillis(dt.Value) : (UnixMillisecondTime?)null;
                    break;

                case var n when n == "clientSide":
                    clientSide = reader.Bool();
                    break;
                }
            }
            if (key is null && !deleted)
            {
                throw new RequiredPropertyException("key", 0);
            }
            return(new FeatureFlag(key, version, deleted, on, prerequisites, targets, rules, fallthrough,
                                   offVariation, variations, salt, trackEvents, trackEventsFallthrough, debugEventsUntilDate, clientSide));
        }
示例#25
0
            public object ReadJson(ref JReader reader)
            {
                var maybeValue = reader.LongOrNull();

                return(maybeValue is null ? (UnixMillisecondTime?)null : UnixMillisecondTime.OfMillis(maybeValue.Value));
            }