public void CreateConnectionStringBuilderFromConnectionString()
        {
            var connectionStringBuilder = new RelayConnectionStringBuilder()
            {
                Endpoint            = this.endpoint,
                EntityPath          = this.entityPath,
                SharedAccessKeyName = this.sasKeyName,
                SharedAccessKey     = this.sasKeyValue
            };
            var connectionString = connectionStringBuilder.ToString();

            TestUtility.Log("Use ConnectionStringBuilder..ctor(string) to parse the created connectionString");
            connectionStringBuilder = new RelayConnectionStringBuilder(connectionString);
            Assert.Equal(this.endpoint, connectionStringBuilder.Endpoint);
            Assert.Equal(this.entityPath, connectionStringBuilder.EntityPath);
            Assert.Equal(this.sasKeyName, connectionStringBuilder.SharedAccessKeyName);
            Assert.Equal(this.sasKeyValue, connectionStringBuilder.SharedAccessKey);
            Assert.Equal(TimeSpan.FromMinutes(1), connectionStringBuilder.OperationTimeout);
            Assert.Null(connectionStringBuilder.SharedAccessSignature);
        }
        protected async Task ReadCountBytesAsync(Stream stream, byte[] buffer, int offset, int bytesToRead, TimeSpan timeout)
        {
            DateTime timeoutInstant      = DateTime.Now.Add(timeout);
            int?     originalReadTimeout = stream.CanTimeout ? stream.ReadTimeout : (int?)null;

            try
            {
                int totalBytesRead = 0;
                do
                {
                    TimeSpan remainingTimeout = timeoutInstant.Subtract(DateTime.Now);
                    if (remainingTimeout <= TimeSpan.Zero)
                    {
                        break;
                    }

                    stream.ReadTimeout = (int)remainingTimeout.TotalMilliseconds;
                    int bytesRead = await stream.ReadAsync(buffer, offset + totalBytesRead, bytesToRead - totalBytesRead);

                    TestUtility.Log($"Stream read {bytesRead} bytes");
                    if (bytesRead == 0)
                    {
                        break;
                    }

                    totalBytesRead += bytesRead;
                }while (totalBytesRead < bytesToRead);

                if (totalBytesRead < bytesToRead)
                {
                    throw new TimeoutException("The requested number of bytes could not be received.  ReadAsync returned 0 bytes");
                }
            }
            finally
            {
                if (originalReadTimeout.HasValue)
                {
                    stream.ReadTimeout = originalReadTimeout.Value;
                }
            }
        }
Пример #3
0
        async Task ConcurrentClientsTest(EndpointTestType endpointTestType)
        {
            const int ClientCount             = 100;
            HybridConnectionListener listener = null;

            try
            {
                listener = GetHybridConnectionListener(endpointTestType);
                var client = GetHybridConnectionClient(endpointTestType);

                TestUtility.Log($"Opening {listener}");
                await listener.OpenAsync(TimeSpan.FromSeconds(10));

                TestUtility.Log($"Opening {ClientCount} connections quickly");

                var createConnectionTasks = new List <Task <HybridConnectionStream> >();
                for (var i = 0; i < ClientCount; i++)
                {
                    createConnectionTasks.Add(client.CreateConnectionAsync());
                }

                var senderTasks = new List <Task>();
                for (var i = 0; i < ClientCount; i++)
                {
                    this.AcceptEchoListener(listener);
                    senderTasks.Add(this.RunEchoClientAsync(await createConnectionTasks[i], i + 1));
                }

                await Task.WhenAll(senderTasks);

                TestUtility.Log($"Closing {listener}");
                await listener.CloseAsync(TimeSpan.FromSeconds(10));

                listener = null;
            }
            finally
            {
                await this.SafeCloseAsync(listener);
            }
        }
Пример #4
0
        async Task RequestHeadersNegativeTest()
        {
            async Task CheckBadHeaderAsync(HybridConnectionClient client, string headerName, string headerValue)
            {
                TestUtility.Log($"CheckBadHeader: \"{headerName}\": \"{headerValue}\"");
                await Assert.ThrowsAnyAsync <RelayException>(() =>
                {
                    var clientRequestHeaders         = new Dictionary <string, string>();
                    clientRequestHeaders[headerName] = headerValue;
                    return(client.CreateConnectionAsync(clientRequestHeaders));
                });
            }

            var hybridConnectionClient = GetHybridConnectionClient(EndpointTestType.Unauthenticated);

            await CheckBadHeaderAsync(hybridConnectionClient, string.Empty, string.Empty);
            await CheckBadHeaderAsync(hybridConnectionClient, string.Empty, null);
            await CheckBadHeaderAsync(hybridConnectionClient, "Bad\nHeader", "Value");
            await CheckBadHeaderAsync(hybridConnectionClient, "Bad:Header", "Value");
            await CheckBadHeaderAsync(hybridConnectionClient, "Header", "Bad\rValue");
            await CheckBadHeaderAsync(hybridConnectionClient, "Header", "Bad\nValue");
        }
        public static void LogHttpRequest(HttpRequestMessage httpRequest, HttpClient httpClient, bool showBody = true)
        {
            TestUtility.Log("Sending Request:");
            string requestUri = $"{httpClient?.BaseAddress}{httpRequest.RequestUri}";

            TestUtility.Log($"{httpRequest.Method} {requestUri} HTTP/{httpRequest.Version}");
            httpClient?.DefaultRequestHeaders.ToList().ForEach((kvp) => LogHttpHeader(kvp.Key, kvp.Value));
            httpRequest.Headers.ToList().ForEach((kvp) => LogHttpHeader(kvp.Key, kvp.Value));
            httpRequest.Content?.Headers.ToList().ForEach((kvp) => LogHttpHeader(kvp.Key, kvp.Value));

            TestUtility.Log(string.Empty);
            if (httpRequest.Content != null)
            {
                if (showBody)
                {
                    TestUtility.Log(httpRequest.Content?.ReadAsStringAsync().Result);
                }
                else
                {
                    TestUtility.Log($"(Body stream is {httpRequest.Content?.ReadAsStreamAsync().Result.Length ?? 0} bytes)");
                }
            }
        }
