public void PingCausesPoll()
        {
            var data = new DataSetBuilder()
                       .Add("flag1", 1, LdValue.Of(true), 0)
                       .Build();
            var streamWithPing = Handlers.SSE.Start()
                                 .Then(PingEvent)
                                 .Then(Handlers.SSE.LeaveOpen());

            using (var pollingServer = HttpServer.Start(PollingResponse(data)))
            {
                using (var streamingServer = HttpServer.Start(streamWithPing))
                {
                    using (var dataSource = MakeDataSource(streamingServer.Uri, BasicUser,
                                                           c => c.ServiceEndpoints(Components.ServiceEndpoints()
                                                                                   .Streaming(streamingServer.Uri).Polling(pollingServer.Uri))))
                    {
                        var initTask = dataSource.Start();

                        pollingServer.Recorder.RequireRequest();

                        var receivedData = _updateSink.ExpectInit(BasicUser);
                        AssertHelpers.DataSetsEqual(data, receivedData);

                        Assert.True(AsyncUtils.WaitSafely(() => initTask, TimeSpan.FromSeconds(1)));
                        Assert.False(initTask.IsFaulted);
                        Assert.True(dataSource.Initialized);
                    }
                }
            }
        }
        public void InitIsNotRepeatedIfServerReturnsNotModifiedStatus()
        {
            var etag      = @"""abc123"""; // note that etag strings must be quoted
            var responses = Handlers.SequentialWithLastRepeating(
                Handlers.Header("Etag", etag).Then(PollingResponse(AllData)),
                Handlers.Status(304)
                );

            using (var server = HttpServer.Start(responses))
            {
                using (var dataSource = MakeDataSource(server.Uri, BasicUser,
                                                       c => c.DataSource(Components.PollingDataSource().PollIntervalNoMinimum(BriefInterval))))
                {
                    dataSource.Start();

                    var receivedData = _updateSink.ExpectInit(BasicUser);
                    AssertHelpers.DataSetsEqual(AllData, receivedData);

                    // We've set it up above so that all requests except the first one return a 304
                    // status, so the data source should *not* push a new data set with Init.
                    _updateSink.ExpectNoMoreActions();

                    var req1 = server.Recorder.RequireRequest();
                    var req2 = server.Recorder.RequireRequest();
                    var req3 = server.Recorder.RequireRequest();
                    Assert.Null(req1.Headers.Get("If-None-Match"));
                    Assert.Equal(etag, req2.Headers.Get("If-None-Match"));
                    Assert.Equal(etag, req3.Headers.Get("If-None-Match"));
                }
            }
        }
        public void GetAllWhenNotInitialized()
        {
            var data = _store.GetAll();

            Assert.NotNull(data);
            AssertHelpers.DataSetsEqual(DataSetBuilder.Empty, data.Value);
        }
        public void UpsertUpdatesPersistentStore()
        {
            var flag1a = new FeatureFlagBuilder().Version(1).Value(true).Build();
            var flag1b = new FeatureFlagBuilder().Version(2).Value(true).Build();
            var flag2  = new FeatureFlagBuilder().Version(1).Value(false).Build();
            var data1a = new DataSetBuilder().Add("flag1", flag1a).Add("flag2", flag2).Build();
            var data1b = new DataSetBuilder().Add("flag1", flag1b).Add("flag2", flag2).Build();

            var store = MakeStore(1);

            store.Init(BasicUser, data1a, true);

            var updated = store.Upsert("flag1", flag1b.ToItemDescriptor());

            Assert.True(updated);

            var item = store.Get("flag1"); // this is reading only from memory, not the persistent store

            Assert.Equal(flag1b.ToItemDescriptor(), item);

            var data = _persistentStore.InspectUserData(BasicMobileKey, BasicUser.Key);

            Assert.NotNull(data);
            AssertHelpers.DataSetsEqual(data1b, data.Value);
        }
        public void GetAllWithEmptyFlags()
        {
            _store.Init(BasicUser, DataSetBuilder.Empty, false);

            var data = _store.GetAll();

            Assert.NotNull(data);
            AssertHelpers.DataSetsEqual(DataSetBuilder.Empty, data.Value);
        }
        public void InitWritesToPersistentStoreIfToldTo()
        {
            var store = MakeStore(1);

            store.Init(BasicUser, DataSet1, true);

            var data = _persistentStore.InspectUserData(BasicMobileKey, BasicUser.Key);

            Assert.NotNull(data);
            AssertHelpers.DataSetsEqual(DataSet1, data.Value);
        }
        public void GetCachedDataForKnownUser()
        {
            _persistentStore.SetupUserData(BasicMobileKey, BasicUser.Key, DataSet1);
            _persistentStore.SetupUserData(BasicMobileKey, OtherUser.Key, DataSet2);

            var store = MakeStore(1);

            var data = store.GetCachedData(BasicUser);

            Assert.NotNull(data);
            AssertHelpers.DataSetsEqual(DataSet1, data.Value);
        }
        public void GetUserDataForKnownUserWithValidData()
        {
            var expectedData   = new DataSetBuilder().Add("flagkey", 1, LdValue.Of(true), 0).Build();
            var serializedData = expectedData.ToJsonString();

            _persistentStore.SetValue(ExpectedEnvironmentNamespace, ExpectedUserFlagsKey, serializedData);

            var data = _wrapper.GetUserData(UserHash);

            Assert.NotNull(data);
            AssertHelpers.DataSetsEqual(expectedData, data.Value);
            Assert.Empty(logCapture.GetMessages());
        }
        public void GetAllReturnsFlags()
        {
            var initData = new DataSetBuilder()
                           .Add("flag1", 1, LdValue.Of(true), 0)
                           .Add("flag2", 2, LdValue.Of(false), 1)
                           .Build();

            _store.Init(BasicUser, initData, false);

            var data = _store.GetAll();

            Assert.NotNull(data);
            AssertHelpers.DataSetsEqual(initData, data.Value);
        }
        public void SuccessfulRequestPutsFeatureDataInStore()
        {
            var expectedData = MakeAllData();

            _mockFeatureRequestor.Setup(fr => fr.GetAllDataAsync()).ReturnsAsync(expectedData);

            using (PollingProcessor pp = MakeProcessor())
            {
                var initTask = pp.Start();
                initTask.Wait();

                var receivedData = _updates.Inits.ExpectValue();
                AssertHelpers.DataSetsEqual(expectedData, receivedData);
            }
        }
        public void PutCausesDataToBeStoredAndDataSourceInitialized()
        {
            var data = new DataSetBuilder()
                       .Add("flag1", 1, LdValue.Of(true), 0)
                       .Build();

            WithDataSourceAndServer(StreamWithInitialData(data), (dataSource, _, initTask) =>
            {
                var receivedData = _updateSink.ExpectInit(BasicUser);
                AssertHelpers.DataSetsEqual(data, receivedData);

                Assert.True(AsyncUtils.WaitSafely(() => initTask, TimeSpan.FromSeconds(1)));
                Assert.False(initTask.IsFaulted);
                Assert.True(dataSource.Initialized);
            });
        }
        public void ResponseWithNewEtagUpdatesEtag()
        {
            var etag1     = @"""abc123"""; // note that etag strings must be quoted
            var etag2     = @"""def456""";
            var data1     = AllData;
            var data2     = new DataSetBuilder().Add("flag2", new FeatureFlagBuilder().Build()).Build();
            var data3     = new DataSetBuilder().Add("flag3", new FeatureFlagBuilder().Build()).Build();
            var responses = Handlers.SequentialWithLastRepeating(
                Handlers.Header("Etag", etag1).Then(PollingResponse(data1)),
                Handlers.Status(304),
                Handlers.Header("Etag", etag2).Then(PollingResponse(data2)),
                Handlers.Status(304),
                PollingResponse(data3) // no etag - even though the server will normally send one
                );

            using (var server = HttpServer.Start(responses))
            {
                using (var dataSource = MakeDataSource(server.Uri, BasicUser,
                                                       c => c.DataSource(Components.PollingDataSource().PollIntervalNoMinimum(BriefInterval))))
                {
                    dataSource.Start();

                    var receivedData1 = _updateSink.ExpectInit(BasicUser);
                    AssertHelpers.DataSetsEqual(data1, receivedData1);

                    var receivedData2 = _updateSink.ExpectInit(BasicUser);
                    AssertHelpers.DataSetsEqual(data2, receivedData2);

                    var receivedData3 = _updateSink.ExpectInit(BasicUser);
                    AssertHelpers.DataSetsEqual(data3, receivedData3);

                    var req1 = server.Recorder.RequireRequest();
                    var req2 = server.Recorder.RequireRequest();
                    var req3 = server.Recorder.RequireRequest();
                    var req4 = server.Recorder.RequireRequest();
                    var req5 = server.Recorder.RequireRequest();
                    var req6 = server.Recorder.RequireRequest();
                    Assert.Null(req1.Headers.Get("If-None-Match"));
                    Assert.Equal(etag1, req2.Headers.Get("If-None-Match"));
                    Assert.Equal(etag1, req3.Headers.Get("If-None-Match"));
                    Assert.Equal(etag2, req4.Headers.Get("If-None-Match")); // etag was updated by 3rd response
                    Assert.Equal(etag2, req5.Headers.Get("If-None-Match")); // etag was updated by 3rd response
                    Assert.Null(req6.Headers.Get("If-None-Match"));         // etag was cleared by 5th response
                }
            }
        }
        public void SuccessfulRequestCausesDataToBeStoredAndDataSourceInitialized()
        {
            using (var server = HttpServer.Start(PollingResponse(AllData)))
            {
                using (var dataSource = MakeDataSource(server.Uri, BasicUser))
                {
                    var initTask = dataSource.Start();

                    var receivedData = _updateSink.ExpectInit(BasicUser);
                    AssertHelpers.DataSetsEqual(AllData, receivedData);

                    Assert.True(AsyncUtils.WaitSafely(() => initTask, TimeSpan.FromSeconds(1)));
                    Assert.False(initTask.IsFaulted);
                    Assert.True(dataSource.Initialized);
                }
            }
        }
