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; } } }
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); } }
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)"); } } }
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); } }
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)); } }
public override void After(MethodInfo methodUnderTest) { TestUtility.Log($"End {methodUnderTest.DeclaringType}.{methodUnderTest.Name}"); base.After(methodUnderTest); }
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}"); }
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); } }
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}")); }
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); }