Пример #6
0
        async Task ListenerAbortWhileClientReadingTest(EndpointTestType endpointTestType)
        {
            HybridConnectionListener listener = null;

            try
            {
                listener = GetHybridConnectionListener(endpointTestType);
                var client = GetHybridConnectionClient(endpointTestType);

                TestUtility.Log($"Opening {listener}");
                await listener.OpenAsync(TimeSpan.FromSeconds(30));

                var clientStream = await client.CreateConnectionAsync();

                var listenerStream = await listener.AcceptConnectionAsync();

                TestUtility.Log("Client and Listener HybridStreams are connected!");

                using (var cancelSource = new CancellationTokenSource())
                {
                    TestUtility.Log("Aborting listener WebSocket");
                    cancelSource.Cancel();
                    await listenerStream.CloseAsync(cancelSource.Token);
                }

                byte[] readBuffer = new byte[1024];
                await Assert.ThrowsAsync <RelayException>(() => clientStream.ReadAsync(readBuffer, 0, readBuffer.Length));

                TestUtility.Log("Calling clientStream.Close");
                var clientCloseTask = clientStream.CloseAsync(CancellationToken.None);
            }
            finally
            {
                await this.SafeCloseAsync(listener);
            }
        }
Пример #7
0
        async Task NonExistantNamespaceTest(EndpointTestType endpointTestType)
        {
            HybridConnectionListener listener = null;

            try
            {
                TestUtility.Log("Setting ConnectionStringBuilder.Endpoint to 'sb://fakeendpoint.com'");

                var fakeEndpointConnectionStringBuilder = new RelayConnectionStringBuilder(this.ConnectionString)
                {
                    Endpoint = new Uri("sb://fakeendpoint.com")
                };

                if (endpointTestType == EndpointTestType.Authenticated)
                {
                    fakeEndpointConnectionStringBuilder.EntityPath = Constants.AuthenticatedEntityPath;
                }
                else
                {
                    fakeEndpointConnectionStringBuilder.EntityPath = Constants.UnauthenticatedEntityPath;
                }

                var fakeEndpointConnectionString = fakeEndpointConnectionStringBuilder.ToString();

                listener = new HybridConnectionListener(fakeEndpointConnectionString);
                var client = new HybridConnectionClient(fakeEndpointConnectionString);

                await Assert.ThrowsAsync <EndpointNotFoundException>(() => listener.OpenAsync());

                await Assert.ThrowsAsync <EndpointNotFoundException>(() => client.CreateConnectionAsync());
            }
            finally
            {
                await this.SafeCloseAsync(listener);
            }
        }
        public void RelayConnectionStringBuilderValidation()
        {
            Assert.Throws <ArgumentNullException>(() => new RelayConnectionStringBuilder(null));
            Assert.Throws <ArgumentNullException>(() => new RelayConnectionStringBuilder(string.Empty));

            Assert.Throws <ArgumentNullException>(() => new RelayConnectionStringBuilder {
                Endpoint = null
            });
            Assert.Throws <ArgumentNullException>(() => new RelayConnectionStringBuilder().ToString());
            Assert.Throws <ArgumentException>(() => new RelayConnectionStringBuilder {
                Endpoint = new Uri("/NotAbsoluteUri", UriKind.Relative)
            });
            Assert.Throws <ArgumentException>(() => new RelayConnectionStringBuilder("Endpoint=sb://contoso.servicebus.windows.net/;OperationTimeout=NotATimeSpan"));

            Assert.Throws <ArgumentException>(() => new RelayConnectionStringBuilder("Endpoint=NOT_A_URI"));
            Assert.Throws <ArgumentException>(() => new RelayConnectionStringBuilder("Endpoint="));
            Assert.Throws <ArgumentException>(() => new RelayConnectionStringBuilder("OperationTimeout="));
            Assert.Throws <ArgumentException>(() => new RelayConnectionStringBuilder("NOT_A_KEY=value"));
            Assert.Throws <ArgumentException>(() => new RelayConnectionStringBuilder("=NO_KEY"));
            Assert.Throws <ArgumentException>(() => new RelayConnectionStringBuilder("NOT_A_KEY_VALUE_PAIR"));
            Assert.Throws <ArgumentException>(() => new RelayConnectionStringBuilder(" "));
            Assert.Throws <ArgumentException>(() => new RelayConnectionStringBuilder("; "));

            TestUtility.Log("Try some other weird combinations which shouldn't fail.");

            new RelayConnectionStringBuilder("Endpoint=sb://whatever.servicebus.windows.net").ToString();
            new RelayConnectionStringBuilder("Endpoint=sb://whatever.servicebus.windows.net/").ToString();
            new RelayConnectionStringBuilder("Endpoint=sb://whatever.servicebus.windows.net".ToLowerInvariant()).ToString();
            new RelayConnectionStringBuilder("Endpoint=sb://whatever.servicebus.windows.net:443").ToString();
            new RelayConnectionStringBuilder("Endpoint=sb://whatever.servicebus.windows.net:443;").ToString();
            new RelayConnectionStringBuilder("Endpoint=sb://whatever.servicebus.windows.net:443;;").ToString();
            new RelayConnectionStringBuilder(";Endpoint=sb://whatever.servicebus.windows.net:443").ToString();
            new RelayConnectionStringBuilder(";;Endpoint=sb://whatever.servicebus.windows.net:443").ToString();
            new RelayConnectionStringBuilder("Endpoint=sb://whatever.servicebus.windows.net:443;;EntityPath=foo").ToString();
            new RelayConnectionStringBuilder("Endpoint=sb://whatever.servicebus.windows.net:443/;;EntityPath=foo;").ToString();
        }
        async Task LoadBalancedListeners(EndpointTestType endpointTestType)
        {
            HybridConnectionListener listener1 = null;
            HybridConnectionListener listener2 = null;
            var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));

            try
            {
                listener1 = this.GetHybridConnectionListener(endpointTestType);
                listener2 = this.GetHybridConnectionListener(endpointTestType);
                RelayConnectionStringBuilder connectionString = GetConnectionStringBuilder(endpointTestType);
                Uri endpointUri = connectionString.Endpoint;

                TestUtility.Log("Opening HybridConnectionListeners");
                await Task.WhenAll(
                    listener1.OpenAsync(cts.Token),
                    listener2.OpenAsync(cts.Token));

                const int TotalExpectedRequestCount = 50;
                long      listenerRequestCount1     = 0;
                long      listenerRequestCount2     = 0;

                listener1.RequestHandler = async(context) =>
                {
                    Interlocked.Increment(ref listenerRequestCount1);
                    context.Response.OutputStream.WriteByte(1);
                    await context.Response.CloseAsync();
                };

                listener2.RequestHandler = async(context) =>
                {
                    Interlocked.Increment(ref listenerRequestCount2);
                    context.Response.OutputStream.WriteByte(2);
                    await context.Response.CloseAsync();
                };

                Uri hybridHttpUri = new UriBuilder("https://", endpointUri.Host, endpointUri.Port, connectionString.EntityPath).Uri;
                await Enumerable.Range(0, TotalExpectedRequestCount).ParallelBatchAsync(
                    batchSize: 10,
                    parallelTasksCount: 10,
                    asyncTask: async(indexes) =>
                {
                    string messageIndexes = string.Join(",", indexes);
                    TestUtility.Log($"Messages {messageIndexes} starting");
                    try
                    {
                        foreach (var index in indexes)
                        {
                            var httpRequest = (HttpWebRequest)WebRequest.Create(hybridHttpUri);
                            using (var abortRegistration = cts.Token.Register(() => httpRequest.Abort()))
                            {
                                httpRequest.Method = HttpMethod.Get.Method;
                                await AddAuthorizationHeader(connectionString, httpRequest.Headers, hybridHttpUri);

                                using (var httpResponse = (HttpWebResponse)(await httpRequest.GetResponseAsync()))
                                {
                                    Assert.Equal(HttpStatusCode.OK, httpResponse.StatusCode);
                                }
                            }
                        }
                    }
                    catch (WebException webException)
                    {
                        TestUtility.Log($"Messages {messageIndexes} Error: {webException}");
                        throw;
                    }

                    TestUtility.Log($"Messages {messageIndexes} complete");
                });

                TestUtility.Log($"Listener1 Request Count: {listenerRequestCount1}");
                TestUtility.Log($"Listener2 Request Count: {listenerRequestCount2}");

                Assert.Equal(TotalExpectedRequestCount, listenerRequestCount1 + listenerRequestCount2);
                Assert.True(listenerRequestCount1 > 0, "Listener 1 should have received some of the events.");
                Assert.True(listenerRequestCount2 > 0, "Listener 2 should have received some of the events.");

                await Task.WhenAll(
                    listener1.CloseAsync(cts.Token),
                    listener2.CloseAsync(cts.Token));
            }
            finally
            {
                TestUtility.Log("Shutting down");
                cts.Dispose();
                await Task.WhenAll(
                    SafeCloseAsync(listener1),
                    SafeCloseAsync(listener2));
            }
        }