예제 #14
0
        public async Task GetAllParsesResponseAsync()
        {
            var resp = Handlers.BodyJson(AllDataJson);

            using (var server = HttpServer.Start(resp))
            {
                using (var requestor = MakeRequestor(server))
                {
                    var result = await requestor.GetAllDataAsync();

                    var req = server.Recorder.RequireRequest();
                    Assert.Equal("/sdk/latest-all", req.Path);

                    var expectedData = new DataSetBuilder().Flags(flag1).Segments(segment1).Build();
                    AssertHelpers.DataSetsEqual(expectedData, result.Value);
                }
            }
        }
예제 #15
0
        public async Task GetAllUsesCorrectUriAndParsesResponseAsync()
        {
            using (var server = await TestHttpUtils.StartServerAsync())
            {
                server.Given(Request.Create().UsingGet())
                .RespondWith(Response.Create().WithStatusCode(200).WithBody(AllDataJson));

                using (var requestor = MakeRequestor(server))
                {
                    var result = await requestor.GetAllDataAsync();

                    var req = GetLastRequest(server);
                    Assert.Equal("/sdk/latest-all", req.Path);

                    var expectedData = new DataSetBuilder().Flags(flag1).Segments(segment1).Build();
                    AssertHelpers.DataSetsEqual(expectedData, result.Value);
                }
            }
        }
        public void GetAllDoesNotReadFromPersistentStore()
        {
            var flag1 = new FeatureFlagBuilder().Version(1).Value(true).Build();
            var flag2 = new FeatureFlagBuilder().Version(2).Value(false).Build();
            var data1 = new DataSetBuilder().Add("flag1", flag1).Build();
            var data2 = new DataSetBuilder().Add("flag2", flag2).Build();

            var store = MakeStore(1);

            store.Init(BasicUser, data1, true);

            // Hack the underlying store to change the data so we can verify it isn't being reread
            _persistentStore.SetupUserData(BasicMobileKey, BasicUser.Key, data2);

            var data = store.GetAll();

            Assert.NotNull(data);
            AssertHelpers.DataSetsEqual(data1, data.Value);
        }
        public void InitDoesNotWriteToPersistentStoreIfToldNotTo()
        {
            _persistentStore.SetupUserData(BasicMobileKey, BasicUser.Key, DataSet1);

            var store = MakeStore(1);

            var data = store.GetCachedData(BasicUser);

            Assert.NotNull(data);
            AssertHelpers.DataSetsEqual(DataSet1, data.Value);

            // Hack the underlying store to remove the data so we can tell if it gets rewritten
            _persistentStore.SetupUserData(BasicMobileKey, BasicUser.Key, DataSetBuilder.Empty);

            store.Init(BasicUser, data.Value, false);

            // Because we passed false in Init, it does not rewrite the data - this behavior is to
            // avoid unnecessary writes on startup when we've just read the data from the cache.
            var underlyingData = _persistentStore.InspectUserData(BasicMobileKey, BasicUser.Key);

            Assert.NotNull(underlyingData);
            AssertHelpers.DataSetsEqual(DataSetBuilder.Empty, underlyingData.Value);
        }
