Пример #1
0
 public Task StartThrowsFormatExceptionIfNegotiationResponseHasNoTransports()
 {
     return(RunInvalidNegotiateResponseTest <InvalidOperationException>(ResponseUtils.CreateNegotiationContent(transportTypes: 0), "Unable to connect to the server with any of the available transports."));
 }
Пример #2
0
 public Task ConnectionCannotBeStartedIfNoCommonTransportsBetweenClientAndServer(HttpTransportType serverTransports)
 {
     return(RunInvalidNegotiateResponseTest <InvalidOperationException>(ResponseUtils.CreateNegotiationContent(transportTypes: serverTransports), "Unable to connect to the server with any of the available transports."));
 }
Пример #3
0
            public async Task NegotiateThatReturnsUrlGetFollowedWithAccessToken()
            {
                var testHttpHandler = new TestHttpMessageHandler(autoNegotiate: false);
                var firstNegotiate  = true;

                testHttpHandler.OnNegotiate((request, cancellationToken) =>
                {
                    if (firstNegotiate)
                    {
                        firstNegotiate = false;

                        // The first negotiate requires an access token
                        if (request.Headers.Authorization?.Parameter != "firstSecret")
                        {
                            return(ResponseUtils.CreateResponse(HttpStatusCode.Unauthorized));
                        }

                        return(ResponseUtils.CreateResponse(HttpStatusCode.OK,
                                                            JsonConvert.SerializeObject(new
                        {
                            url = "https://another.domain.url/chat",
                            accessToken = "secondSecret"
                        })));
                    }

                    // All other requests require an access token
                    if (request.Headers.Authorization?.Parameter != "secondSecret")
                    {
                        return(ResponseUtils.CreateResponse(HttpStatusCode.Unauthorized));
                    }

                    return(ResponseUtils.CreateResponse(HttpStatusCode.OK,
                                                        JsonConvert.SerializeObject(new
                    {
                        connectionId = "0rge0d00-0040-0030-0r00-000q00r00e00",
                        availableTransports = new object[]
                        {
                            new
                            {
                                transport = "LongPolling",
                                transferFormats = new[] { "Text" }
                            },
                        }
                    })));
                });

                testHttpHandler.OnLongPoll((request, token) =>
                {
                    // All other requests require an access token
                    if (request.Headers.Authorization?.Parameter != "secondSecret")
                    {
                        return(Task.FromResult(ResponseUtils.CreateResponse(HttpStatusCode.Unauthorized)));
                    }
                    var tcs = new TaskCompletionSource <HttpResponseMessage>(TaskCreationOptions.RunContinuationsAsynchronously);

                    token.Register(() => tcs.TrySetResult(ResponseUtils.CreateResponse(HttpStatusCode.NoContent)));

                    return(tcs.Task);
                });

                testHttpHandler.OnLongPollDelete((token) => ResponseUtils.CreateResponse(HttpStatusCode.Accepted));

                Task <string> AccessTokenProvider() => Task.FromResult <string>("firstSecret");

                using (var noErrorScope = new VerifyNoErrorsScope())
                {
                    await WithConnectionAsync(
                        CreateConnection(testHttpHandler, loggerFactory : noErrorScope.LoggerFactory, accessTokenProvider : AccessTokenProvider),
                        async (connection) =>
                    {
                        await connection.StartAsync(TransferFormat.Text).OrTimeout();
                    });
                }

                Assert.Equal("http://fakeuri.org/negotiate", testHttpHandler.ReceivedRequests[0].RequestUri.ToString());
                Assert.Equal("https://another.domain.url/chat/negotiate", testHttpHandler.ReceivedRequests[1].RequestUri.ToString());
                Assert.Equal("https://another.domain.url/chat?id=0rge0d00-0040-0030-0r00-000q00r00e00", testHttpHandler.ReceivedRequests[2].RequestUri.ToString());
                Assert.Equal("https://another.domain.url/chat?id=0rge0d00-0040-0030-0r00-000q00r00e00", testHttpHandler.ReceivedRequests[3].RequestUri.ToString());
                // Delete request
                Assert.Equal(5, testHttpHandler.ReceivedRequests.Count);
            }
