コード例 #1
0
        public void ReconnectAfterHttpError()
        {
            HttpStatusCode error1 = HttpStatusCode.BadRequest, error2 = HttpStatusCode.InternalServerError;
            var            message = new MessageEvent("put", "hello", _uri);

            var handler = new StubMessageHandler();

            handler.QueueResponse(StubResponse.WithStatus(error1));
            handler.QueueResponse(StubResponse.WithStatus(error2));
            handler.QueueResponse(StubResponse.StartStream(StreamAction.Write(message)));

            using (var es = MakeEventSource(handler, builder => builder.InitialRetryDelay(TimeSpan.FromMilliseconds(20))))
            {
                var eventSink = new EventSink(es, _testLogging);
                _ = Task.Run(es.StartAsync);

                var action1 = eventSink.ExpectAction();
                var ex1     = Assert.IsType <EventSourceServiceUnsuccessfulResponseException>(action1.Exception);
                Assert.Equal((int)error1, ex1.StatusCode);

                eventSink.ExpectActions(EventSink.ClosedAction());

                var action2 = eventSink.ExpectAction();
                var ex2     = Assert.IsType <EventSourceServiceUnsuccessfulResponseException>(action2.Exception);
                Assert.Equal((int)error2, ex2.StatusCode);

                eventSink.ExpectActions(
                    EventSink.ClosedAction(),
                    EventSink.OpenedAction(),
                    EventSink.MessageReceivedAction(message)
                    );
            }
        }
コード例 #2
0
        public void ReconnectAfterHttpError()
        {
            HttpStatusCode error1 = HttpStatusCode.BadRequest, error2 = HttpStatusCode.InternalServerError;
            var            message = new MessageEvent("put", "hello", _uri);

            var handler = Handlers.Sequential(
                Handlers.Status((int)error1),
                Handlers.Status((int)error2),
                StartStream().Then(WriteEvent(message)).Then(LeaveStreamOpen())
                );

            WithServerAndEventSource(handler, c => c.InitialRetryDelay(TimeSpan.FromMilliseconds(20)), (server, es) =>
            {
                var eventSink = new EventSink(es, _testLogging);
                _             = Task.Run(es.StartAsync);

                var action1 = eventSink.ExpectAction();
                var ex1     = Assert.IsType <EventSourceServiceUnsuccessfulResponseException>(action1.Exception);
                Assert.Equal((int)error1, ex1.StatusCode);

                eventSink.ExpectActions(EventSink.ClosedAction());

                var action2 = eventSink.ExpectAction();
                var ex2     = Assert.IsType <EventSourceServiceUnsuccessfulResponseException>(action2.Exception);
                Assert.Equal((int)error2, ex2.StatusCode);

                eventSink.ExpectActions(
                    EventSink.ClosedAction(),
                    EventSink.OpenedAction(),
                    EventSink.MessageReceivedAction(message)
                    );
            });
        }
コード例 #3
0
        public void CanRestartStream(bool resetBackoff)
        {
            // This test is in EventSourceStreamReadingTest rather than EventSourceReconnectingTest
            // because the important thing here is that the stream reading logic can be interrupted.
            int nAttempts    = 3;
            var initialDelay = TimeSpan.FromMilliseconds(50);

            var anEvent = new MessageEvent("put", "x", _uri);
            var stream  = StubResponse.StartStream(StreamAction.Write(anEvent));
            var handler = new StubMessageHandler();

            for (var i = 0; i <= nAttempts; i++)
            {
                handler.QueueResponse(stream);
            }

            var backoffs = new List <TimeSpan>();

            using (var es = MakeEventSource(handler, builder => builder.InitialRetryDelay(initialDelay)))
            {
                var sink = new EventSink(es, _testLogging);
                es.Closed += (_, ex) =>
                {
                    backoffs.Add(es.BackOffDelay);
                };
                _ = Task.Run(es.StartAsync);

                sink.ExpectActions(
                    EventSink.OpenedAction(),
                    EventSink.MessageReceivedAction(anEvent)
                    );

                for (var i = 0; i < nAttempts; i++)
                {
                    es.Restart(resetBackoff);

                    sink.ExpectActions(
                        EventSink.ClosedAction(),
                        EventSink.OpenedAction(),
                        EventSink.MessageReceivedAction(anEvent)
                        );
                }
            }

            if (resetBackoff)
            {
                Assert.All(backoffs, delay => Assert.InRange(delay, TimeSpan.Zero, initialDelay));
            }
            else
            {
                AssertBackoffsAlwaysIncrease(backoffs, nAttempts);
            }
        }
