public async Task When_response_exceeds_read_timeout_then_read_timeout_exception_occurs() { TimeSpan readTimeout = TimeSpan.FromSeconds(4); TimeSpan timeToWait = readTimeout.Add(TimeSpan.FromSeconds(1)); var handler = new StubMessageHandler(); handler.QueueResponse(StubResponse.StartStream( StreamAction.Write(":\n\n").AfterDelay(timeToWait))); handler.QueueResponse(StubResponse.StartStream()); var config = new ConfigurationBuilder(_uri).MessageHandler(handler).ReadTimeout(readTimeout).Build(); var evt = new EventSource(config); var receiver = new ErrorReceiver(); evt.Error += receiver; evt.Error += (_, e) => evt.Close(); await evt.StartAsync(); Assert.NotNull(receiver.ErrorReceived); Assert.Contains(receiver.ErrorReceived.Message, Resources.EventSourceService_Read_Timeout); Assert.Equal(ReadyState.Closed, receiver.SourceStateReceived); Assert.Equal(ReadyState.Shutdown, evt.ReadyState); }
public async Task Given_content_type_not_equal_to_eventstream_when_the_http_response_is_received_then_error_event_should_occur() { var handler = new StubMessageHandler(); var response = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent("testing", System.Text.Encoding.UTF8) }; response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html"); handler.QueueResponse(StubResponse.WithResponse(response)); var config = new Configuration(_uri, handler); var evt = new EventSource(config); var receiver = new ErrorReceiver(); evt.Error += receiver; evt.Error += (_, e) => evt.Close(); await evt.StartAsync(); Assert.NotNull(receiver.ErrorReceived); Assert.Equal(ReadyState.Closed, receiver.SourceStateReceived); Assert.Equal(ReadyState.Shutdown, evt.ReadyState); }
public async Task Given_bad_http_responses_then_retry_delay_durations_should_increase() { var handler = new StubMessageHandler(); var nAttempts = 2; for (int i = 0; i < nAttempts; i++) { handler.QueueResponse(StubResponse.WithIOError()); } handler.QueueResponse(StubResponse.StartStream()); var evt = new EventSource(new Configuration(_uri, handler)); var backoffs = new List <TimeSpan>(); evt.Error += (_, e) => { backoffs.Add(evt.BackOffDelay); if (backoffs.Count >= nAttempts) { evt.Close(); } }; await evt.StartAsync(); Assert.NotEmpty(backoffs); Assert.NotEqual(backoffs[0], backoffs[1]); Assert.True(backoffs[1] > backoffs[0]); }
public async Task When_reconnecting_the_outgoing_request_contains_Last_Event_Id_header() { var lastEventId = "10"; var firstResponse = $"id:{lastEventId}\nevent: put\ndata: this is a test message\n\n"; var secondResponse = $"id:20\nevent: put\ndata: this is a test message\n\n"; var handler = new StubMessageHandler(); handler.QueueResponse(StubResponse.StartStream(StreamAction.Write(firstResponse), StreamAction.CloseStream())); handler.QueueResponse(StubResponse.StartStream(StreamAction.Write(secondResponse), StreamAction.CloseStream())); var evt = new EventSource(new Configuration(_uri, handler)); var first = true; handler.RequestReceived += (s, r) => { if (first) { first = false; } else { evt.Close(); } }; await evt.StartAsync(); var requests = handler.GetRequests().ToList(); Assert.False(requests[0].Headers.Contains(Constants.LastEventIdHttpHeader)); Assert.True(requests[1].Headers.Contains(Constants.LastEventIdHttpHeader)); Assert.True(requests[1].Headers.GetValues(Constants.LastEventIdHttpHeader).Contains(lastEventId)); }
public async Task When_Configuration_Request_headers_are_set_then_the_outgoing_request_contains_those_same_headers() { var handler = new StubMessageHandler(); handler.QueueResponse(StubResponse.StartStream()); var headers = new Dictionary <string, string> { { "User-Agent", "mozilla" }, { "Authorization", "testing" } }; var config = new ConfigurationBuilder(_uri).MessageHandler(handler) .RequestHeaders(headers).Build(); var evt = new EventSource(config); handler.RequestReceived += (s, r) => evt.Close(); await evt.StartAsync(); var request = handler.GetRequests().First(); Assert.True(headers.All( item => request.Headers.Contains(item.Key) && request.Headers.GetValues(item.Key).Contains(item.Value) )); }
public void RetryDelayDurationsShouldIncrease() { var handler = new StubMessageHandler(); var nAttempts = 3; for (var i = 0; i < nAttempts; i++) { handler.QueueResponse(StubResponse.StartStream( StreamAction.Write(":hi\n"), StreamAction.CloseStream())); } handler.QueueResponse(StubResponse.StartStream()); var backoffs = new List <TimeSpan>(); using (var es = MakeEventSource(handler, builder => builder.InitialRetryDelay(TimeSpan.FromMilliseconds(100)))) { _ = new EventSink(es, _testLogging); es.Closed += (_, state) => { backoffs.Add(es.BackOffDelay); }; _ = Task.Run(es.StartAsync); for (int i = 0; i <= nAttempts; i++) { _ = handler.AwaitRequest(); } } AssertBackoffsAlwaysIncrease(backoffs, nAttempts); }
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) ); } }
public async Task When_server_returns_HTTP_error_a_reconnect_attempt_is_made() { var messageData = "hello"; var handler = new StubMessageHandler(); handler.QueueResponse(new HttpResponseMessage(HttpStatusCode.Unauthorized)); handler.QueueStringResponse("event: put\ndata: " + messageData + "\n\n"); var evt = new EventSource(new Configuration(_uri, handler)); var receiver = new ErrorReceiver(evt); string messageReceived = null; evt.MessageReceived += (_, e) => { messageReceived = e.Message.Data; evt.Close(); }; await evt.StartAsync(); Assert.Equal(2, handler.GetRequests().Count()); Assert.NotNull(receiver.ErrorReceived); var ex = Assert.IsType <EventSourceServiceUnsuccessfulResponseException>(receiver.ErrorReceived); Assert.Equal((int)HttpStatusCode.Unauthorized, ex.StatusCode); Assert.Equal(messageData, messageReceived); }
public async Task When_server_returns_HTTP_error_a_reconnect_attempt_is_made() { var messageData = "hello"; var handler = new StubMessageHandler(); handler.QueueResponse(StubResponse.WithStatus(HttpStatusCode.Unauthorized)); handler.QueueResponse(StubResponse.StartStream( StreamAction.Write("event: put\ndata: " + messageData + "\n\n"))); var evt = new EventSource(new Configuration(_uri, handler)); var errorReceiver = new ErrorReceiver(); evt.Error += errorReceiver; var messageReceiver = new MessageReceiver(); evt.MessageReceived += messageReceiver; evt.MessageReceived += (_, e) => evt.Close(); await evt.StartAsync(); Assert.Equal(2, handler.GetRequests().Count()); Assert.NotNull(errorReceiver.ErrorReceived); var ex = Assert.IsType <EventSourceServiceUnsuccessfulResponseException>(errorReceiver.ErrorReceived); Assert.Equal((int)HttpStatusCode.Unauthorized, ex.StatusCode); Assert.Equal(messageData, messageReceiver.RequireSingleEvent().Message.Data); }
public async Task When_response_does_not_exceed_read_timeout_then_expected_message_event_occurs() { var sse = "event: put\ndata: this is a test message\n\n"; var handler = new StubMessageHandler(); handler.QueueStringResponse(sse); handler.QueueResponse(new HttpResponseMessage(HttpStatusCode.NoContent)); TimeSpan readTimeout = TimeSpan.FromSeconds(4); TimeSpan timeout = readTimeout.Subtract(TimeSpan.FromSeconds(1)); var evt = new StubEventSource(new Configuration(_uri, handler, readTimeout: readTimeout), (int)timeout.TotalMilliseconds); var wasMessageReceivedEventRaised = false; var eventName = "message"; evt.MessageReceived += (_, e) => { eventName = e.EventName; wasMessageReceivedEventRaised = true; evt.Close(); }; await evt.StartAsync(); Assert.Equal("put", eventName); Assert.True(wasMessageReceivedEventRaised); }
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); } }
public async Task When_response_exceeds_read_timeout_then_read_timeout_exception_occurs() { var commentSent = ":"; var handler = new StubMessageHandler(); handler.QueueStringResponse(commentSent); TimeSpan readTimeout = TimeSpan.FromSeconds(4); TimeSpan timeout = readTimeout.Add(TimeSpan.FromSeconds(1)); var evt = new StubEventSource(new Configuration(_uri, handler, readTimeout: readTimeout), (int)timeout.TotalMilliseconds); var exceptionMessage = string.Empty; try { evt.Error += (_, e) => { exceptionMessage = e.Exception.Message; evt.Close(); }; await evt.StartAsync(); } catch (TaskCanceledException tce) {} Assert.Contains(exceptionMessage, Resources.EventSourceService_Read_Timeout); Assert.True(evt.ReadyState == ReadyState.Shutdown); }
public async Task Given_content_type_not_equal_to_eventstream_when_the_http_response_is_recieved_then_error_event_should_occur() { // Arrange var handler = new StubMessageHandler(); var response = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent("testing", System.Text.Encoding.UTF8) }; response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html"); handler.QueueResponse(response); var config = new Configuration(_uri, handler); var evt = new EventSource(config); var wasErrorEventRaised = false; evt.Error += (s, e) => { wasErrorEventRaised = true; }; //// Act await evt.StartAsync(); //// Assert Assert.True(wasErrorEventRaised); Assert.True(evt.ReadyState == ReadyState.Closed); }
public async Task Given_bad_http_responses_then_retry_delay_durations_should_be_random() { // Arrange var handler = new StubMessageHandler(); for (int i = 0; i < 2; i++) { var response = new HttpResponseMessageWithError(); response.StatusCode = HttpStatusCode.OK; response.ShouldThrowError = true; response.Content = new StringContent("Content " + i, System.Text.Encoding.UTF8, "text/event-stream"); handler.QueueResponse(response); } handler.QueueResponse(new HttpResponseMessage(HttpStatusCode.NoContent)); var evt = new EventSource(new Configuration(_uri, handler, readTimeout: _defaultReadTimeout)); var backoffs = new List <TimeSpan>(); evt.Error += (_, e) => { backoffs.Add(evt.BackOffDelay); }; //Act await evt.StartAsync(); //// Assert Assert.NotEmpty(backoffs); Assert.True(backoffs.Distinct().Count() == backoffs.Count()); }
public async Task When_LastEventId_is_configured_then_the_outgoing_request_contains_Last_Event_Id_header() { // Arrange var sse = ":"; var lastEventId = "10"; var handler = new StubMessageHandler(); handler.QueueStringResponse(sse); var config = new Configuration( uri: _uri, messageHandler: handler, readTimeout: _defaultReadTimeout, lastEventId: lastEventId); var evt = new EventSource(config); evt.CommentReceived += (_, e) => { evt.Close(); }; //// Act await evt.StartAsync(); var request = handler.GetRequests().First(); IEnumerable <string> headerValues; var lastEventHeaderExists = request.Headers.TryGetValues(Constants.LastEventIdHttpHeader, out headerValues); //// Assert Assert.True(lastEventHeaderExists); Assert.Equal(lastEventId, headerValues.First()); }
public async Task When_Configuration_Request_headers_are_set_then_the_outgoing_request_contains_those_same_headers() { // Arrange var sse = ":"; var handler = new StubMessageHandler(); handler.QueueStringResponse(sse); var headers = new Dictionary <string, string> { { "User-Agent", "mozilla" }, { "Authorization", "testing" } }; var config = new Configuration(_uri, handler, requestHeaders: headers, readTimeout: _defaultReadTimeout); var evt = new EventSource(config); evt.CommentReceived += (_, e) => { evt.Close(); }; //// Act await evt.StartAsync(); var request = handler.GetRequests().First(); //// Assert Assert.True(headers.All( item => request.Headers.Contains(item.Key) && request.Headers.GetValues(item.Key).Contains(item.Value) )); }
public async Task When_an_message_SSE_contains_id_is_received_then_last_event_id_is_set() { // Arrange var sse = "id:200\nevent: put\ndata: this is a test message\n\n"; var handler = new StubMessageHandler(); handler.QueueStringResponse(sse); var evt = new EventSource(new Configuration(_uri, handler, readTimeout: _defaultReadTimeout)); MessageEvent message = null; var wasMessageReceivedEventRaised = false; evt.MessageReceived += (_, e) => { message = e.Message; wasMessageReceivedEventRaised = true; evt.Close(); }; //// Act await evt.StartAsync(); //// Assert Assert.Equal("200", message.LastEventId); Assert.True(wasMessageReceivedEventRaised); }
public async Task When_the_HttpRequest_is_sent_then_the_outgoing_request_contains_accept_header() { // Arrange var sse = ":"; var handler = new StubMessageHandler(); handler.QueueStringResponse(sse); var evt = new EventSource(new Configuration(_uri, handler, readTimeout: _defaultReadTimeout)); evt.CommentReceived += (_, e) => { evt.Close(); }; //// Act await evt.StartAsync(); var request = handler.GetRequests().First(); IEnumerable <string> headerValues; var acceptHeaderExists = request.Headers.TryGetValues(Constants.AcceptHttpHeader, out headerValues); //// Assert Assert.True(acceptHeaderExists); Assert.True(headerValues.Contains(Constants.EventStreamContentType)); }
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); } }
public async Task When_an_event_message_SSE_is_received_then_a_message_event_is_raised() { // Arrange var sse = "event: put\ndata: this is a test message\n\n"; var handler = new StubMessageHandler(); handler.QueueStringResponse(sse); var evt = new EventSource(new Configuration(_uri, handler, readTimeout: _defaultReadTimeout)); var wasMessageReceivedEventRaised = false; var eventName = "message"; evt.MessageReceived += (_, e) => { eventName = e.EventName; wasMessageReceivedEventRaised = true; evt.Close(); }; //// Act await evt.StartAsync(); //// Assert Assert.Equal("put", eventName); Assert.True(wasMessageReceivedEventRaised); }
public async Task When_a_comment_SSE_is_received_then_a_comment_event_is_raised() { // Arrange var commentSent = ":"; var handler = new StubMessageHandler(); handler.QueueStringResponse(commentSent); var evt = new EventSource(new Configuration(_uri, handler, readTimeout: _defaultReadTimeout)); string commentReceived = string.Empty; var wasCommentEventRaised = false; evt.CommentReceived += (_, e) => { commentReceived = e.Comment; wasCommentEventRaised = true; evt.Close(); }; //// Act await evt.StartAsync(); //// Assert Assert.Equal(commentSent, commentReceived); Assert.True(wasCommentEventRaised); }
public async Task When_a_data_only_message_SSE_is_received_then_a_message_event_is_raised() { // Arrange var sse = "data: this is a test message\n\n"; var sseData = "this is a test message"; var handler = new StubMessageHandler(); handler.QueueStringResponse(sse); var evt = new EventSource(new Configuration(_uri, handler, readTimeout: _defaultReadTimeout)); MessageEvent message = null; var wasMessageReceivedEventRaised = false; evt.MessageReceived += (_, e) => { message = e.Message; wasMessageReceivedEventRaised = true; evt.Close(); }; //// Act await evt.StartAsync(); //// Assert Assert.Equal(sseData, message?.Data); Assert.True(wasMessageReceivedEventRaised); }
public void Configuration_constructor_throws_exception_when_http_client_and_connectionTimeout_is_provided() { var stubMessageHandler = new StubMessageHandler(); var e = Record.Exception(() => new Configuration(uri: _uri, httpClient: new HttpClient(stubMessageHandler), connectionTimeout: TimeSpan.Zero)); Assert.IsType <ArgumentException>(e); }
public async Task CustomHttpClientIsNotClosedWhenEventSourceCloses() { var handler = new StubMessageHandler(StubResponse.WithStatus(HttpStatusCode.OK)); using (var client = new HttpClient(handler)) { var es = new EventSource(Configuration.Builder(_uri).HttpClient(client).Build()); es.Close(); await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, _uri)); } }
public void LastEventIdHeaderIsNotSetByDefault() { var handler = new StubMessageHandler(StubResponse.StartStream()); using (var es = MakeEventSource(handler)) { _ = Task.Run(es.StartAsync); var req = handler.AwaitRequest(); Assert.False(req.Headers.Contains(Constants.LastEventIdHttpHeader)); } }
public void DefaultMethod() { var handler = new StubMessageHandler(StubResponse.StartStream()); using (var es = MakeEventSource(handler)) { _ = Task.Run(es.StartAsync); var req = handler.AwaitRequest(); Assert.Equal(HttpMethod.Get, req.Method); } }
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); } }
public void CustomMethod() { var handler = new StubMessageHandler(StubResponse.StartStream()); using (var es = MakeEventSource(handler, builder => builder.Method(HttpMethod.Post))) { _ = Task.Run(es.StartAsync); var req = handler.AwaitRequest(); Assert.Equal(HttpMethod.Post, req.Method); } }
public void LastEventIdHeaderIsSetIfConfigured() { var handler = new StubMessageHandler(StubResponse.StartStream()); var lastEventId = "abc123"; using (var es = MakeEventSource(handler, builder => builder.LastEventId(lastEventId))) { _ = Task.Run(es.StartAsync); var req = handler.AwaitRequest(); Assert.True(req.Headers.Contains(Constants.LastEventIdHttpHeader)); Assert.Contains(lastEventId, req.Headers.GetValues(Constants.LastEventIdHttpHeader)); } }
public async Task When_error_handler_closes_event_source_no_reconnect_attempt_is_made() { var handler = new StubMessageHandler(); handler.QueueResponse(StubResponse.WithStatus(HttpStatusCode.Unauthorized)); handler.QueueResponse(StubResponse.StartStream()); var evt = new EventSource(new Configuration(_uri, handler)); evt.Error += (_, e) => evt.Close(); await evt.StartAsync(); Assert.Equal(1, handler.GetRequests().Count()); }