From 9e8bdde30c7df139750e3e7b3c1b37b466ce899e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 27 Jul 2025 15:34:33 -0400 Subject: [PATCH] Remove `HttpClient` abstractions Now implement mocked `HttpMessageHandler`s as recommended: https://stackoverflow.com/a/36427274/3976486 --- src/Tgstation.Server.Client/ApiClient.cs | 6 +- .../ApiClientFactory.cs | 16 +++- .../IApiClientFactory.cs | 19 +++++ .../Http/CachedResponseStream.cs | 2 +- .../Http/HttpClient.cs | 51 ------------- .../Http/HttpClientFactory.cs | 41 ---------- .../Http/IAbstractHttpClientFactory.cs | 14 ---- .../Http/IHttpClient.cs | 33 -------- .../Engine/OpenDreamInstallation.cs | 7 +- .../Components/Engine/OpenDreamInstaller.cs | 8 +- .../Engine/WindowsOpenDreamInstaller.cs | 6 +- src/Tgstation.Server.Host/Core/Application.cs | 9 ++- .../IO/FileDownloader.cs | 7 +- .../IO/RequestFileStreamProvider.cs | 6 +- .../Security/OAuth/DiscordOAuthValidator.cs | 6 +- .../Security/OAuth/GenericOAuthValidator.cs | 11 ++- .../OAuth/InvisionCommunityOAuthValidator.cs | 6 +- .../Security/OAuth/KeycloakOAuthValidator.cs | 6 +- .../Security/OAuth/OAuthProviders.cs | 6 +- .../Swarm/SwarmService.cs | 7 +- .../Utils/AbstractHttpClientFactory.cs | 76 ------------------- .../TestApiClient.cs | 11 ++- .../Tgstation.Server.Client.Tests.csproj | 1 + .../Extensions/TestVersionExtensions.cs | 19 +++++ .../MockHttpMessageHandler.cs | 23 ++++++ .../Tgstation.Server.Common.Tests.csproj | 12 +++ .../Engine/TestOpenDreamInstaller.cs | 7 +- .../IO/TestFileDownloader.cs | 22 ++++-- .../IO/TestRequestFileStreamProvider.cs | 67 ++++++++-------- .../Swarm/SwarmRpcMapper.cs | 9 +-- .../Swarm/TestableSwarmNode.cs | 13 ++-- .../Tgstation.Server.Host.Tests.csproj | 1 + .../CachingFileDownloader.cs | 19 ++++- .../Live/Instance/InstanceTest.cs | 4 +- .../Live/RateLimitRetryingApiClient.cs | 2 +- .../Live/RateLimitRetryingApiClientFactory.cs | 17 ++++- .../Live/TestLiveServer.cs | 10 +-- tgstation-server.sln | 15 ++++ 38 files changed, 255 insertions(+), 340 deletions(-) delete mode 100644 src/Tgstation.Server.Common/Http/HttpClient.cs delete mode 100644 src/Tgstation.Server.Common/Http/HttpClientFactory.cs delete mode 100644 src/Tgstation.Server.Common/Http/IAbstractHttpClientFactory.cs delete mode 100644 src/Tgstation.Server.Common/Http/IHttpClient.cs delete mode 100644 src/Tgstation.Server.Host/Utils/AbstractHttpClientFactory.cs create mode 100644 tests/Tgstation.Server.Common.Tests/Extensions/TestVersionExtensions.cs create mode 100644 tests/Tgstation.Server.Common.Tests/MockHttpMessageHandler.cs create mode 100644 tests/Tgstation.Server.Common.Tests/Tgstation.Server.Common.Tests.csproj diff --git a/src/Tgstation.Server.Client/ApiClient.cs b/src/Tgstation.Server.Client/ApiClient.cs index 0a7214e3cd..ffa5731f35 100644 --- a/src/Tgstation.Server.Client/ApiClient.cs +++ b/src/Tgstation.Server.Client/ApiClient.cs @@ -69,9 +69,9 @@ namespace Tgstation.Server.Client }; /// - /// The for the . + /// The for the . /// - readonly IHttpClient httpClient; + readonly HttpClient httpClient; /// /// The s used by the . @@ -166,7 +166,7 @@ namespace Tgstation.Server.Client /// The value of . /// The value of . public ApiClient( - IHttpClient httpClient, + HttpClient httpClient, Uri url, ApiHeaders apiHeaders, ApiHeaders? tokenRefreshHeaders, diff --git a/src/Tgstation.Server.Client/ApiClientFactory.cs b/src/Tgstation.Server.Client/ApiClientFactory.cs index 0429f7d649..469010c153 100644 --- a/src/Tgstation.Server.Client/ApiClientFactory.cs +++ b/src/Tgstation.Server.Client/ApiClientFactory.cs @@ -1,7 +1,7 @@ using System; +using System.Net.Http; using Tgstation.Server.Api; -using Tgstation.Server.Common.Http; namespace Tgstation.Server.Client { @@ -19,5 +19,19 @@ namespace Tgstation.Server.Client apiHeaders, tokenRefreshHeaders, authless); + + /// + public IApiClient CreateApiClient( + Uri url, + ApiHeaders apiHeaders, + ApiHeaders? tokenRefreshHeaders, + HttpMessageHandler handler, + bool disposeHandler, + bool authless) => new ApiClient( + new HttpClient(handler, disposeHandler), + url, + apiHeaders, + tokenRefreshHeaders, + authless); } } diff --git a/src/Tgstation.Server.Client/IApiClientFactory.cs b/src/Tgstation.Server.Client/IApiClientFactory.cs index e49385dcf9..f0fa49a42a 100644 --- a/src/Tgstation.Server.Client/IApiClientFactory.cs +++ b/src/Tgstation.Server.Client/IApiClientFactory.cs @@ -1,4 +1,5 @@ using System; +using System.Net.Http; using Tgstation.Server.Api; @@ -22,5 +23,23 @@ namespace Tgstation.Server.Client ApiHeaders apiHeaders, ApiHeaders? tokenRefreshHeaders, bool authless); + + /// + /// Create an . + /// + /// The base . + /// The for the . + /// The to use to generate a new . + /// The to use with the internal . + /// If should be disposed with the created . + /// If there should be no authentication performed. + /// A new . + public IApiClient CreateApiClient( + Uri url, + ApiHeaders apiHeaders, + ApiHeaders? tokenRefreshHeaders, + HttpMessageHandler handler, + bool disposeHandler, + bool authless); } } diff --git a/src/Tgstation.Server.Common/Http/CachedResponseStream.cs b/src/Tgstation.Server.Common/Http/CachedResponseStream.cs index eb007b54a5..14361b6ef8 100644 --- a/src/Tgstation.Server.Common/Http/CachedResponseStream.cs +++ b/src/Tgstation.Server.Common/Http/CachedResponseStream.cs @@ -36,7 +36,7 @@ namespace Tgstation.Server.Common.Http response.Content = null; try { - // don't cry about the missing CancellationToken overload: https://github.com/dotnet/runtime/issues/916 + // don't cry about the missing CancellationToken overload: https://github.com/dotnet/corefx/issues/32615#issuecomment-562083237 var responseStream = await content.ReadAsStreamAsync().ConfigureAwait(false); return new CachedResponseStream(content, responseStream); } diff --git a/src/Tgstation.Server.Common/Http/HttpClient.cs b/src/Tgstation.Server.Common/Http/HttpClient.cs deleted file mode 100644 index 692c10a304..0000000000 --- a/src/Tgstation.Server.Common/Http/HttpClient.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading; -using System.Threading.Tasks; - -namespace Tgstation.Server.Common.Http -{ - /// - public sealed class HttpClient : IHttpClient - { - /// - public TimeSpan Timeout - { - get => httpClient.Timeout; - set => httpClient.Timeout = value; - } - - /// - public HttpRequestHeaders DefaultRequestHeaders => httpClient.DefaultRequestHeaders; - - /// - /// The real . - /// - readonly System.Net.Http.HttpClient httpClient; - - /// - /// Initializes a new instance of the class. - /// - /// The to wrap. - public HttpClient(System.Net.Http.HttpClient implementation) - { - httpClient = implementation ?? throw new ArgumentNullException(nameof(implementation)); - } - - /// - /// Initializes a new instance of the class. - /// - public HttpClient() - : this(new System.Net.Http.HttpClient()) - { - } - - /// - public void Dispose() => httpClient.Dispose(); - - /// - public Task SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken) - => httpClient.SendAsync(request, completionOption, cancellationToken); - } -} diff --git a/src/Tgstation.Server.Common/Http/HttpClientFactory.cs b/src/Tgstation.Server.Common/Http/HttpClientFactory.cs deleted file mode 100644 index 93659471b5..0000000000 --- a/src/Tgstation.Server.Common/Http/HttpClientFactory.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Net.Http.Headers; - -namespace Tgstation.Server.Common.Http -{ - /// - /// that creates s. - /// - public sealed class HttpClientFactory : IAbstractHttpClientFactory - { - /// - public IHttpClient CreateClient() - { - var client = new HttpClient(); - try - { - client.DefaultRequestHeaders.UserAgent.Add(userAgent); - return client; - } - catch - { - client.Dispose(); - throw; - } - } - - /// - /// The used as created client's User-Agent header on request. - /// - readonly ProductInfoHeaderValue userAgent; - - /// - /// Initializes a new instance of the class. - /// - /// The value of . - public HttpClientFactory(ProductInfoHeaderValue userAgent) - { - this.userAgent = userAgent ?? throw new ArgumentNullException(nameof(userAgent)); - } - } -} diff --git a/src/Tgstation.Server.Common/Http/IAbstractHttpClientFactory.cs b/src/Tgstation.Server.Common/Http/IAbstractHttpClientFactory.cs deleted file mode 100644 index 120712f2bb..0000000000 --- a/src/Tgstation.Server.Common/Http/IAbstractHttpClientFactory.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Tgstation.Server.Common.Http -{ - /// - /// Creates s. - /// - public interface IAbstractHttpClientFactory - { - /// - /// Create a . - /// - /// A new . - IHttpClient CreateClient(); - } -} diff --git a/src/Tgstation.Server.Common/Http/IHttpClient.cs b/src/Tgstation.Server.Common/Http/IHttpClient.cs deleted file mode 100644 index d0ade7050d..0000000000 --- a/src/Tgstation.Server.Common/Http/IHttpClient.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading; -using System.Threading.Tasks; - -namespace Tgstation.Server.Common.Http -{ - /// - /// For sending HTTP requests. - /// - public interface IHttpClient : IDisposable - { - /// - /// The request timeout. - /// - TimeSpan Timeout { get; set; } - - /// - /// The used on every request. - /// - HttpRequestHeaders DefaultRequestHeaders { get; } - - /// - /// Send an HTTP request. - /// - /// The . - /// The . - /// The for the operation. - /// A resulting in the of the request. - Task SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken); - } -} diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs index b8f5e7f877..76d129729d 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstallation.cs @@ -12,7 +12,6 @@ using Microsoft.Extensions.Logging; using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; -using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Components.Deployment; using Tgstation.Server.Host.Components.Interop; using Tgstation.Server.Host.IO; @@ -56,9 +55,9 @@ namespace Tgstation.Server.Host.Components.Engine readonly IAsyncDelayer asyncDelayer; /// - /// The for the . + /// The for the . /// - readonly IAbstractHttpClientFactory httpClientFactory; + readonly IHttpClientFactory httpClientFactory; /// /// Path to the Robust.Server.dll. @@ -84,7 +83,7 @@ namespace Tgstation.Server.Host.Components.Engine public OpenDreamInstallation( IIOManager installationIOManager, IAsyncDelayer asyncDelayer, - IAbstractHttpClientFactory httpClientFactory, + IHttpClientFactory httpClientFactory, string dotnetPath, string serverDllPath, string compilerDllPath, diff --git a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs index 87ad2cd721..c165e33d03 100644 --- a/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/OpenDreamInstaller.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; @@ -8,7 +9,6 @@ using Microsoft.Extensions.Options; using Tgstation.Server.Api.Models; using Tgstation.Server.Common.Extensions; -using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.IO; @@ -77,9 +77,9 @@ namespace Tgstation.Server.Host.Components.Engine readonly IAsyncDelayer asyncDelayer; /// - /// The for the . + /// The for the . /// - readonly IAbstractHttpClientFactory httpClientFactory; + readonly IHttpClientFactory httpClientFactory; /// /// Initializes a new instance of the class. @@ -100,7 +100,7 @@ namespace Tgstation.Server.Host.Components.Engine IProcessExecutor processExecutor, IRepositoryManager repositoryManager, IAsyncDelayer asyncDelayer, - IAbstractHttpClientFactory httpClientFactory, + IHttpClientFactory httpClientFactory, IOptions generalConfigurationOptions, IOptions sessionConfigurationOptions) : base(ioManager, logger) diff --git a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs index 1cc8da52c5..de36a53d10 100644 --- a/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs +++ b/src/Tgstation.Server.Host/Components/Engine/WindowsOpenDreamInstaller.cs @@ -1,4 +1,5 @@ using System; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; @@ -7,7 +8,6 @@ using Microsoft.Extensions.Options; using Tgstation.Server.Api.Models; using Tgstation.Server.Common.Extensions; -using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.IO; @@ -36,7 +36,7 @@ namespace Tgstation.Server.Host.Components.Engine /// The for the . /// The for the . /// The for the . - /// The for the . + /// The for the . /// The of for the . /// The of for the . /// The value of . @@ -47,7 +47,7 @@ namespace Tgstation.Server.Host.Components.Engine IProcessExecutor processExecutor, IRepositoryManager repositoryManager, IAsyncDelayer asyncDelayer, - IAbstractHttpClientFactory httpClientFactory, + IHttpClientFactory httpClientFactory, IOptions generalConfigurationOptions, IOptions sessionConfigurationOptions, IFilesystemLinkFactory linkFactory) diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index 3246b8ba0f..13f06e6e7b 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -46,7 +46,6 @@ using Serilog.Sinks.Elasticsearch; using Tgstation.Server.Api; using Tgstation.Server.Api.Hubs; using Tgstation.Server.Api.Models; -using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Authority; using Tgstation.Server.Host.Authority.Core; using Tgstation.Server.Host.Components; @@ -311,8 +310,12 @@ namespace Tgstation.Server.Host.Core services.AddCors(); // Enable managed HTTP clients - services.AddHttpClient(); - services.AddSingleton(); + services + .AddHttpClient() + .ConfigureHttpClientDefaults( + builder => builder.ConfigureHttpClient( + client => client.DefaultRequestHeaders.UserAgent.Add( + assemblyInformationProvider.ProductInfoHeaderValue))); // configure metrics var prometheusPort = postSetupServices.GeneralConfiguration.PrometheusPort; diff --git a/src/Tgstation.Server.Host/IO/FileDownloader.cs b/src/Tgstation.Server.Host/IO/FileDownloader.cs index 30efdb6718..10b148136f 100644 --- a/src/Tgstation.Server.Host/IO/FileDownloader.cs +++ b/src/Tgstation.Server.Host/IO/FileDownloader.cs @@ -5,7 +5,6 @@ using System.Net.Http.Headers; using Microsoft.Extensions.Logging; using Tgstation.Server.Api; -using Tgstation.Server.Common.Http; namespace Tgstation.Server.Host.IO { @@ -13,9 +12,9 @@ namespace Tgstation.Server.Host.IO public sealed class FileDownloader : IFileDownloader { /// - /// The for the . + /// The for the . /// - readonly IAbstractHttpClientFactory httpClientFactory; + readonly IHttpClientFactory httpClientFactory; /// /// The for the . @@ -27,7 +26,7 @@ namespace Tgstation.Server.Host.IO /// /// The value of . /// The value of . - public FileDownloader(IAbstractHttpClientFactory httpClientFactory, ILogger logger) + public FileDownloader(IHttpClientFactory httpClientFactory, ILogger logger) { this.httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); diff --git a/src/Tgstation.Server.Host/IO/RequestFileStreamProvider.cs b/src/Tgstation.Server.Host/IO/RequestFileStreamProvider.cs index 12461e4e7f..ef82a2bf53 100644 --- a/src/Tgstation.Server.Host/IO/RequestFileStreamProvider.cs +++ b/src/Tgstation.Server.Host/IO/RequestFileStreamProvider.cs @@ -14,9 +14,9 @@ namespace Tgstation.Server.Host.IO sealed class RequestFileStreamProvider : IFileStreamProvider { /// - /// The for the . + /// The for the . /// - readonly IHttpClient httpClient; + readonly HttpClient httpClient; /// /// The for the . @@ -43,7 +43,7 @@ namespace Tgstation.Server.Host.IO /// /// The value of . /// The value of . - public RequestFileStreamProvider(IHttpClient httpClient, HttpRequestMessage requestMessage) + public RequestFileStreamProvider(HttpClient httpClient, HttpRequestMessage requestMessage) { this.httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient)); this.requestMessage = requestMessage ?? throw new ArgumentNullException(nameof(requestMessage)); diff --git a/src/Tgstation.Server.Host/Security/OAuth/DiscordOAuthValidator.cs b/src/Tgstation.Server.Host/Security/OAuth/DiscordOAuthValidator.cs index 3195ec9dcf..c11a1ba991 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/DiscordOAuthValidator.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/DiscordOAuthValidator.cs @@ -1,9 +1,9 @@ using System; +using System.Net.Http; using Microsoft.Extensions.Logging; using Tgstation.Server.Api.Models; -using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Configuration; namespace Tgstation.Server.Host.Security.OAuth @@ -25,11 +25,11 @@ namespace Tgstation.Server.Host.Security.OAuth /// /// Initializes a new instance of the class. /// - /// The for the . + /// The for the . /// The for the . /// The for the . public DiscordOAuthValidator( - IAbstractHttpClientFactory httpClientFactory, + IHttpClientFactory httpClientFactory, ILogger logger, OAuthConfiguration oAuthConfiguration) : base(httpClientFactory, logger, oAuthConfiguration) diff --git a/src/Tgstation.Server.Host/Security/OAuth/GenericOAuthValidator.cs b/src/Tgstation.Server.Host/Security/OAuth/GenericOAuthValidator.cs index b68813be3c..eb5570c634 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/GenericOAuthValidator.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/GenericOAuthValidator.cs @@ -13,7 +13,6 @@ using Newtonsoft.Json.Serialization; using Tgstation.Server.Api; using Tgstation.Server.Api.Models; -using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Extensions; @@ -53,7 +52,7 @@ namespace Tgstation.Server.Host.Security.OAuth /// /// The for the . /// - readonly IAbstractHttpClientFactory httpClientFactory; + readonly IHttpClientFactory httpClientFactory; /// /// Gets that should be used. @@ -74,7 +73,7 @@ namespace Tgstation.Server.Host.Security.OAuth /// The value of . /// The value of . public GenericOAuthValidator( - IAbstractHttpClientFactory httpClientFactory, + IHttpClientFactory httpClientFactory, ILogger logger, OAuthConfiguration oAuthConfiguration) { @@ -178,10 +177,10 @@ namespace Tgstation.Server.Host.Security.OAuth protected abstract OAuthTokenRequest CreateTokenRequest(string code); /// - /// Create a new configured . + /// Create a new configured . /// - /// A new configured . - IHttpClient CreateHttpClient() + /// A new configured . + HttpClient CreateHttpClient() { var httpClient = httpClientFactory.CreateClient(); try diff --git a/src/Tgstation.Server.Host/Security/OAuth/InvisionCommunityOAuthValidator.cs b/src/Tgstation.Server.Host/Security/OAuth/InvisionCommunityOAuthValidator.cs index 20206e86d8..75733d0c51 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/InvisionCommunityOAuthValidator.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/InvisionCommunityOAuthValidator.cs @@ -1,9 +1,9 @@ using System; +using System.Net.Http; using Microsoft.Extensions.Logging; using Tgstation.Server.Api.Models; -using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Configuration; namespace Tgstation.Server.Host.Security.OAuth @@ -27,11 +27,11 @@ namespace Tgstation.Server.Host.Security.OAuth /// /// Initializes a new instance of the class. /// - /// The for the . + /// The for the . /// The for the . /// The for the . public InvisionCommunityOAuthValidator( - IAbstractHttpClientFactory httpClientFactory, + IHttpClientFactory httpClientFactory, ILogger logger, OAuthConfiguration oAuthConfiguration) : base(httpClientFactory, logger, oAuthConfiguration) diff --git a/src/Tgstation.Server.Host/Security/OAuth/KeycloakOAuthValidator.cs b/src/Tgstation.Server.Host/Security/OAuth/KeycloakOAuthValidator.cs index 795812b40d..ee9efcd214 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/KeycloakOAuthValidator.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/KeycloakOAuthValidator.cs @@ -1,9 +1,9 @@ using System; +using System.Net.Http; using Microsoft.Extensions.Logging; using Tgstation.Server.Api.Models; -using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Configuration; namespace Tgstation.Server.Host.Security.OAuth @@ -32,11 +32,11 @@ namespace Tgstation.Server.Host.Security.OAuth /// /// Initializes a new instance of the class. /// - /// The for the . + /// The for the . /// The for the . /// The for the . public KeycloakOAuthValidator( - IAbstractHttpClientFactory httpClientFactory, + IHttpClientFactory httpClientFactory, ILogger logger, OAuthConfiguration oAuthConfiguration) : base(httpClientFactory, logger, oAuthConfiguration) diff --git a/src/Tgstation.Server.Host/Security/OAuth/OAuthProviders.cs b/src/Tgstation.Server.Host/Security/OAuth/OAuthProviders.cs index 1f67b1999f..f514094e01 100644 --- a/src/Tgstation.Server.Host/Security/OAuth/OAuthProviders.cs +++ b/src/Tgstation.Server.Host/Security/OAuth/OAuthProviders.cs @@ -1,12 +1,12 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Tgstation.Server.Api.Models; -using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Utils.GitHub; @@ -24,12 +24,12 @@ namespace Tgstation.Server.Host.Security.OAuth /// Initializes a new instance of the class. /// /// The to use. - /// The to use. + /// The to use. /// The to use. /// The containing the to use. public OAuthProviders( IGitHubServiceFactory gitHubServiceFactory, - IAbstractHttpClientFactory httpClientFactory, + IHttpClientFactory httpClientFactory, ILoggerFactory loggerFactory, IOptions securityConfigurationOptions) { diff --git a/src/Tgstation.Server.Host/Swarm/SwarmService.cs b/src/Tgstation.Server.Host/Swarm/SwarmService.cs index dcb3737ff9..1bd10a8720 100644 --- a/src/Tgstation.Server.Host/Swarm/SwarmService.cs +++ b/src/Tgstation.Server.Host/Swarm/SwarmService.cs @@ -19,7 +19,6 @@ using Newtonsoft.Json; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Common.Extensions; -using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Core; using Tgstation.Server.Host.Database; @@ -74,9 +73,9 @@ namespace Tgstation.Server.Host.Swarm readonly IAssemblyInformationProvider assemblyInformationProvider; /// - /// The for the . + /// The for the . /// - readonly IAbstractHttpClientFactory httpClientFactory; + readonly IHttpClientFactory httpClientFactory; /// /// The for the . @@ -175,7 +174,7 @@ namespace Tgstation.Server.Host.Swarm IDatabaseContextFactory databaseContextFactory, IDatabaseSeeder databaseSeeder, IAssemblyInformationProvider assemblyInformationProvider, - IAbstractHttpClientFactory httpClientFactory, + IHttpClientFactory httpClientFactory, IAsyncDelayer asyncDelayer, IServerUpdater serverUpdater, IFileTransferTicketProvider transferService, diff --git a/src/Tgstation.Server.Host/Utils/AbstractHttpClientFactory.cs b/src/Tgstation.Server.Host/Utils/AbstractHttpClientFactory.cs deleted file mode 100644 index 973551e1d4..0000000000 --- a/src/Tgstation.Server.Host/Utils/AbstractHttpClientFactory.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System; -using System.Net.Http; - -using Microsoft.Extensions.Logging; - -using Tgstation.Server.Common.Http; -using Tgstation.Server.Host.System; - -namespace Tgstation.Server.Host.Utils -{ - /// - sealed class AbstractHttpClientFactory : IAbstractHttpClientFactory - { - /// - /// The real . - /// - readonly IHttpClientFactory httpClientFactory; - - /// - /// The for the . - /// - readonly IAssemblyInformationProvider assemblyInformationProvider; - - /// - /// The for the . - /// - readonly ILogger logger; - - /// - /// Initializes a new instance of the class. - /// - /// The value of . - /// The value of . - /// The value of . - public AbstractHttpClientFactory( - IHttpClientFactory httpClientFactory, - IAssemblyInformationProvider assemblyInformationProvider, - ILogger logger) - { - this.httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory)); - this.assemblyInformationProvider = assemblyInformationProvider ?? throw new ArgumentNullException(nameof(assemblyInformationProvider)); - this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); - } - - /// -#pragma warning disable IDE0079 -#pragma warning disable CA2000 - public IHttpClient CreateClient() - { - logger.LogTrace("Creating client..."); - var innerClient = httpClientFactory.CreateClient(); - try - { - var client = new Tgstation.Server.Common.Http.HttpClient(innerClient); - innerClient = null; - try - { - client.DefaultRequestHeaders.UserAgent.Add(assemblyInformationProvider.ProductInfoHeaderValue); - return client; - } - catch - { - client.Dispose(); - throw; - } - } - catch - { - innerClient?.Dispose(); - throw; - } - } -#pragma warning restore CA2000 -#pragma warning restore IDE0079 - } -} diff --git a/tests/Tgstation.Server.Client.Tests/TestApiClient.cs b/tests/Tgstation.Server.Client.Tests/TestApiClient.cs index 900d64a56f..630526dbd6 100644 --- a/tests/Tgstation.Server.Client.Tests/TestApiClient.cs +++ b/tests/Tgstation.Server.Client.Tests/TestApiClient.cs @@ -15,6 +15,7 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Models.Internal; using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Common.Http; +using Tgstation.Server.Common.Tests; namespace Tgstation.Server.Client.Tests { @@ -44,11 +45,10 @@ namespace Tgstation.Server.Client.Tests Content = new StringContent(sampleJson) }; - var httpClient = new Mock(); - httpClient.Setup(x => x.SendAsync(It.IsNotNull(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(response)); + var handler = new MockHttpMessageHandler((_, __) => Task.FromResult(response)); var client = new ApiClient( - httpClient.Object, + new HttpClient(handler), new Uri("http://fake.com"), new ApiHeaders( new ProductHeaderValue("fake"), @@ -84,11 +84,10 @@ namespace Tgstation.Server.Client.Tests Content = new StringContent(fakeJson) }; - var httpClient = new Mock(); - httpClient.Setup(x => x.SendAsync(It.IsNotNull(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(response)); + var handler = new MockHttpMessageHandler((_, __) => Task.FromResult(response)); var client = new ApiClient( - httpClient.Object, + new HttpClient(handler), new Uri("http://fake.com"), new ApiHeaders( new ProductHeaderValue("fake"), diff --git a/tests/Tgstation.Server.Client.Tests/Tgstation.Server.Client.Tests.csproj b/tests/Tgstation.Server.Client.Tests/Tgstation.Server.Client.Tests.csproj index 66888f4430..7784b3fda9 100644 --- a/tests/Tgstation.Server.Client.Tests/Tgstation.Server.Client.Tests.csproj +++ b/tests/Tgstation.Server.Client.Tests/Tgstation.Server.Client.Tests.csproj @@ -11,6 +11,7 @@ + diff --git a/tests/Tgstation.Server.Common.Tests/Extensions/TestVersionExtensions.cs b/tests/Tgstation.Server.Common.Tests/Extensions/TestVersionExtensions.cs new file mode 100644 index 0000000000..d5f7fee277 --- /dev/null +++ b/tests/Tgstation.Server.Common.Tests/Extensions/TestVersionExtensions.cs @@ -0,0 +1,19 @@ +using System; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Tgstation.Server.Common.Extensions.Tests +{ + /// + /// Tests for . + /// + [TestClass] + public sealed class TestVersionExtensions + { + [TestMethod] + public void TestSemver() + { + Assert.AreEqual(new Version(1, 2, 3), new Version(1, 2, 3, 4).Semver()); + } + } +} diff --git a/tests/Tgstation.Server.Common.Tests/MockHttpMessageHandler.cs b/tests/Tgstation.Server.Common.Tests/MockHttpMessageHandler.cs new file mode 100644 index 0000000000..e4fc02dd89 --- /dev/null +++ b/tests/Tgstation.Server.Common.Tests/MockHttpMessageHandler.cs @@ -0,0 +1,23 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; + +namespace Tgstation.Server.Common.Tests +{ + /// + /// Simple mock . + /// + public sealed class MockHttpMessageHandler : HttpMessageHandler + { + readonly Func> callback; + + public MockHttpMessageHandler(Func> callback) + { + this.callback = callback ?? throw new ArgumentNullException(nameof(callback)); + } + + protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + => callback(request, cancellationToken); + } +} diff --git a/tests/Tgstation.Server.Common.Tests/Tgstation.Server.Common.Tests.csproj b/tests/Tgstation.Server.Common.Tests/Tgstation.Server.Common.Tests.csproj new file mode 100644 index 0000000000..e915d283b0 --- /dev/null +++ b/tests/Tgstation.Server.Common.Tests/Tgstation.Server.Common.Tests.csproj @@ -0,0 +1,12 @@ + + + + + $(TgsFrameworkVersion) + + + + + + + diff --git a/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs b/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs index 8950acc6ab..e2ded03c84 100644 --- a/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs +++ b/tests/Tgstation.Server.Host.Tests/Components/Engine/TestOpenDreamInstaller.cs @@ -1,4 +1,5 @@ -using System.Threading; +using System.Net.Http; +using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; @@ -8,8 +9,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using Tgstation.Server.Api.Models; -using Tgstation.Server.Api.Models.Internal; -using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Components.Repository; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.IO; @@ -76,7 +75,7 @@ namespace Tgstation.Server.Host.Components.Engine.Tests Mock.Of(), mockRepositoryManager.Object, Mock.Of(), - Mock.Of(), + Mock.Of(), mockGeneralConfigOptions.Object, mockSessionConfigOptions.Object); diff --git a/tests/Tgstation.Server.Host.Tests/IO/TestFileDownloader.cs b/tests/Tgstation.Server.Host.Tests/IO/TestFileDownloader.cs index 768be41442..f5e22b4aa9 100644 --- a/tests/Tgstation.Server.Host.Tests/IO/TestFileDownloader.cs +++ b/tests/Tgstation.Server.Host.Tests/IO/TestFileDownloader.cs @@ -1,5 +1,7 @@ using System; using System.IO; +using System.Net; +using System.Net.Http; using System.Text; using System.Threading.Tasks; @@ -8,7 +10,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; -using Tgstation.Server.Common.Http; +using Tgstation.Server.Common.Tests; using Tgstation.Server.Host.System; namespace Tgstation.Server.Host.IO.Tests @@ -27,8 +29,8 @@ Please see the following for more context: public void TestConstructor() { Assert.ThrowsException(() => new FileDownloader(null, null)); - Assert.ThrowsException(() => new FileDownloader(Mock.Of(), null)); - _ = new FileDownloader(Mock.Of(), Mock.Of>()); + Assert.ThrowsException(() => new FileDownloader(Mock.Of(), null)); + _ = new FileDownloader(Mock.Of(), Mock.Of>()); } [TestMethod] @@ -65,11 +67,21 @@ Please see the following for more context: builder.SetMinimumLevel(LogLevel.Trace); }); + var mockHttpClientFactory = new Mock(); + var httpClient = new HttpClient( + new MockHttpMessageHandler( + (_, __) => Task.FromResult( + new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent(ExpectedData), + }))); + + mockHttpClientFactory.Setup(x => x.CreateClient(String.Empty)).Returns(httpClient); + try { return new FileDownloader( - new HttpClientFactory( - new AssemblyInformationProvider().ProductInfoHeaderValue), + mockHttpClientFactory.Object, loggerFactory.CreateLogger()); } catch diff --git a/tests/Tgstation.Server.Host.Tests/IO/TestRequestFileStreamProvider.cs b/tests/Tgstation.Server.Host.Tests/IO/TestRequestFileStreamProvider.cs index a950ee6b9f..cb8af00bfb 100644 --- a/tests/Tgstation.Server.Host.Tests/IO/TestRequestFileStreamProvider.cs +++ b/tests/Tgstation.Server.Host.Tests/IO/TestRequestFileStreamProvider.cs @@ -10,6 +10,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using Tgstation.Server.Common.Http; +using Tgstation.Server.Common.Tests; using Tgstation.Server.Host.Extensions; namespace Tgstation.Server.Host.IO.Tests @@ -21,7 +22,7 @@ namespace Tgstation.Server.Host.IO.Tests public async Task TestConstruction() { Assert.ThrowsException(() => new RequestFileStreamProvider(null, null)); - var mockClient = Mock.Of(); + var mockClient = new HttpClient(); Assert.ThrowsException(() => new RequestFileStreamProvider(mockClient, null)); await using var test = new RequestFileStreamProvider(mockClient, new HttpRequestMessage()); } @@ -31,21 +32,23 @@ namespace Tgstation.Server.Host.IO.Tests { var sequence = new byte[] { 1, 2, 3 }; var resultMs = new MemoryStream(sequence); - var mockHttpClient = new Mock(); var response = new HttpResponseMessage() { Content = new StreamContent(resultMs), }; - + var ran = false; var request = new HttpRequestMessage(); - mockHttpClient - .Setup(x => x.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, It.IsAny())) - .Returns(Task.FromResult(response)) - .Verifiable(); + var mockHttpClient = new HttpClient( + new MockHttpMessageHandler( + (_, _) => + { + ran = true; + return Task.FromResult(response); + })); - await using var downloader = new RequestFileStreamProvider(mockHttpClient.Object, request); + await using var downloader = new RequestFileStreamProvider(mockHttpClient, request); var download = await downloader.GetResult(default); @@ -55,8 +58,7 @@ namespace Tgstation.Server.Host.IO.Tests var resultSequence = buffer.ToArray(); Assert.IsTrue(sequence.SequenceEqual(resultSequence)); - - mockHttpClient.VerifyAll(); + Assert.IsTrue(ran); } [TestMethod] @@ -64,20 +66,23 @@ namespace Tgstation.Server.Host.IO.Tests { var sequence = new byte[] { 1, 2, 3 }; var resultMs = new MemoryStream(sequence); - var mockHttpClient = new Mock(); var response = new HttpResponseMessage() { Content = new StreamContent(resultMs), }; + int ran = 0; var request = new HttpRequestMessage(); - mockHttpClient - .Setup(x => x.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, It.IsAny())) - .Returns(Task.FromResult(response)) - .Verifiable(); + var mockHttpClient = new HttpClient( + new MockHttpMessageHandler( + (_, _) => + { + ++ran; + return Task.FromResult(response); + })); - await using var downloader = new RequestFileStreamProvider(mockHttpClient.Object, request); + await using var downloader = new RequestFileStreamProvider(mockHttpClient, request); var task1 = downloader.GetResult(default); var task2 = downloader.GetResult(default); @@ -93,15 +98,13 @@ namespace Tgstation.Server.Host.IO.Tests Assert.AreSame(task1Result, await task2); Assert.AreSame(task1Result, await task3); - mockHttpClient.VerifyAll(); - Assert.AreEqual(1, mockHttpClient.Invocations.Count); + Assert.AreEqual(1, ran); } [TestMethod] public async Task TestInterruptedDownload() { var resultMs = new MemoryStream(); - var mockHttpClient = new Mock(); var response = new HttpResponseMessage() { @@ -110,17 +113,17 @@ namespace Tgstation.Server.Host.IO.Tests var tcs = new TaskCompletionSource(); + var ran = false; var request = new HttpRequestMessage(); - mockHttpClient - .Setup(x => x.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, It.IsAny())) - .Returns((request, option, cancellationToken) => - { - cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken)); - return tcs.Task; - }) - .Verifiable(); + var mockHttpClient = new HttpClient( + new MockHttpMessageHandler( + (_, _) => + { + ran = true; + return Task.FromResult(response); + })); - await using var downloader = new RequestFileStreamProvider(mockHttpClient.Object, request); + await using var downloader = new RequestFileStreamProvider(mockHttpClient, request); using var cts1 = new CancellationTokenSource(); var task1 = downloader.GetResult(cts1.Token); @@ -133,11 +136,11 @@ namespace Tgstation.Server.Host.IO.Tests cts2.Cancel(); - await Assert.ThrowsExceptionAsync(() => task1.AsTask()); - await Assert.ThrowsExceptionAsync(() => task2.AsTask()); - await Assert.ThrowsExceptionAsync(() => task3.AsTask()); + await Assert.ThrowsExceptionAsync(task1.AsTask); + await Assert.ThrowsExceptionAsync(task2.AsTask); + await Assert.ThrowsExceptionAsync(task3.AsTask); - mockHttpClient.VerifyAll(); + Assert.IsTrue(ran); } } } diff --git a/tests/Tgstation.Server.Host.Tests/Swarm/SwarmRpcMapper.cs b/tests/Tgstation.Server.Host.Tests/Swarm/SwarmRpcMapper.cs index cb48282fd2..6135e988c2 100644 --- a/tests/Tgstation.Server.Host.Tests/Swarm/SwarmRpcMapper.cs +++ b/tests/Tgstation.Server.Host.Tests/Swarm/SwarmRpcMapper.cs @@ -21,7 +21,7 @@ using Moq; using Newtonsoft.Json; -using Tgstation.Server.Common.Http; +using Tgstation.Server.Common.Tests; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Controllers; using Tgstation.Server.Host.Controllers.Results; @@ -41,12 +41,10 @@ namespace Tgstation.Server.Host.Swarm.Tests int serverErrorCount; - public SwarmRpcMapper(Func createSwarmController, Mock clientMock, ILogger logger) + public SwarmRpcMapper(Func createSwarmController, ILogger logger, out HttpMessageHandler handlerMock) { this.createSwarmController = createSwarmController; - clientMock - .Setup(x => x.SendAsync(It.IsNotNull(), It.IsAny(), It.IsAny())) - .Returns(MapRequest); + handlerMock = new MockHttpMessageHandler(MapRequest); this.logger = logger; AsyncRequests = true; } @@ -63,7 +61,6 @@ namespace Tgstation.Server.Host.Swarm.Tests async Task MapRequest( HttpRequestMessage request, - HttpCompletionOption httpCompletionOption, CancellationToken cancellationToken) { var (config, transferService, node) = configToNodes.FirstOrDefault( diff --git a/tests/Tgstation.Server.Host.Tests/Swarm/TestableSwarmNode.cs b/tests/Tgstation.Server.Host.Tests/Swarm/TestableSwarmNode.cs index 9b3e925536..bcd2a1f56e 100644 --- a/tests/Tgstation.Server.Host.Tests/Swarm/TestableSwarmNode.cs +++ b/tests/Tgstation.Server.Host.Tests/Swarm/TestableSwarmNode.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Reflection; using System.Threading; using System.Threading.Tasks; @@ -50,7 +51,6 @@ namespace Tgstation.Server.Host.Swarm.Tests public bool Shutdown { get; private set; } - readonly Mock mockHttpClient; readonly Mock mockDBContextFactory; readonly Mock mockDatabaseSeeder; readonly ISetup mockDatabaseSeederInitialize; @@ -121,10 +121,6 @@ namespace Tgstation.Server.Host.Swarm.Tests .Setup(x => x.UseContextTaskReturn(It.IsNotNull>())) .Callback>((func) => func(mockDatabaseContext)); - var mockHttpClientFactory = new Mock(); - mockHttpClient = new Mock(); - mockHttpClientFactory.Setup(x => x.CreateClient()).Returns(mockHttpClient.Object); - var mockAsyncDelayer = new Mock(); mockAsyncDelayer.Setup( x => x.Delay(It.IsAny(), It.IsAny())) @@ -161,8 +157,8 @@ namespace Tgstation.Server.Host.Swarm.Tests targetTransfer, mockOptions.Object, loggerFactory.CreateLogger()), - mockHttpClient, - loggerFactory.CreateLogger($"SwarmRpcMapper-{swarmConfiguration.Identifier}")); + loggerFactory.CreateLogger($"SwarmRpcMapper-{swarmConfiguration.Identifier}"), + out var mockMessageHandler); mockServerUpdater .Setup(x => x.BeginUpdate(It.IsNotNull(), It.IsAny(), It.IsNotNull(), It.IsAny())) @@ -175,6 +171,9 @@ namespace Tgstation.Server.Host.Swarm.Tests var mockTokenFactory = new MockTokenFactory(); + var mockHttpClientFactory = new Mock(); + mockHttpClientFactory.Setup(x => x.CreateClient(String.Empty)).Returns(() => new HttpClient(mockMessageHandler)); + var runCount = 0; void RecreateControllerAndService() { diff --git a/tests/Tgstation.Server.Host.Tests/Tgstation.Server.Host.Tests.csproj b/tests/Tgstation.Server.Host.Tests/Tgstation.Server.Host.Tests.csproj index 2b96d6fd6a..b8509b165e 100644 --- a/tests/Tgstation.Server.Host.Tests/Tgstation.Server.Host.Tests.csproj +++ b/tests/Tgstation.Server.Host.Tests/Tgstation.Server.Host.Tests.csproj @@ -14,6 +14,7 @@ + diff --git a/tests/Tgstation.Server.Tests/CachingFileDownloader.cs b/tests/Tgstation.Server.Tests/CachingFileDownloader.cs index 16dce2af75..6e058f581d 100644 --- a/tests/Tgstation.Server.Tests/CachingFileDownloader.cs +++ b/tests/Tgstation.Server.Tests/CachingFileDownloader.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.IO.Abstractions; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; @@ -174,16 +175,26 @@ namespace Tgstation.Server.Tests public IFileStreamProvider DownloadFile(Uri url, string bearerToken) => new ProviderPackage(logger, url, bearerToken); - static FileDownloader CreateRealDownloader(ILogger logger) - => new( - new HttpClientFactory( - new AssemblyInformationProvider().ProductInfoHeaderValue), + public static FileDownloader CreateRealDownloader(ILogger logger) + { + var mockHttpClientFactory = new Mock(); + mockHttpClientFactory.Setup(x => x.CreateClient(String.Empty)).Returns( + () => + { + var client = new HttpClient(); + client.DefaultRequestHeaders.UserAgent.Add(new AssemblyInformationProvider().ProductInfoHeaderValue); + return client; + }); + + return new ( + mockHttpClientFactory.Object, logger != null ? new Logger( TestingUtils.CreateLoggerFactoryForLogger( logger, out _)) : Mock.Of>()); + } static async Task CacheFile(ILogger logger, Uri url, string bearerToken, string path, CancellationToken cancellationToken) { diff --git a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs index 5fd65574eb..ab94a4b8cc 100644 --- a/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs +++ b/tests/Tgstation.Server.Tests/Live/Instance/InstanceTest.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO.Abstractions; using System.Linq; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; @@ -16,7 +17,6 @@ using Tgstation.Server.Api.Models.Request; using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Client; using Tgstation.Server.Client.Components; -using Tgstation.Server.Common.Http; using Tgstation.Server.Host.Components; using Tgstation.Server.Host.Components.Engine; using Tgstation.Server.Host.Components.Events; @@ -126,7 +126,7 @@ namespace Tgstation.Server.Tests.Live.Instance Mock.Of>(), genConfig), Mock.Of(), - Mock.Of(), + Mock.Of(), Options.Create(genConfig), Options.Create(new SessionConfiguration())) : new PlatformIdentifier().IsWindows diff --git a/tests/Tgstation.Server.Tests/Live/RateLimitRetryingApiClient.cs b/tests/Tgstation.Server.Tests/Live/RateLimitRetryingApiClient.cs index a487a91991..7eda5965fb 100644 --- a/tests/Tgstation.Server.Tests/Live/RateLimitRetryingApiClient.cs +++ b/tests/Tgstation.Server.Tests/Live/RateLimitRetryingApiClient.cs @@ -14,7 +14,7 @@ namespace Tgstation.Server.Tests.Live sealed class RateLimitRetryingApiClient : ApiClient { public RateLimitRetryingApiClient( - IHttpClient httpClient, + HttpClient httpClient, Uri url, ApiHeaders apiHeaders, ApiHeaders tokenRefreshHeaders, diff --git a/tests/Tgstation.Server.Tests/Live/RateLimitRetryingApiClientFactory.cs b/tests/Tgstation.Server.Tests/Live/RateLimitRetryingApiClientFactory.cs index f9ba45e66e..3fea762930 100644 --- a/tests/Tgstation.Server.Tests/Live/RateLimitRetryingApiClientFactory.cs +++ b/tests/Tgstation.Server.Tests/Live/RateLimitRetryingApiClientFactory.cs @@ -1,9 +1,8 @@ using System; +using System.Net.Http; using Tgstation.Server.Api; -using Tgstation.Server.Api.Models.Response; using Tgstation.Server.Client; -using Tgstation.Server.Common.Http; namespace Tgstation.Server.Tests.Live { @@ -20,5 +19,19 @@ namespace Tgstation.Server.Tests.Live apiHeaders, tokenRefreshHeaders, authless); + + /// + public IApiClient CreateApiClient( + Uri url, + ApiHeaders apiHeaders, + ApiHeaders tokenRefreshHeaders, + HttpMessageHandler handler, + bool disposeHandler, + bool authless) => new RateLimitRetryingApiClient( + new HttpClient(handler, disposeHandler), + url, + apiHeaders, + tokenRefreshHeaders, + authless); } } diff --git a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs index 8d2222c9fa..9bcf766788 100644 --- a/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs +++ b/tests/Tgstation.Server.Tests/Live/TestLiveServer.cs @@ -409,10 +409,7 @@ namespace Tgstation.Server.Tests.Live await CheckUpdate(); // Second pass, uploaded updates - var downloader = new Host.IO.FileDownloader( - new Common.Http.HttpClientFactory( - new AssemblyInformationProvider().ProductInfoHeaderValue), - Mock.Of>()); + var downloader = CachingFileDownloader.CreateRealDownloader(Mock.Of>()); var gitHubToken = Environment.GetEnvironmentVariable("TGS_TEST_GITHUB_TOKEN"); if (String.IsNullOrWhiteSpace(gitHubToken)) gitHubToken = null; @@ -828,10 +825,7 @@ namespace Tgstation.Server.Tests.Live CheckInfo(node2Info2); // also test with uploaded updates this time - var downloader = new Host.IO.FileDownloader( - new Common.Http.HttpClientFactory( - new AssemblyInformationProvider().ProductInfoHeaderValue), - Mock.Of>()); + var downloader = CachingFileDownloader.CreateRealDownloader(Mock.Of>()); var gitHubToken = Environment.GetEnvironmentVariable("TGS_TEST_GITHUB_TOKEN"); if (String.IsNullOrWhiteSpace(gitHubToken)) gitHubToken = null; diff --git a/tgstation-server.sln b/tgstation-server.sln index 165ed3cac8..b5233ded86 100644 --- a/tgstation-server.sln +++ b/tgstation-server.sln @@ -277,6 +277,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nix", "nix", "{5130526C-A55 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tgstation.Server.Host.Utils.GitLab.GraphQL", "src\Tgstation.Server.Host.Utils.GitLab.GraphQL\Tgstation.Server.Host.Utils.GitLab.GraphQL.csproj", "{BF02BCC5-735C-4FF1-8EEF-FF78EA42FC85}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tgstation.Server.Common.Tests", "tests\Tgstation.Server.Common.Tests\Tgstation.Server.Common.Tests.csproj", "{73F2C6B9-54A6-4433-9D94-07F2AC0FD084}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -571,6 +573,18 @@ Global {BF02BCC5-735C-4FF1-8EEF-FF78EA42FC85}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU {BF02BCC5-735C-4FF1-8EEF-FF78EA42FC85}.ReleaseNoWix|Any CPU.ActiveCfg = Release|Any CPU {BF02BCC5-735C-4FF1-8EEF-FF78EA42FC85}.ReleaseNoWix|Any CPU.Build.0 = Release|Any CPU + {73F2C6B9-54A6-4433-9D94-07F2AC0FD084}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {73F2C6B9-54A6-4433-9D94-07F2AC0FD084}.Debug|Any CPU.Build.0 = Debug|Any CPU + {73F2C6B9-54A6-4433-9D94-07F2AC0FD084}.DebugNoWindows|Any CPU.ActiveCfg = Debug|Any CPU + {73F2C6B9-54A6-4433-9D94-07F2AC0FD084}.DebugNoWindows|Any CPU.Build.0 = Debug|Any CPU + {73F2C6B9-54A6-4433-9D94-07F2AC0FD084}.DebugNoWix|Any CPU.ActiveCfg = Debug|Any CPU + {73F2C6B9-54A6-4433-9D94-07F2AC0FD084}.DebugNoWix|Any CPU.Build.0 = Debug|Any CPU + {73F2C6B9-54A6-4433-9D94-07F2AC0FD084}.Release|Any CPU.ActiveCfg = Release|Any CPU + {73F2C6B9-54A6-4433-9D94-07F2AC0FD084}.Release|Any CPU.Build.0 = Release|Any CPU + {73F2C6B9-54A6-4433-9D94-07F2AC0FD084}.ReleaseNoWindows|Any CPU.ActiveCfg = Release|Any CPU + {73F2C6B9-54A6-4433-9D94-07F2AC0FD084}.ReleaseNoWindows|Any CPU.Build.0 = Release|Any CPU + {73F2C6B9-54A6-4433-9D94-07F2AC0FD084}.ReleaseNoWix|Any CPU.ActiveCfg = Release|Any CPU + {73F2C6B9-54A6-4433-9D94-07F2AC0FD084}.ReleaseNoWix|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -609,6 +623,7 @@ Global {7F7FCFDF-271D-45C2-830C-BCCB19C57077} = {A55C1117-5808-4AB2-BEA6-4D4A3E66A2F2} {EAB84FD0-5514-4254-B188-7D90ACB7284D} = {316141B0-CD21-4769-A013-D53DA9B9EC09} {5130526C-A553-493B-A9B0-3DB452949886} = {2648A85F-61AE-428E-95E1-66D06C7A3768} + {73F2C6B9-54A6-4433-9D94-07F2AC0FD084} = {316141B0-CD21-4769-A013-D53DA9B9EC09} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {DFD36C95-3E49-41C7-ACDB-86BAF5B18A79}