コード例 #4
0
        public void CanRestartStream(bool resetBackoff)
        {
            // This test is in EventSourceStreamReadingTest rather than EventSourceReconnectingTest
            // because the important thing here is that the stream reading logic can be interrupted.
            int nAttempts    = 3;
            var initialDelay = TimeSpan.FromMilliseconds(50);

            var anEvent = new MessageEvent("put", "x", _uri);
            var handler = Handlers.Sequential(
                Enumerable.Range(0, nAttempts + 1).Select(_ =>
                                                          StartStream().Then(WriteEvent(anEvent)).Then(LeaveStreamOpen())
                                                          ).ToArray());

            var backoffs = new List <TimeSpan>();

            using (var server = HttpServer.Start(handler))
            {
                using (var es = MakeEventSource(server.Uri, config => config.InitialRetryDelay(initialDelay)))
                {
                    var sink = new EventSink(es, _testLogging);
                    es.Closed += (_, ex) =>
                    {
                        backoffs.Add(es.BackOffDelay);
                    };
                    _ = Task.Run(es.StartAsync);

                    sink.ExpectActions(
                        EventSink.OpenedAction(),
                        EventSink.MessageReceivedAction(anEvent)
                        );

                    for (var i = 0; i < nAttempts; i++)
                    {
                        es.Restart(resetBackoff);

                        sink.ExpectActions(
                            EventSink.ClosedAction(),
                            EventSink.OpenedAction(),
                            EventSink.MessageReceivedAction(anEvent)
                            );
                    }
                }
            }

            if (resetBackoff)
            {
                Assert.All(backoffs, delay => Assert.InRange(delay, TimeSpan.Zero, initialDelay));
            }
            else
            {
                AssertBackoffsAlwaysIncrease(backoffs, nAttempts);
            }
        }
コード例 #5
0
        public void ReadTimeoutIsDetected(bool utf8Mode)
        {
            TimeSpan readTimeout   = TimeSpan.FromMilliseconds(200);
            var      streamHandler = Handlers.StartChunks("text/event-stream")
                                     .Then(Handlers.WriteChunkString("data: event1\n\ndata: e"))
                                     .Then(Handlers.Delay(readTimeout + readTimeout))
                                     .Then(Handlers.WriteChunkString("vent2\n\n"));

            using (var server = HttpServer.Start(streamHandler))
            {
                var config = Configuration.Builder(server.Uri)
                             .LogAdapter(_testLogging)
                             .ReadTimeout(readTimeout)
                             .PreferDataAsUtf8Bytes(utf8Mode)
                             .Build();
                using (var es = new EventSource(config))
                {
                    var sink = new EventSink(es)
                    {
                        Output = _testLogger.Debug
                    };
                    _ = es.StartAsync();
                    sink.ExpectActions(
                        EventSink.OpenedAction(),
                        EventSink.MessageReceivedAction(new MessageEvent(MessageEvent.DefaultName, "event1", server.Uri)),
                        EventSink.ErrorAction(new ReadTimeoutException()),
                        EventSink.ClosedAction()
                        );
                }
            }
        }
コード例 #6
0
        public void NonUtf8EncodingIsReadAsStrings(bool preferUtf8Data)
        {
            var handler = new StubMessageHandler();

            handler.QueueResponse(StubResponse.StartStream(
                                      Encoding.GetEncoding("iso-8859-1"),
                                      BasicStreamTestParams.StreamActions));

            var config = Configuration.Builder(_uri).HttpMessageHandler(handler)
                         .LogAdapter(_testLogging)
                         .PreferDataAsUtf8Bytes(preferUtf8Data)
                         .Build();

            using (var es = new EventSource(config))
            {
                var sink = new EventSink(es, _testLogging)
                {
                    ExpectUtf8Data = false
                };

                _ = Task.Run(es.StartAsync);

                sink.ExpectActions(BasicStreamTestParams.ExpectedEventActions);
            }
        }