Пример #4
0
 public Task StartThrowsFormatExceptionIfNegotiationResponseHasNoConnectionId()
 {
     return(RunInvalidNegotiateResponseTest <FormatException>(ResponseUtils.CreateNegotiationContent(connectionId: string.Empty), "Invalid connection id."));
 }
 public Task StartThrowsFormatExceptionIfNegotiationResponseHasNoTransports()
 {
     return(RunInvalidNegotiateResponseTest <FormatException>(ResponseUtils.CreateNegotiationContent(transportTypes: null), "No transports returned in negotiation response."));
 }
            public async Task HttpConnectionSetsInherentKeepAliveFeature(HttpTransportType transportType, bool expectedValue)
            {
                using (StartVerifiableLog())
                {
                    var testHttpHandler = new TestHttpMessageHandler(autoNegotiate: false);

                    testHttpHandler.OnNegotiate((_, cancellationToken) => ResponseUtils.CreateResponse(HttpStatusCode.OK, ResponseUtils.CreateNegotiationContent()));

                    testHttpHandler.OnRequest((request, next, token) => Task.FromResult(ResponseUtils.CreateResponse(HttpStatusCode.NoContent)));

                    await WithConnectionAsync(
                        CreateConnection(testHttpHandler, transportType : transportType, loggerFactory : LoggerFactory),
                        async (connection) =>
                    {
                        await connection.StartAsync().OrTimeout();

                        var feature = connection.Features.Get <IConnectionInherentKeepAliveFeature>();
                        Assert.NotNull(feature);
                        Assert.Equal(expectedValue, feature.HasInherentKeepAlive);
                    });
                }
            }
Пример #7
0
 public Task ConnectionCannotBeStartedIfNoCommonTransportsBetweenClientAndServer()
 {
     return(RunInvalidNegotiateResponseTest <AggregateException>(ResponseUtils.CreateNegotiationContent(transportTypes: HttpTransportType.ServerSentEvents),
                                                                 "Unable to connect to the server with any of the available transports. (ServerSentEvents failed: The transport is disabled by the client.)"));
 }
Пример #8
0
 public Task ConnectionCannotBeStartedIfNoCommonTransportsBetweenClientAndServer(TransportType serverTransports)
 {
     return(RunInvalidNegotiateResponseTest <InvalidOperationException>(ResponseUtils.CreateNegotiationContent(transportTypes: serverTransports), "No requested transports available on the server."));
 }
Пример #9
0
 public Task NegotiateResponseWithNegotiateVersionRequiresConnectionToken()
 {
     return(RunInvalidNegotiateResponseTest <InvalidDataException>(ResponseUtils.CreateNegotiationContent(negotiateVersion: 1, connectionToken: null), "Invalid negotiation response received."));
 }
Пример #10
0
            public async Task NegotiateThatReturnsRedirectUrlDoesNotAddAnotherNegotiateVersionQueryString()
            {
                var testHttpHandler = new TestHttpMessageHandler(autoNegotiate: false);
                var negotiateCount  = 0;

                testHttpHandler.OnNegotiate((request, cancellationToken) =>
                {
                    negotiateCount++;
                    if (negotiateCount == 1)
                    {
                        return(ResponseUtils.CreateResponse(HttpStatusCode.OK,
                                                            JsonConvert.SerializeObject(new
                        {
                            url = "https://another.domain.url/chat?negotiateVersion=1"
                        })));
                    }
                    else
                    {
                        return(ResponseUtils.CreateResponse(HttpStatusCode.OK,
                                                            JsonConvert.SerializeObject(new
                        {
                            connectionId = "0rge0d00-0040-0030-0r00-000q00r00e00",
                            availableTransports = new object[]
                            {
                                new
                                {
                                    transport = "LongPolling",
                                    transferFormats = new[] { "Text" }
                                },
                            }
                        })));
                    }
                });

                testHttpHandler.OnLongPoll((token) =>
                {
                    var tcs = new TaskCompletionSource <HttpResponseMessage>(TaskCreationOptions.RunContinuationsAsynchronously);

                    token.Register(() => tcs.TrySetResult(ResponseUtils.CreateResponse(HttpStatusCode.NoContent)));

                    return(tcs.Task);
                });

                testHttpHandler.OnLongPollDelete((token) => ResponseUtils.CreateResponse(HttpStatusCode.Accepted));

                using (var noErrorScope = new VerifyNoErrorsScope())
                {
                    await WithConnectionAsync(
                        CreateConnection(testHttpHandler, loggerFactory : noErrorScope.LoggerFactory),
                        async (connection) =>
                    {
                        await connection.StartAsync().DefaultTimeout();
                    });
                }

                Assert.Equal("http://fakeuri.org/negotiate?negotiateVersion=1", testHttpHandler.ReceivedRequests[0].RequestUri.ToString());
                Assert.Equal("https://another.domain.url/chat/negotiate?negotiateVersion=1", testHttpHandler.ReceivedRequests[1].RequestUri.ToString());
                Assert.Equal("https://another.domain.url/chat?negotiateVersion=1&id=0rge0d00-0040-0030-0r00-000q00r00e00", testHttpHandler.ReceivedRequests[2].RequestUri.ToString());
                Assert.Equal("https://another.domain.url/chat?negotiateVersion=1&id=0rge0d00-0040-0030-0r00-000q00r00e00", testHttpHandler.ReceivedRequests[3].RequestUri.ToString());
                Assert.Equal(5, testHttpHandler.ReceivedRequests.Count);
            }