Пример #10
0
 public override void After(MethodInfo methodUnderTest)
 {
     TestUtility.Log($"End {methodUnderTest.DeclaringType}.{methodUnderTest.Name}");
     base.After(methodUnderTest);
 }
Пример #11
0
 public override void Before(MethodInfo methodUnderTest)
 {
     TestUtility.Log($"Begin {methodUnderTest.DeclaringType}.{methodUnderTest.Name} on {PlatformServices.Default.Application.RuntimeFramework.ToString()}");
     base.Before(methodUnderTest);
 }
        public static void LogRequestLine(HttpRequestMessage httpRequest, HttpClient httpClient)
        {
            string requestUri = $"{httpClient?.BaseAddress}{httpRequest.RequestUri}";

            TestUtility.Log($"Request: {httpRequest.Method} {requestUri} HTTP/{httpRequest.Version}");
        }
Пример #13
0
        async Task AcceptHandlerTest(EndpointTestType endpointTestType)
        {
            HybridConnectionListener listener = null;

            try
            {
                listener = GetHybridConnectionListener(endpointTestType);
                TestUtility.Log($"Opening {listener}");
                await listener.OpenAsync(TimeSpan.FromSeconds(30));

                // Install a Custom AcceptHandler which allows using Headers to control the StatusCode, StatusDescription,
                // and whether to accept or reject the client.
                listener.AcceptHandler = TestAcceptHandler;

                var clientConnectionString = GetConnectionString(endpointTestType);

                var connectionStringBuilder = new RelayConnectionStringBuilder(clientConnectionString);

                var wssUri = await GetWebSocketConnectionUri(endpointTestType);

                TestUtility.Log($"Using WebSocket address {wssUri}");
                using (var cancelSource = new CancellationTokenSource(TimeSpan.FromMinutes(1)))
                {
                    TestUtility.Log("Testing HybridConnectionListener.AcceptHandler accepting with only returning true");
                    AcceptEchoListener(listener);
                    var clientWebSocket = new ClientWebSocket();
                    clientWebSocket.Options.SetRequestHeader(TestAcceptHandlerResultHeader, true.ToString());
                    await clientWebSocket.ConnectAsync(wssUri, cancelSource.Token);

                    await clientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test closing web socket", cancelSource.Token);

                    TestUtility.Log("Testing HybridConnectionListener.AcceptHandler accepting and setting response header");
                    AcceptEchoListener(listener);
                    clientWebSocket = new ClientWebSocket();
                    clientWebSocket.Options.SetRequestHeader(TestAcceptHandlerResultHeader, true.ToString());
                    clientWebSocket.Options.SetRequestHeader(TestAcceptHandlerSetResponseHeader, "X-CustomHeader: Test value");
                    await clientWebSocket.ConnectAsync(wssUri, cancelSource.Token);

                    await clientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Test closing web socket", cancelSource.Token);

                    TestUtility.Log("Testing HybridConnectionListener.AcceptHandler rejecting with only returning false");
                    AcceptEchoListener(listener);
                    HttpStatusCode expectedStatusCode        = HttpStatusCode.BadRequest;
                    string         expectedStatusDescription = "Rejected by user code";
                    clientWebSocket = new ClientWebSocket();
                    clientWebSocket.Options.SetRequestHeader(TestAcceptHandlerResultHeader, false.ToString());
                    var webSocketException = await Assert.ThrowsAsync <WebSocketException>(() => clientWebSocket.ConnectAsync(wssUri, cancelSource.Token));

                    VerifyHttpStatusCodeAndDescription(webSocketException, expectedStatusCode, expectedStatusDescription);

                    TestUtility.Log("Testing HybridConnectionListener.AcceptHandler rejecting with setting status code and returning false");
                    AcceptEchoListener(listener);
                    expectedStatusCode        = HttpStatusCode.Unauthorized;
                    expectedStatusDescription = "Unauthorized";
                    clientWebSocket           = new ClientWebSocket();
                    clientWebSocket.Options.SetRequestHeader(TestAcceptHandlerResultHeader, false.ToString());
                    clientWebSocket.Options.SetRequestHeader(TestAcceptHandlerStatusCodeHeader, ((int)expectedStatusCode).ToString());
                    webSocketException = await Assert.ThrowsAsync <WebSocketException>(() => clientWebSocket.ConnectAsync(wssUri, cancelSource.Token));

                    VerifyHttpStatusCodeAndDescription(webSocketException, expectedStatusCode, expectedStatusDescription);

                    TestUtility.Log("Testing HybridConnectionListener.AcceptHandler rejecting with setting status code+description and returning false");
                    AcceptEchoListener(listener);
                    expectedStatusCode        = HttpStatusCode.Unauthorized;
                    expectedStatusDescription = "Status Description from test";
                    clientWebSocket           = new ClientWebSocket();
                    clientWebSocket.Options.SetRequestHeader(TestAcceptHandlerResultHeader, false.ToString());
                    clientWebSocket.Options.SetRequestHeader(TestAcceptHandlerStatusCodeHeader, ((int)expectedStatusCode).ToString());
                    clientWebSocket.Options.SetRequestHeader(TestAcceptHandlerStatusDescriptionHeader, expectedStatusDescription);
                    webSocketException = await Assert.ThrowsAsync <WebSocketException>(() => clientWebSocket.ConnectAsync(wssUri, cancelSource.Token));

                    VerifyHttpStatusCodeAndDescription(webSocketException, expectedStatusCode, expectedStatusDescription);

                    TestUtility.Log("Testing HybridConnectionListener.AcceptHandler with a custom handler that returns null instead of a valid Task<bool>");
                    listener.AcceptHandler = context => null;
                    AcceptEchoListener(listener);
                    expectedStatusCode        = HttpStatusCode.BadGateway;
                    expectedStatusDescription = "The Listener's custom AcceptHandler threw an exception. See Listener logs for details.";
                    clientWebSocket           = new ClientWebSocket();
                    webSocketException        = await Assert.ThrowsAsync <WebSocketException>(() => clientWebSocket.ConnectAsync(wssUri, cancelSource.Token));

                    VerifyHttpStatusCodeAndDescription(webSocketException, expectedStatusCode, expectedStatusDescription, false);
                }
            }
            finally
            {
                await SafeCloseAsync(listener);
            }
        }
        async Task MultiValueHeader(EndpointTestType endpointTestType)
        {
            HybridConnectionListener listener = this.GetHybridConnectionListener(endpointTestType);

            try
            {
                RelayConnectionStringBuilder connectionString = GetConnectionStringBuilder(endpointTestType);
                Uri endpointUri = connectionString.Endpoint;

                TestUtility.Log("Calling HybridConnectionListener.Open");
                await listener.OpenAsync(TimeSpan.FromSeconds(30));

                const string CustomHeaderName   = "X-CustomHeader";
                string       requestHeaderValue = string.Empty;
                listener.RequestHandler = (context) =>
                {
                    TestUtility.Log("HybridConnectionListener.RequestHandler invoked with Request:");
                    TestUtility.Log($"{context.Request.HttpMethod} {context.Request.Url}");
                    context.Request.Headers.AllKeys.ToList().ForEach((k) => TestUtility.Log($"{k}: {context.Request.Headers[k]}"));
                    TestUtility.Log(StreamToString(context.Request.InputStream));
                    requestHeaderValue = context.Request.Headers[CustomHeaderName];

                    context.Response.Headers.Add(CustomHeaderName, "responseValue1");
                    context.Response.Headers.Add(CustomHeaderName, "responseValue2");
                    context.Response.OutputStream.Close();
                };

                Uri hybridHttpUri = new UriBuilder("https://", endpointUri.Host, endpointUri.Port, connectionString.EntityPath).Uri;
                using (var client = new HttpClient {
                    BaseAddress = hybridHttpUri
                })
                {
                    client.DefaultRequestHeaders.ExpectContinue = false;

                    var getRequest = new HttpRequestMessage();
                    getRequest.Method = HttpMethod.Get;
                    await AddAuthorizationHeader(connectionString, getRequest, hybridHttpUri);

                    getRequest.Headers.Add(CustomHeaderName, "requestValue1");
                    getRequest.Headers.Add(CustomHeaderName, "requestValue2");

                    LogRequest(getRequest, client);
                    using (HttpResponseMessage response = await client.SendAsync(getRequest))
                    {
                        LogResponse(response);
                        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                        Assert.Equal("requestValue1, requestValue2", requestHeaderValue);
                        string[] responseHeaders = string.Join(",", response.Headers.GetValues(CustomHeaderName)).Split(new[] { ',' });
                        for (int i = 0; i < responseHeaders.Length; i++)
                        {
                            responseHeaders[i] = responseHeaders[i].Trim(' ', '\t');
                        }

                        Assert.Equal(new [] { "responseValue1", "responseValue2" }, responseHeaders);
                    }
                }

                await listener.CloseAsync(TimeSpan.FromSeconds(10));
            }
            finally
            {
                await SafeCloseAsync(listener);
            }
        }