コード例 #7
0
        public void CanReceiveUtf8EventDataAsBytes(bool setExplicitEncoding)
        {
            var handler = new StubMessageHandler();

            handler.QueueResponse(StubResponse.StartStream(
                                      setExplicitEncoding ? Encoding.UTF8 : null,
                                      BasicStreamTestParams.StreamActions));

            var config = Configuration.Builder(_uri).HttpMessageHandler(handler)
                         .LogAdapter(_testLogging)
                         .PreferDataAsUtf8Bytes(true)
                         .Build();

            using (var es = new EventSource(config))
            {
                var eventSink = new EventSink(es, _testLogging)
                {
                    ExpectUtf8Data = true
                };

                _ = Task.Run(es.StartAsync);

                eventSink.ExpectActions(BasicStreamTestParams.ExpectedEventActions);
            }
        }
コード例 #8
0
        public void CanSpecifyLoggerInstance()
        {
            WithServerAndEventSource(HandlerWithBasicEvent(), c => c.Logger(_logCapture.Logger("special")), (server, es) =>
            {
                var eventSink = new EventSink(es);
                _             = Task.Run(es.StartAsync);

                eventSink.ExpectActions(EventSink.OpenedAction());

                Assert.NotEmpty(_logCapture.GetMessages());
                Assert.True(_logCapture.GetMessages().All(m => m.LoggerName == "special"), _logCapture.ToString());
            });
        }
コード例 #9
0
        public void ConnectingLogMessage()
        {
            WithServerAndEventSource(HandlerWithBasicEvent(), (server, es) =>
            {
                var eventSink = new EventSink(es);
                _             = Task.Run(es.StartAsync);

                eventSink.ExpectActions(EventSink.OpenedAction());

                Assert.True(_logCapture.HasMessageWithText(LogLevel.Debug,
                                                           "Making GET request to EventSource URI " + server.Uri),
                            _logCapture.ToString());
            });
        }
コード例 #10
0
        public void UsesDefaultLoggerNameWhenLogAdapterIsSpecified()
        {
            WithServerAndEventSource(HandlerWithBasicEvent(), (server, es) =>
            {
                var eventSink = new EventSink(es);
                _             = Task.Run(es.StartAsync);

                eventSink.ExpectActions(EventSink.OpenedAction());

                Assert.NotEmpty(_logCapture.GetMessages());
                Assert.True(_logCapture.GetMessages().All(m => m.LoggerName == Configuration.DefaultLoggerName),
                            _logCapture.ToString());
            });
        }
コード例 #11
0
        public void EventReceivedLogMessage()
        {
            WithServerAndEventSource(HandlerWithBasicEvent(), (server, es) =>
            {
                var eventSink = new EventSink(es, _testLogging);
                _             = Task.Run(es.StartAsync);

                eventSink.ExpectActions(
                    EventSink.OpenedAction(),
                    EventSink.MessageReceivedAction(BasicEvent)
                    );

                Assert.True(_logCapture.HasMessageWithText(LogLevel.Debug,
                                                           string.Format(@"Received event ""{0}""", BasicEvent.Name)));
            });
        }
コード例 #12
0
        public void CanSpecifyLoggerInstance()
        {
            var config = new ConfigurationBuilder(_uri)
                         .HttpMessageHandler(HandlerWithBasicEvent())
                         .Logger(_logCapture.Logger("special"))
                         .Build();

            using (var es = new EventSource(config))
            {
                var eventSink = new EventSink(es);
                _ = Task.Run(es.StartAsync);

                eventSink.ExpectActions(EventSink.OpenedAction());

                Assert.NotEmpty(_logCapture.GetMessages());
                Assert.True(_logCapture.GetMessages().All(m => m.LoggerName == "special"), _logCapture.ToString());
            }
        }