Пример #11
0
        public TestHttpMessageHandler(bool autoNegotiate = true)
        {
            _handler = (request, cancellationToken) => BaseHandler(request, cancellationToken);

            if (autoNegotiate)
            {
                OnNegotiate((_, cancellationToken) => ResponseUtils.CreateResponse(HttpStatusCode.OK, ResponseUtils.CreateNegotiationContent()));
            }
        }
Пример #12
0
        public async Task LongPollingTransportSendsAvailableMessagesWhenTheyArrive()
        {
            var sentRequests = new List <byte[]>();
            var tcs          = new TaskCompletionSource <HttpResponseMessage>();
            var firstPoll    = true;

            var mockHttpHandler = new Mock <HttpMessageHandler>();

            mockHttpHandler.Protected()
            .Setup <Task <HttpResponseMessage> >("SendAsync", ItExpr.IsAny <HttpRequestMessage>(), ItExpr.IsAny <CancellationToken>())
            .Returns <HttpRequestMessage, CancellationToken>(async(request, cancellationToken) =>
            {
                await Task.Yield();
                if (request.Method == HttpMethod.Post)
                {
                    // Build a new request object, but convert the entire payload to string
                    sentRequests.Add(await request.Content.ReadAsByteArrayAsync());
                }
                else if (request.Method == HttpMethod.Get)
                {
                    // First poll completes immediately
                    if (firstPoll)
                    {
                        firstPoll = false;
                        return(ResponseUtils.CreateResponse(HttpStatusCode.OK));
                    }

                    cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken));
                    // This is the poll task
                    return(await tcs.Task);
                }
                else if (request.Method == HttpMethod.Delete)
                {
                    return(ResponseUtils.CreateResponse(HttpStatusCode.Accepted));
                }
                return(ResponseUtils.CreateResponse(HttpStatusCode.OK));
            });

            using (var httpClient = new HttpClient(mockHttpHandler.Object))
            {
                var longPollingTransport = new LongPollingTransport(httpClient);

                try
                {
                    // Start the transport
                    await longPollingTransport.StartAsync(TestUri, TransferFormat.Binary);

                    longPollingTransport.Output.Write(Encoding.UTF8.GetBytes("Hello"));
                    longPollingTransport.Output.Write(Encoding.UTF8.GetBytes("World"));
                    await longPollingTransport.Output.FlushAsync();

                    longPollingTransport.Output.Complete();

                    await longPollingTransport.Running.DefaultTimeout();

                    await longPollingTransport.Input.ReadAllAsync();

                    Assert.Single(sentRequests);
                    Assert.Equal(new[] { (byte)'H', (byte)'e', (byte)'l', (byte)'l', (byte)'o', (byte)'W', (byte)'o', (byte)'r', (byte)'l', (byte)'d' }, sentRequests[0]);
                }
                finally
                {
                    await longPollingTransport.StopAsync();
                }
            }
        }
Пример #13
0
        public TestHttpMessageHandler(ILoggerFactory loggerFactory, bool autoNegotiate = true, bool handleFirstPoll = true)
        {
            _logger = loggerFactory?.CreateLogger <TestHttpMessageHandler>() ?? NullLoggerFactory.Instance.CreateLogger <TestHttpMessageHandler>();

            if (autoNegotiate)
            {
                OnNegotiate((_, cancellationToken) => ResponseUtils.CreateResponse(HttpStatusCode.OK, ResponseUtils.CreateNegotiationContent()));
            }

            if (handleFirstPoll)
            {
                var firstPoll = true;
                OnRequest(async(request, next, cancellationToken) =>
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    if (ResponseUtils.IsLongPollRequest(request) && firstPoll)
                    {
                        firstPoll = false;
                        return(ResponseUtils.CreateResponse(HttpStatusCode.OK));
                    }
                    else
                    {
                        return(await next());
                    }
                });
            }
        }