Пример #15
0
        async Task RequestHeadersTest(EndpointTestType endpointTestType)
        {
            HybridConnectionListener listener = null;

            try
            {
                listener = this.GetHybridConnectionListener(endpointTestType);
                var client = GetHybridConnectionClient(endpointTestType);

                var listenerRequestTcs = new TaskCompletionSource <IDictionary <string, string> >();
                listener.AcceptHandler = (context) =>
                {
                    try
                    {
                        var headers = new Dictionary <string, string>();
                        foreach (string headerName in context.Request.Headers.AllKeys)
                        {
                            headers[headerName] = context.Request.Headers[headerName];
                        }

                        listenerRequestTcs.SetResult(headers);
                        return(Task.FromResult(true));
                    }
                    catch (Exception e)
                    {
                        listenerRequestTcs.TrySetException(e);
                        throw;
                    }
                };

                TestUtility.Log($"Opening {listener}");
                await listener.OpenAsync(TimeSpan.FromSeconds(30));

                const string ExpectedRequestHeaderName  = "CustomHeader1";
                const string ExpectedRequestHeaderValue = "Some value here; other-value/here.";

                var clientRequestHeaders = new Dictionary <string, string>();
                clientRequestHeaders[ExpectedRequestHeaderName] = ExpectedRequestHeaderValue;
                var clientStream = await client.CreateConnectionAsync(clientRequestHeaders);

                var listenerStream = await listener.AcceptConnectionAsync();

                TestUtility.Log("Client and Listener HybridStreams are connected!");

                Assert.True(listenerRequestTcs.Task.Wait(TimeSpan.FromSeconds(5)), "AcceptHandler should have been invoked by now.");
                IDictionary <string, string> listenerRequestHeaders = await listenerRequestTcs.Task;
                Assert.True(listenerRequestHeaders.ContainsKey(ExpectedRequestHeaderName), "Expected header name should be present.");
                Assert.Equal(ExpectedRequestHeaderValue, listenerRequestHeaders[ExpectedRequestHeaderName]);

                byte[] sendBuffer = this.CreateBuffer(1025, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });
                await clientStream.WriteAsync(sendBuffer, 0, sendBuffer.Length);

                TestUtility.Log($"clientStream wrote {sendBuffer.Length} bytes");

                byte[] readBuffer = new byte[sendBuffer.Length];
                await this.ReadCountBytesAsync(listenerStream, readBuffer, 0, sendBuffer.Length, TimeSpan.FromSeconds(30));

                Assert.Equal(sendBuffer, readBuffer);

                var clientStreamCloseTask = clientStream.CloseAsync(new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token);
                await listenerStream.CloseAsync(new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token);

                await clientStreamCloseTask;

                TestUtility.Log($"Closing {listener}");
                await listener.CloseAsync(TimeSpan.FromSeconds(10));

                listener = null;
            }
            finally
            {
                await this.SafeCloseAsync(listener);
            }
        }
 public static void LogHttpHeader(string headerName, IEnumerable <string> headerValues)
 {
     TestUtility.Log($"{headerName}: {string.Join(",", headerValues)}");
 }
        public async Task ConnectionStringBuilderOperationValidation()
        {
            TestUtility.Log("Create a new connection string using RelayConnectionStringBuilder properties.");
            var connectionStringBuilder = new RelayConnectionStringBuilder()
            {
                Endpoint            = this.endpoint,
                EntityPath          = this.entityPath,
                SharedAccessKeyName = this.sasKeyName,
                SharedAccessKey     = this.sasKeyValue
            };
            var connectionString = connectionStringBuilder.ToString();

            // Endpoint is expected to appear first in the connection string.
            Assert.StartsWith("Endpoint=", connectionString);

            Assert.Contains($"Endpoint={this.endpoint.AbsoluteUri}", connectionString);
            Assert.Contains($"EntityPath={this.entityPath}", connectionString);
            Assert.Contains($"SharedAccessKeyName={this.sasKeyName}", connectionString);
            Assert.Contains($"SharedAccessKey={this.sasKeyValue}", connectionString);

            // OperationTimeout should be omitted since it is the default value.
            Assert.DoesNotContain("OperationTimeout", connectionString);

            // SharedAccessSignature should be omitted since it is not specified.
            Assert.DoesNotContain("SharedAccessSignature", connectionString);

            TestUtility.Log("Try to set the timeout to a negative number");
            Assert.Throws <ArgumentOutOfRangeException>(() => connectionStringBuilder.OperationTimeout = TimeSpan.FromMinutes(-1));

            TestUtility.Log("Try to create a connection string with SAS KeyName but no KeyValue");
            connectionStringBuilder.SharedAccessKeyName = this.sasKeyName;
            connectionStringBuilder.SharedAccessKey     = null;
            Assert.Throws <ArgumentException>(() => connectionStringBuilder.ToString());

            TestUtility.Log("Try to create a connection string with SAS KeyValue but no KeyName");
            connectionStringBuilder.SharedAccessKeyName = null;
            connectionStringBuilder.SharedAccessKey     = this.sasKeyValue;
            Assert.Throws <ArgumentException>(() => connectionStringBuilder.ToString());

            var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(this.sasKeyName, this.sasKeyValue);
            var sasToken      = await tokenProvider.GetTokenAsync(this.endpoint.AbsoluteUri, TimeSpan.FromMinutes(5));

            TestUtility.Log("Create a connection string with SAS token only");
            connectionStringBuilder.SharedAccessSignature = sasToken.TokenString;
            connectionStringBuilder.SharedAccessKeyName   = null;
            connectionStringBuilder.SharedAccessKey       = null;
            connectionString = connectionStringBuilder.ToString();

            TestUtility.Log("Parse a connection string with SAS token only");
            connectionStringBuilder = new RelayConnectionStringBuilder(connectionString);
            Assert.Equal(sasToken.TokenString, connectionStringBuilder.SharedAccessSignature);
            Assert.Null(connectionStringBuilder.SharedAccessKeyName);
            Assert.Null(connectionStringBuilder.SharedAccessKey);

            TestUtility.Log("Create a connection string with SAS token and SAS KeyName");
            connectionStringBuilder.SharedAccessSignature = sasToken.TokenString;
            connectionStringBuilder.SharedAccessKeyName   = this.sasKeyName;
            connectionStringBuilder.SharedAccessKey       = null;
            Assert.Throws <ArgumentException>(() => connectionStringBuilder.ToString());

            TestUtility.Log("Create a connection string with SAS token and SAS Key value");
            connectionStringBuilder.SharedAccessSignature = sasToken.TokenString;
            connectionStringBuilder.SharedAccessKeyName   = null;
            connectionStringBuilder.SharedAccessKey       = this.sasKeyValue;
            Assert.Throws <ArgumentException>(() => connectionStringBuilder.ToString());

            TestUtility.Log("Create a new ConnectionStringBuilder, set no properties, and call ToString()");
            connectionStringBuilder = new RelayConnectionStringBuilder();
            Assert.Throws <ArgumentNullException>(() => connectionStringBuilder.ToString());

            TestUtility.Log("Set only Endpoint, call ToString()");
            connectionStringBuilder = new RelayConnectionStringBuilder()
            {
                Endpoint = this.endpoint
            };
            connectionString = connectionStringBuilder.ToString();

            TestUtility.Log("Set OperationTimeout using connectionString");
            TimeSpan operationTimeout = TimeSpan.FromSeconds(90);

            connectionString       += $"OperationTimeout={operationTimeout.ToString(null, CultureInfo.InvariantCulture)}";
            connectionStringBuilder = new RelayConnectionStringBuilder(connectionString);
            Assert.Equal(operationTimeout, connectionStringBuilder.OperationTimeout);
            connectionString = connectionStringBuilder.ToString();

            var expectedOperationTimeOutString = $";OperationTimeout={operationTimeout.ToString(null, CultureInfo.InvariantCulture)}";

            Assert.Contains(expectedOperationTimeOutString, connectionString);
        }
        async Task QueryString(EndpointTestType endpointTestType)
        {
            HybridConnectionListener listener = this.GetHybridConnectionListener(endpointTestType);

            try
            {
                RelayConnectionStringBuilder connectionString = GetConnectionStringBuilder(endpointTestType);
                Uri endpointUri = connectionString.Endpoint;

                TestUtility.Log("Calling HybridConnectionListener.Open");
                await listener.OpenAsync(TimeSpan.FromSeconds(30));

                var queryStringTests = new[]
                {
                    new { Original = "?foo=bar", Output = "?foo=bar" },
                    new { Original = "?sb-hc-id=1", Output = "" },
                    new { Original = "?sb-hc-id=1&custom=value", Output = "?custom=value" },
                    new { Original = "?custom=value&sb-hc-id=1", Output = "?custom=value" },
                    new { Original = "?sb-hc-undefined=true", Output = "" },
                    new { Original = "? Key =  Value With Space ", Output = "?+Key+=++Value+With+Space" }, // HttpUtility.ParseQueryString.ToString() in the cloud service changes this
                    new { Original = "?key='value'", Output = "?key=%27value%27" },                        // HttpUtility.ParseQueryString.ToString() in the cloud service changes this
                    new { Original = "?key=\"value\"", Output = "?key=%22value%22" },                      // HttpUtility.ParseQueryString.ToString() in the cloud service changes this
                    new { Original = "?key=<value>", Output = "?key=%3cvalue%3e" },
#if PENDING_SERVICE_UPDATE
                    new { Original = "?foo=bar&", Output = "?foo=bar&" },
                    new { Original = "?&foo=bar", Output = "?foo=bar" }, // HttpUtility.ParseQueryString.ToString() in the cloud service changes this
                    new { Original = "?sb-hc-undefined", Output = "?sb-hc-undefined" },
                    new { Original = "?CustomValue", Output = "?CustomValue" },
                    new { Original = "?custom-Value", Output = "?custom-Value" },
                    new { Original = "?custom&value", Output = "?custom&value" },
                    new { Original = "?&custom&value&", Output = "?&custom&value&" },
                    new { Original = "?&&value&&", Output = "?&&value&&" },
                    new { Original = "?+", Output = "?+" },
                    new { Original = "?%20", Output = "?+" },                                        // HttpUtility.ParseQueryString.ToString() in the cloud service changes this
                    new { Original = "? Not a key value pair ", Output = "?+Not+a+key+value+pair" }, // HttpUtility.ParseQueryString.ToString() in the cloud service changes this
                    new { Original = "?&+&", Output = "?&+&" },
                    new { Original = "?%2f%3a%3d%26", Output = "?%2f%3a%3d%26" },
#endif
                };

                RelayedHttpListenerContext actualRequestContext = null;
                listener.RequestHandler = async(context) =>
                {
                    TestUtility.Log($"RequestHandler {context.Request.HttpMethod} {context.Request.Url}");
                    actualRequestContext = context;
                    await context.Response.CloseAsync();
                };

                foreach (var queryStringTest in queryStringTests)
                {
                    string originalQueryString = queryStringTest.Original;
                    string expectedQueryString = queryStringTest.Output;
                    actualRequestContext = null;

                    TestUtility.Log($"Testing Query String '{originalQueryString}'");
                    Uri hybridHttpUri = new UriBuilder("https://", endpointUri.Host, endpointUri.Port, connectionString.EntityPath, originalQueryString).Uri;
                    using (var client = new HttpClient {
                        BaseAddress = hybridHttpUri
                    })
                    {
                        client.DefaultRequestHeaders.ExpectContinue = false;

                        var getRequest = new HttpRequestMessage();
                        getRequest.Method = HttpMethod.Get;
                        await AddAuthorizationHeader(connectionString, getRequest, hybridHttpUri);

                        LogRequestLine(getRequest, client);
                        using (HttpResponseMessage response = await client.SendAsync(getRequest))
                        {
                            LogResponseLine(response);
                            Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                            Assert.Equal(expectedQueryString, actualRequestContext.Request.Url.Query);
                        }
                    }
                }

                await listener.CloseAsync(TimeSpan.FromSeconds(10));
            }
            finally
            {
                await SafeCloseAsync(listener);
            }
        }
        async Task StatusCodes()
        {
            var endpointTestType = EndpointTestType.Authenticated;
            HybridConnectionListener listener = this.GetHybridConnectionListener(endpointTestType);

            try
            {
                RelayConnectionStringBuilder connectionString = GetConnectionStringBuilder(endpointTestType);
                Uri endpointUri = connectionString.Endpoint;

                TestUtility.Log("Calling HybridConnectionListener.Open");
                await listener.OpenAsync(TimeSpan.FromSeconds(30));

                var httpHandler = new HttpClientHandler {
                    AllowAutoRedirect = false
                };
                Uri hybridHttpUri = new UriBuilder("https://", endpointUri.Host, endpointUri.Port, connectionString.EntityPath).Uri;
                using (var client = new HttpClient(httpHandler)
                {
                    BaseAddress = hybridHttpUri
                })
                {
                    client.DefaultRequestHeaders.ExpectContinue = false;

                    HttpStatusCode[] expectedStatusCodes = new HttpStatusCode[]
                    {
                        HttpStatusCode.Accepted, HttpStatusCode.Ambiguous, HttpStatusCode.BadGateway, HttpStatusCode.BadRequest, HttpStatusCode.Conflict,
                        /*HttpStatusCode.Continue,*/ HttpStatusCode.Created, HttpStatusCode.ExpectationFailed, HttpStatusCode.Forbidden,
                        HttpStatusCode.GatewayTimeout, HttpStatusCode.Gone, HttpStatusCode.HttpVersionNotSupported, HttpStatusCode.InternalServerError,
                        HttpStatusCode.LengthRequired, HttpStatusCode.MethodNotAllowed, HttpStatusCode.MovedPermanently, HttpStatusCode.MultipleChoices,
                        HttpStatusCode.NoContent, HttpStatusCode.NonAuthoritativeInformation, HttpStatusCode.NotAcceptable, HttpStatusCode.NotFound,
                        HttpStatusCode.NotImplemented, HttpStatusCode.NotModified, HttpStatusCode.PartialContent, HttpStatusCode.PaymentRequired,
                        HttpStatusCode.PreconditionFailed, HttpStatusCode.ProxyAuthenticationRequired, HttpStatusCode.Redirect, HttpStatusCode.TemporaryRedirect,
                        HttpStatusCode.RedirectMethod, HttpStatusCode.RequestedRangeNotSatisfiable, HttpStatusCode.RequestEntityTooLarge, HttpStatusCode.RequestTimeout,
                        HttpStatusCode.RequestUriTooLong, HttpStatusCode.ResetContent, HttpStatusCode.ServiceUnavailable,
                        /*HttpStatusCode.SwitchingProtocols,*/ HttpStatusCode.Unauthorized, HttpStatusCode.UnsupportedMediaType,
                        HttpStatusCode.Unused, HttpStatusCode.UpgradeRequired, HttpStatusCode.UseProxy, (HttpStatusCode)418, (HttpStatusCode)450
                    };

                    foreach (HttpStatusCode expectedStatusCode in expectedStatusCodes)
                    {
                        TestUtility.Log($"Testing HTTP Status Code: {(int)expectedStatusCode} {expectedStatusCode}");
                        listener.RequestHandler = (context) =>
                        {
                            TestUtility.Log($"RequestHandler: {context.Request.HttpMethod} {context.Request.Url}");
                            context.Response.StatusCode = expectedStatusCode;
                            context.Response.Close();
                        };

                        var getRequest = new HttpRequestMessage();
                        getRequest.Method = HttpMethod.Get;
                        await AddAuthorizationHeader(connectionString, getRequest, hybridHttpUri);

                        LogRequestLine(getRequest, client);
                        using (HttpResponseMessage response = await client.SendAsync(getRequest))
                        {
                            TestUtility.Log($"Response: HTTP/{response.Version} {(int)response.StatusCode} {response.ReasonPhrase}");
                            Assert.Equal(expectedStatusCode, response.StatusCode);
                        }

                        var postRequest = new HttpRequestMessage();
                        postRequest.Method = HttpMethod.Post;
                        await AddAuthorizationHeader(connectionString, postRequest, hybridHttpUri);

                        string body = "{  \"a\": 11,   \"b\" :22, \"c\":\"test\",    \"d\":true}";
                        postRequest.Content = new StringContent(body);
                        postRequest.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                        LogRequestLine(postRequest, client);
                        using (HttpResponseMessage response = await client.SendAsync(postRequest))
                        {
                            TestUtility.Log($"Response: HTTP/{response.Version} {(int)response.StatusCode} {response.ReasonPhrase}");
                            Assert.Equal(expectedStatusCode, response.StatusCode);
                        }
                    }
                }

                await listener.CloseAsync(TimeSpan.FromSeconds(10));
            }
            finally
            {
                await SafeCloseAsync(listener);
            }
        }
        async Task ResponseHeadersAfterBody(EndpointTestType endpointTestType)
        {
            var cts      = new CancellationTokenSource(TimeSpan.FromSeconds(60));
            var listener = this.GetHybridConnectionListener(endpointTestType);

            try
            {
                await listener.OpenAsync(cts.Token);

                var requestHandlerComplete = new TaskCompletionSource <object>();
                listener.RequestHandler = (context) =>
                {
                    TestUtility.Log($"RequestHandler: {context.Request.HttpMethod} {context.Request.Url}");
                    try
                    {
                        // Begin writing to the output stream
                        context.Response.OutputStream.WriteByte((byte)'X');

                        // Now try to change some things which are no longer mutable
                        var exception = Assert.Throws <InvalidOperationException>(() => context.Response.StatusCode = HttpStatusCode.Found);
                        Assert.Contains("TrackingId", exception.Message, StringComparison.OrdinalIgnoreCase);
                        exception = Assert.Throws <InvalidOperationException>(() => context.Response.StatusDescription = "Test Description");
                        Assert.Contains("TrackingId", exception.Message, StringComparison.OrdinalIgnoreCase);
                        exception = Assert.Throws <InvalidOperationException>(() => context.Response.Headers["CustomHeader"] = "Header value");
                        Assert.Contains("TrackingId", exception.Message, StringComparison.OrdinalIgnoreCase);

                        context.Response.OutputStream.Close();
                        requestHandlerComplete.TrySetResult(null);
                    }
                    catch (Exception e)
                    {
                        requestHandlerComplete.TrySetException(e);
                    }
                };

                RelayConnectionStringBuilder connectionString = GetConnectionStringBuilder(endpointTestType);
                Uri endpointUri   = connectionString.Endpoint;
                Uri hybridHttpUri = new UriBuilder("https://", endpointUri.Host, endpointUri.Port, connectionString.EntityPath).Uri;

                using (var client = new HttpClient {
                    BaseAddress = hybridHttpUri
                })
                {
                    client.DefaultRequestHeaders.ExpectContinue = false;

                    var getRequest = new HttpRequestMessage();
                    await AddAuthorizationHeader(connectionString, getRequest, hybridHttpUri);

                    LogRequest(getRequest, client);
                    var sendTask = client.SendAsync(getRequest);

                    // This will throw if anything failed in the RequestHandler
                    await requestHandlerComplete.Task;

                    using (HttpResponseMessage response = await sendTask)
                    {
                        LogResponse(response);
                        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                        Assert.Equal(1, (await response.Content.ReadAsStreamAsync()).Length);
                    }
                }

                await listener.CloseAsync(cts.Token);
            }
            finally
            {
                await SafeCloseAsync(listener);
            }
        }
 public static void LogResponseLine(HttpResponseMessage httpResponse)
 {
     TestUtility.Log($"Response: HTTP/{httpResponse.Version} {(int)httpResponse.StatusCode} {httpResponse.ReasonPhrase}");
 }
 protected static void DisplayListenerInvocationCounts(IEnumerable <ListenerInfo> listeners)
 {
     listeners.ForEach(listenerInfo => TestUtility.Log($"{listenerInfo.Listener}, Invocation count: {listenerInfo.RequestCount}"));
 }