コード例 #13
0
        public void UsesDefaultLoggerNameWhenLogAdapterIsSpecified()
        {
            var config = new ConfigurationBuilder(_uri)
                         .HttpMessageHandler(HandlerWithBasicEvent())
                         .LogAdapter(_logCapture)
                         .Build();

            using (var es = new EventSource(config))
            {
                var eventSink = new EventSink(es);
                _ = Task.Run(es.StartAsync);

                eventSink.ExpectActions(EventSink.OpenedAction());

                Assert.NotEmpty(_logCapture.GetMessages());
                Assert.True(_logCapture.GetMessages().All(m => m.LoggerName == Configuration.DefaultLoggerName),
                            _logCapture.ToString());
            }
        }
コード例 #14
0
        public void ConnectingLogMessage()
        {
            var config = new ConfigurationBuilder(_uri)
                         .HttpMessageHandler(HandlerWithBasicEvent())
                         .LogAdapter(_logCapture)
                         .Build();

            using (var es = new EventSource(config))
            {
                var eventSink = new EventSink(es);
                _ = Task.Run(es.StartAsync);

                eventSink.ExpectActions(EventSink.OpenedAction());

                Assert.True(_logCapture.HasMessageWithText(LogLevel.Debug,
                                                           "Making GET request to EventSource URI " + _uri),
                            _logCapture.ToString());
            }
        }
コード例 #15
0
        public void CanReceiveUtf8EventDataAsStrings(bool setExplicitEncoding)
        {
            using (var server = HttpServer.Start(MakeStreamHandler(setExplicitEncoding ? Encoding.UTF8 : null)))
            {
                var config = Configuration.Builder(server.Uri)
                             .LogAdapter(_testLogging)
                             .Build();
                using (var es = new EventSource(config))
                {
                    var eventSink = new EventSink(es, _testLogging)
                    {
                        ExpectUtf8Data = false
                    };

                    _ = Task.Run(es.StartAsync);

                    eventSink.ExpectActions(expectedEventActions);
                }
            }
        }
コード例 #16
0
        public void NonUtf8EncodingIsReadAsStrings(bool preferUtf8Data)
        {
            using (var server = HttpServer.Start(MakeStreamHandler(Encoding.GetEncoding("iso-8859-1"))))
            {
                var config = Configuration.Builder(server.Uri)
                             .LogAdapter(_testLogging)
                             .PreferDataAsUtf8Bytes(preferUtf8Data)
                             .Build();
                using (var es = new EventSource(config))
                {
                    var sink = new EventSink(es, _testLogging)
                    {
                        ExpectUtf8Data = false
                    };

                    _ = Task.Run(es.StartAsync);

                    sink.ExpectActions(expectedEventActions);
                }
            }
        }
コード例 #17
0
        public void EventReceivedLogMessage()
        {
            var config = new ConfigurationBuilder(_uri)
                         .HttpMessageHandler(HandlerWithBasicEvent())
                         .LogAdapter(_logCapture)
                         .Build();

            using (var es = new EventSource(config))
            {
                var eventSink = new EventSink(es, _testLogging);
                _ = Task.Run(es.StartAsync);

                eventSink.ExpectActions(
                    EventSink.OpenedAction(),
                    EventSink.MessageReceivedAction(BasicEvent)
                    );

                Assert.True(_logCapture.HasMessageWithText(LogLevel.Debug,
                                                           string.Format(@"Received event ""{0}""", BasicEvent.Name)));
            }
        }
コード例 #18
0
        public void ReadTimeoutIsDetected(bool utf8Mode)
        {
            TimeSpan readTimeout = TimeSpan.FromMilliseconds(200);

            IEnumerable <string> DoChunks()
            {
                yield return("");

                yield return("data: event1\n\ndata: e");

                Thread.Sleep(readTimeout + readTimeout);
                yield return("vent2\n\n");
            }

            using (var server = StartWebServerOnAvailablePort(out var uri, RespondWithChunks("text/event-stream", DoChunks)))
            {
                var config = Configuration.Builder(uri)
                             .LogAdapter(_testLogging)
                             .ReadTimeout(readTimeout)
                             .PreferDataAsUtf8Bytes(utf8Mode)
                             .Build();
                using (var es = new EventSource(config))
                {
                    var sink = new EventSink(es)
                    {
                        Output = _testLogger.Debug
                    };
                    _ = es.StartAsync();
                    sink.ExpectActions(
                        EventSink.OpenedAction(),
                        EventSink.MessageReceivedAction(new MessageEvent(MessageEvent.DefaultName, "event1", uri)),
                        EventSink.ErrorAction(new ReadTimeoutException()),
                        EventSink.ClosedAction()
                        );
                }
            }
        }