Пример #14
0
        public async Task SSETransportStopsWithErrorIfSendingMessageFails()
        {
            bool ExpectedErrors(WriteContext writeContext)
            {
                return(writeContext.LoggerName == typeof(ServerSentEventsTransport).FullName &&
                       writeContext.EventId.Name == "ErrorSending");
            }

            var eventStreamTcs = new TaskCompletionSource();
            var readTcs        = new TaskCompletionSource <int>();

            var mockHttpHandler = new Mock <HttpMessageHandler>();

            mockHttpHandler.Protected()
            .Setup <Task <HttpResponseMessage> >("SendAsync", ItExpr.IsAny <HttpRequestMessage>(), ItExpr.IsAny <CancellationToken>())
            .Returns <HttpRequestMessage, CancellationToken>(async(request, cancellationToken) =>
            {
                await Task.Yield();

                if (request.Headers.Accept?.Contains(new MediaTypeWithQualityHeaderValue("text/event-stream")) == true)
                {
                    // Receive loop started - allow stopping the transport
                    eventStreamTcs.SetResult();

                    // returns unfinished task to block pipelines
                    var mockStream = new Mock <Stream>();
                    mockStream
                    .Setup(s => s.ReadAsync(It.IsAny <Memory <byte> >(), It.IsAny <CancellationToken>()))
                    .Returns <Memory <byte>, CancellationToken>(async(data, ct) =>
                    {
                        using (ct.Register(() => readTcs.TrySetCanceled()))
                        {
                            return(await readTcs.Task);
                        }
                    });
                    mockStream.Setup(s => s.CanRead).Returns(true);
                    return(new HttpResponseMessage {
                        Content = new StreamContent(mockStream.Object)
                    });
                }

                return(ResponseUtils.CreateResponse(System.Net.HttpStatusCode.InternalServerError));
            });

            using (var httpClient = new HttpClient(mockHttpHandler.Object))
                using (StartVerifiableLog(expectedErrorsFilter: ExpectedErrors))
                {
                    var sseTransport = new ServerSentEventsTransport(httpClient, LoggerFactory);

                    await sseTransport.StartAsync(
                        new Uri("http://fakeuri.org"), TransferFormat.Text).DefaultTimeout();

                    await eventStreamTcs.Task;

                    await sseTransport.Output.WriteAsync(new byte[] { 0x42 });

                    var exception = await Assert.ThrowsAsync <HttpRequestException>(() => sseTransport.Input.ReadAllAsync().DefaultTimeout());

                    Assert.Contains("500", exception.Message);

                    // Errors are only communicated through the pipe
                    await sseTransport.Running.DefaultTimeout();
                }
        }
Пример #15
0
 public Task ConnectionCannotBeStartedIfNoTransportProvidedByServer()
 {
     return(RunInvalidNegotiateResponseTest <NoTransportSupportedException>(ResponseUtils.CreateNegotiationContent(transportTypes: HttpTransportType.None), "None of the transports supported by the client are supported by the server."));
 }
Пример #16
0
        public TestHttpMessageHandler(bool autoNegotiate = true, bool handleFirstPoll = true)
        {
            if (autoNegotiate)
            {
                OnNegotiate((_, cancellationToken) => ResponseUtils.CreateResponse(HttpStatusCode.OK, ResponseUtils.CreateNegotiationContent()));
            }

            if (handleFirstPoll)
            {
                var firstPoll = true;
                OnRequest(async(request, next, cancellationToken) =>
                {
                    if (ResponseUtils.IsLongPollRequest(request) && firstPoll)
                    {
                        firstPoll = false;
                        return(ResponseUtils.CreateResponse(HttpStatusCode.OK));
                    }
                    else
                    {
                        return(await next());
                    }
                });
            }
        }
Пример #17
0
 public Task StartThrowsFormatExceptionIfNegotiationResponseHasNoConnectionId()
 {
     return(RunInvalidNegotiateResponseTest <FormatException>(ResponseUtils.CreateNegotiationContent(connectionId: null), "Invalid connection id returned in negotiation response."));
 }