Пример #23
0
        async Task SmallRequestSmallResponse(EndpointTestType endpointTestType)
        {
            var cts = new CancellationTokenSource(TimeSpan.FromSeconds(60));
            HybridConnectionListener listener = null;

            try
            {
                listener = this.GetHybridConnectionListener(endpointTestType);
                RelayConnectionStringBuilder connectionString = GetConnectionStringBuilder(endpointTestType);
                Uri endpointUri = connectionString.Endpoint;

                string         expectedResponse   = "{ \"a\" : true }";
                HttpStatusCode expectedStatusCode = HttpStatusCode.OK;
                listener.RequestHandler = (context) =>
                {
                    TestUtility.Log("HybridConnectionListener.RequestHandler invoked with Request:");
                    TestUtility.Log($"{context.Request.HttpMethod} {context.Request.Url}");
                    context.Request.Headers.AllKeys.ToList().ForEach((k) => TestUtility.Log($"{k}: {context.Request.Headers[k]}"));
                    TestUtility.Log(StreamToString(context.Request.InputStream));

                    context.Response.StatusCode = expectedStatusCode;
                    byte[] responseBytes = Encoding.UTF8.GetBytes(expectedResponse);
                    context.Response.OutputStream.Write(responseBytes, 0, responseBytes.Length);
                    context.Response.Close();
                };

                TestUtility.Log($"Opening {listener}");
                await listener.OpenAsync(cts.Token);

                Uri hybridHttpUri = new UriBuilder("https://", endpointUri.Host, endpointUri.Port, connectionString.EntityPath).Uri;
                using (var client = new HttpClient {
                    BaseAddress = hybridHttpUri
                })
                {
                    client.DefaultRequestHeaders.ExpectContinue = false;

                    var getRequest = new HttpRequestMessage();
                    await AddAuthorizationHeader(connectionString, getRequest, hybridHttpUri);

                    getRequest.Method = HttpMethod.Get;
                    LogHttpRequest(getRequest, client);
                    using (HttpResponseMessage response = await client.SendAsync(getRequest, cts.Token))
                    {
                        LogHttpResponse(response);
                        Assert.Equal(expectedStatusCode, response.StatusCode);
                        Assert.Equal("OK", response.ReasonPhrase);
                        Assert.Equal(expectedResponse, await response.Content.ReadAsStringAsync());
                    }

                    var postRequest = new HttpRequestMessage();
                    await AddAuthorizationHeader(connectionString, postRequest, hybridHttpUri);

                    postRequest.Method = HttpMethod.Post;
                    string body = "{  \"a\": 11,   \"b\" :22, \"c\":\"test\",    \"d\":true}";
                    postRequest.Content = new StringContent(body);
                    postRequest.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                    LogHttpRequest(postRequest, client);
                    using (HttpResponseMessage response = await client.SendAsync(postRequest, cts.Token))
                    {
                        LogHttpResponse(response);
                        Assert.Equal(expectedStatusCode, response.StatusCode);
                        Assert.Equal("OK", response.ReasonPhrase);
                        Assert.Equal(expectedResponse, await response.Content.ReadAsStringAsync());
                    }
                }

                TestUtility.Log($"Closing {listener}");
                await listener.CloseAsync(cts.Token);

                listener = null;
            }
            finally
            {
                cts.Dispose();
                await this.SafeCloseAsync(listener);
            }
        }
 public override void Before(MethodInfo methodUnderTest)
 {
     TestUtility.Log($"Begin {methodUnderTest.DeclaringType}.{methodUnderTest.Name}({TestUtility.RuntimeFramework})");
     base.Before(methodUnderTest);
 }