예제 #18
0
        public void ParsePutData()
        {
            var allDataJson     = @"{
 ""flags"": {
  ""flag1"": { ""key"": ""flag1"", ""version"": 1},
  ""flag2"": { ""key"": ""flag2"", ""version"": 2}
 },
 ""segments"": {
  ""segment1"": {""key"": ""segment1"",""version"": 3}
 }
}";
            var expectedAllData = new DataSetBuilder()
                                  .Flags(new FeatureFlagBuilder("flag1").Version(1).Build(),
                                         new FeatureFlagBuilder("flag2").Version(2).Build())
                                  .Segments(new SegmentBuilder("segment1").Version(3).Build())
                                  .Build();

            var validInput  = @"{""path"": ""/"", ""data"": " + allDataJson + "}";
            var validResult = StreamProcessorEvents.ParsePutData(Utf8Bytes(validInput));

            Assert.Equal("/", validResult.Path);
            AssertHelpers.DataSetsEqual(expectedAllData, validResult.Data);

            var inputWithoutPath  = @"{""data"": " + allDataJson + "}";
            var resultWithoutPath = StreamProcessorEvents.ParsePutData(Utf8Bytes(inputWithoutPath));

            Assert.Null(resultWithoutPath.Path); // we don't consider this an error; some versions of Relay don't send a path
            AssertHelpers.DataSetsEqual(expectedAllData, resultWithoutPath.Data);

            var inputWithoutData = @"{""path"": ""/""}";

            Assert.ThrowsAny <JsonReadException>(() => StreamProcessorEvents.ParsePutData(Utf8Bytes(inputWithoutData)));

            var malformedJsonInput = @"{no";

            Assert.ThrowsAny <JsonReadException>(() => StreamProcessorEvents.ParsePutData(Utf8Bytes(malformedJsonInput)));
        }