|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Net.WebSockets;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Http.Connections;
using Microsoft.AspNetCore.Http.Connections.Client;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.SignalR.Client.Tests;
public class HttpConnectionFactoryTests
{
[Fact]
public async Task ConnectionIsDisposedIfItFailsToStartAsync()
{
var testHandler = new TestHttpMessageHandler(autoNegotiate: false, handleFirstPoll: false);
testHandler.OnRequest((req, next, ct) => Task.FromException<HttpResponseMessage>(new Exception("BOOM")));
var factory = new HttpConnectionFactory(
Options.Create(new HttpConnectionOptions
{
DefaultTransferFormat = TransferFormat.Text,
HttpMessageHandlerFactory = _ => testHandler,
}),
NullLoggerFactory.Instance);
// We don't care about the specific exception
await Assert.ThrowsAnyAsync<Exception>(async () => await factory.ConnectAsync(new UriEndPoint(new Uri("http://example.com"))));
// We care that the handler (and by extension the client) was disposed
Assert.True(testHandler.Disposed);
}
[Fact]
public async Task DoesNotSupportNonUriEndPoints()
{
var factory = new HttpConnectionFactory(
Options.Create(new HttpConnectionOptions { DefaultTransferFormat = TransferFormat.Text }),
NullLoggerFactory.Instance);
var ex = await Assert.ThrowsAsync<NotSupportedException>(async () => await factory.ConnectAsync(new IPEndPoint(IPAddress.Loopback, 0)));
Assert.Equal("The provided EndPoint must be of type UriEndPoint.", ex.Message);
}
[Fact]
public async Task OptionsUrlMustMatchEndPointIfSet()
{
var url1 = new Uri("http://example.com/1");
var url2 = new Uri("http://example.com/2");
var factory = new HttpConnectionFactory(
Options.Create(new HttpConnectionOptions
{
Url = url1,
DefaultTransferFormat = TransferFormat.Text
}),
NullLoggerFactory.Instance);
var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () => await factory.ConnectAsync(new UriEndPoint(url2)));
Assert.Equal("If HttpConnectionOptions.Url was set, it must match the UriEndPoint.Uri passed to ConnectAsync.", ex.Message);
}
[Fact]
public void ShallowCopyHttpConnectionOptionsCopiesAllPublicProperties()
{
Func<HttpMessageHandler, HttpMessageHandler> handlerFactory = handler => handler;
Func<Task<string>> tokenProvider = () => Task.FromResult("");
Func<WebSocketConnectionContext, CancellationToken, ValueTask<WebSocket>> webSocketFactory = (context, token) => ValueTask.FromResult<WebSocket>(null);
Action<ClientWebSocketOptions> webSocketConfig = options => { };
var testValues = new Dictionary<string, object>
{
{ $"{nameof(HttpConnectionOptions.HttpMessageHandlerFactory)}", handlerFactory },
{ $"{nameof(HttpConnectionOptions.Headers)}", new Dictionary<string, string>() },
{ $"{nameof(HttpConnectionOptions.ClientCertificates)}", new X509CertificateCollection() },
{ $"{nameof(HttpConnectionOptions.Cookies)}", new CookieContainer() },
{ $"{nameof(HttpConnectionOptions.Url)}", new Uri("https://example.com") },
{ $"{nameof(HttpConnectionOptions.Transports)}", HttpTransportType.ServerSentEvents },
{ $"{nameof(HttpConnectionOptions.SkipNegotiation)}", true },
{ $"{nameof(HttpConnectionOptions.AccessTokenProvider)}", tokenProvider },
{ $"{nameof(HttpConnectionOptions.CloseTimeout)}", TimeSpan.FromDays(1) },
{ $"{nameof(HttpConnectionOptions.Credentials)}", Mock.Of<ICredentials>() },
{ $"{nameof(HttpConnectionOptions.Proxy)}", Mock.Of<IWebProxy>() },
{ $"{nameof(HttpConnectionOptions.UseDefaultCredentials)}", true },
{ $"{nameof(HttpConnectionOptions.DefaultTransferFormat)}", TransferFormat.Text },
{ $"{nameof(HttpConnectionOptions.WebSocketConfiguration)}", webSocketConfig },
{ $"{nameof(HttpConnectionOptions.WebSocketFactory)}", webSocketFactory },
{ $"{nameof(HttpConnectionOptions.ApplicationMaxBufferSize)}", 1L * 1024 * 1024 },
{ $"{nameof(HttpConnectionOptions.TransportMaxBufferSize)}", 1L * 1024 * 1024 },
{ $"{nameof(HttpConnectionOptions.UseStatefulReconnect)}", true },
};
var options = new HttpConnectionOptions();
var properties = typeof(HttpConnectionOptions)
.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var property in properties)
{
property.SetValue(options, testValues[property.Name]);
}
var shallowCopiedOptions = HttpConnectionFactory.ShallowCopyHttpConnectionOptions(options);
foreach (var property in properties)
{
Assert.Equal(testValues[property.Name], property.GetValue(shallowCopiedOptions));
testValues.Remove(property.Name);
}
Assert.Empty(testValues);
}
}
|