コード例 #19
0
        public void ReceiveEventStreamInChunks()
        {
            // This simply verifies that chunked streaming works as expected and that events are being
            // parsed correctly regardless of how the chunks line up with the events.

            var eventData = new List <string>();

            for (var i = 0; i < 200; i++)
            {
                eventData.Add(string.Format("data{0}", i) + new string('x', i % 7));
            }
            var allBody           = string.Concat(eventData.Select(data => "data:" + data + "\n\n"));
            var allEventsReceived = new TaskCompletionSource <bool>();

            IEnumerable <string> MakeChunks()
            {
                var i = 0;

                for (var pos = 0; ;)
                {
                    int chunkSize = i % 20 + 1;
                    if (pos + chunkSize >= allBody.Length)
                    {
                        yield return(allBody.Substring(pos));

                        break;
                    }
                    yield return(allBody.Substring(pos, chunkSize));

                    pos += chunkSize;
                    i++;
                }
            }

            try
            {
                Handler streamHandler = Handlers.StartChunks("text/event-stream")
                                        .Then(async ctx =>
                {
                    foreach (var s in MakeChunks())
                    {
                        await Handlers.WriteChunkString(s)(ctx);
                    }
                    await allEventsReceived.Task;
                });
                using (var server = HttpServer.Start(streamHandler))
                {
                    var expectedActions = new List <EventSink.Action>();
                    expectedActions.Add(EventSink.OpenedAction());
                    foreach (var data in eventData)
                    {
                        expectedActions.Add(EventSink.MessageReceivedAction(new MessageEvent(MessageEvent.DefaultName, data, server.Uri)));
                    }

                    var config = Configuration.Builder(server.Uri).LogAdapter(_testLogging).Build();
                    using (var es = new EventSource(config))
                    {
                        var sink = new EventSink(es);
                        _ = es.StartAsync();
                        sink.ExpectActions(expectedActions.ToArray());
                    }
                }
            }
            finally
            {
                allEventsReceived.SetResult(true);
            }
        }
コード例 #20
0
        public void ReceiveEventStreamInChunks()
        {
            // This simply verifies that chunked streaming works as expected and that events are being
            // parsed correctly regardless of how the chunks line up with the events.

            var eventData = new List <string>();

            for (var i = 0; i < 200; i++)
            {
                eventData.Add(string.Format("data{0}", i) + new string('x', i % 7));
            }
            var allBody           = string.Concat(eventData.Select(data => "data:" + data + "\n\n"));
            var allEventsReceived = new EventWaitHandle(false, EventResetMode.ManualReset);

            IEnumerable <string> DoChunks()
            {
                var i = 0;

                for (var pos = 0; ;)
                {
                    int chunkSize = i % 20 + 1;
                    if (pos + chunkSize >= allBody.Length)
                    {
                        yield return(allBody.Substring(pos));

                        break;
                    }
                    yield return(allBody.Substring(pos, chunkSize));

                    pos += chunkSize;
                    i++;
                }
                allEventsReceived.WaitOne();
            }

            try
            {
                using (var server = StartWebServerOnAvailablePort(out var uri,
                                                                  RespondWithChunks("text/event-stream", DoChunks)))
                {
                    var expectedActions = new List <EventSink.Action>();
                    expectedActions.Add(EventSink.OpenedAction());
                    foreach (var data in eventData)
                    {
                        expectedActions.Add(EventSink.MessageReceivedAction(new MessageEvent(MessageEvent.DefaultName, data, uri)));
                    }

                    var config = Configuration.Builder(uri).LogAdapter(_testLogging).Build();
                    using (var es = new EventSource(config))
                    {
                        var sink = new EventSink(es);
                        _ = es.StartAsync();
                        sink.ExpectActions(expectedActions.ToArray());
                    }
                }
            }
            finally
            {
                allEventsReceived.Set();
            }
        }