mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-24 13:36:50 +01:00
Remove HttpClient abstractions
Now implement mocked `HttpMessageHandler`s as recommended: https://stackoverflow.com/a/36427274/3976486
This commit is contained in:
@@ -69,9 +69,9 @@ namespace Tgstation.Server.Client
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IHttpClient"/> for the <see cref="ApiClient"/>.
|
||||
/// The <see cref="HttpClient"/> for the <see cref="ApiClient"/>.
|
||||
/// </summary>
|
||||
readonly IHttpClient httpClient;
|
||||
readonly HttpClient httpClient;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IRequestLogger"/>s used by the <see cref="ApiClient"/>.
|
||||
@@ -166,7 +166,7 @@ namespace Tgstation.Server.Client
|
||||
/// <param name="tokenRefreshHeaders">The value of <see cref="tokenRefreshHeaders"/>.</param>
|
||||
/// <param name="authless">The value of <see cref="authless"/>.</param>
|
||||
public ApiClient(
|
||||
IHttpClient httpClient,
|
||||
HttpClient httpClient,
|
||||
Uri url,
|
||||
ApiHeaders apiHeaders,
|
||||
ApiHeaders? tokenRefreshHeaders,
|
||||
|
||||
@@ -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);
|
||||
|
||||
/// <inheritdoc />
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
/// <summary>
|
||||
/// Create an <see cref="IApiClient"/>.
|
||||
/// </summary>
|
||||
/// <param name="url">The base <see cref="Uri"/>.</param>
|
||||
/// <param name="apiHeaders">The <see cref="ApiHeaders"/> for the <see cref="IApiClient"/>.</param>
|
||||
/// <param name="tokenRefreshHeaders">The <see cref="ApiHeaders"/> to use to generate a new <see cref="Api.Models.Response.TokenResponse"/>.</param>
|
||||
/// <param name="handler">The <see cref="HttpMessageHandler"/> to use with the internal <see cref="HttpClient"/>.</param>
|
||||
/// <param name="disposeHandler">If <paramref name="handler"/> should be disposed with the created <see cref="IApiClient"/>.</param>
|
||||
/// <param name="authless">If there should be no authentication performed.</param>
|
||||
/// <returns>A new <see cref="IApiClient"/>.</returns>
|
||||
public IApiClient CreateApiClient(
|
||||
Uri url,
|
||||
ApiHeaders apiHeaders,
|
||||
ApiHeaders? tokenRefreshHeaders,
|
||||
HttpMessageHandler handler,
|
||||
bool disposeHandler,
|
||||
bool authless);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public sealed class HttpClient : IHttpClient
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public TimeSpan Timeout
|
||||
{
|
||||
get => httpClient.Timeout;
|
||||
set => httpClient.Timeout = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public HttpRequestHeaders DefaultRequestHeaders => httpClient.DefaultRequestHeaders;
|
||||
|
||||
/// <summary>
|
||||
/// The real <see cref="System.Net.Http.HttpClient"/>.
|
||||
/// </summary>
|
||||
readonly System.Net.Http.HttpClient httpClient;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HttpClient"/> class.
|
||||
/// </summary>
|
||||
/// <param name="implementation">The <see cref="System.Net.Http.HttpClient"/> to wrap.</param>
|
||||
public HttpClient(System.Net.Http.HttpClient implementation)
|
||||
{
|
||||
httpClient = implementation ?? throw new ArgumentNullException(nameof(implementation));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HttpClient"/> class.
|
||||
/// </summary>
|
||||
public HttpClient()
|
||||
: this(new System.Net.Http.HttpClient())
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose() => httpClient.Dispose();
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)
|
||||
=> httpClient.SendAsync(request, completionOption, cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
using System;
|
||||
using System.Net.Http.Headers;
|
||||
|
||||
namespace Tgstation.Server.Common.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="IAbstractHttpClientFactory"/> that creates <see cref="HttpClient"/>s.
|
||||
/// </summary>
|
||||
public sealed class HttpClientFactory : IAbstractHttpClientFactory
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public IHttpClient CreateClient()
|
||||
{
|
||||
var client = new HttpClient();
|
||||
try
|
||||
{
|
||||
client.DefaultRequestHeaders.UserAgent.Add(userAgent);
|
||||
return client;
|
||||
}
|
||||
catch
|
||||
{
|
||||
client.Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ProductInfoHeaderValue"/> used as created client's User-Agent header on request.
|
||||
/// </summary>
|
||||
readonly ProductInfoHeaderValue userAgent;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HttpClientFactory"/> class.
|
||||
/// </summary>
|
||||
/// <param name="userAgent">The value of <see cref="userAgent"/>.</param>
|
||||
public HttpClientFactory(ProductInfoHeaderValue userAgent)
|
||||
{
|
||||
this.userAgent = userAgent ?? throw new ArgumentNullException(nameof(userAgent));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
namespace Tgstation.Server.Common.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates <see cref="IHttpClient"/>s.
|
||||
/// </summary>
|
||||
public interface IAbstractHttpClientFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a <see cref="IHttpClient"/>.
|
||||
/// </summary>
|
||||
/// <returns>A new <see cref="IHttpClient"/>.</returns>
|
||||
IHttpClient CreateClient();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// For sending HTTP requests.
|
||||
/// </summary>
|
||||
public interface IHttpClient : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// The request timeout.
|
||||
/// </summary>
|
||||
TimeSpan Timeout { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="HttpRequestHeaders"/> used on every request.
|
||||
/// </summary>
|
||||
HttpRequestHeaders DefaultRequestHeaders { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Send an HTTP request.
|
||||
/// </summary>
|
||||
/// <param name="request">The <see cref="HttpRequestMessage"/>.</param>
|
||||
/// <param name="completionOption">The <see cref="HttpCompletionOption"/>.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> resulting in the <see cref="HttpResponseMessage"/> of the request.</returns>
|
||||
Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IAbstractHttpClientFactory"/> for the <see cref="OpenDreamInstallation"/>.
|
||||
/// The <see cref="IHttpClientFactory"/> for the <see cref="OpenDreamInstallation"/>.
|
||||
/// </summary>
|
||||
readonly IAbstractHttpClientFactory httpClientFactory;
|
||||
readonly IHttpClientFactory httpClientFactory;
|
||||
|
||||
/// <summary>
|
||||
/// 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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IAbstractHttpClientFactory"/> for the <see cref="OpenDreamInstaller"/>.
|
||||
/// The <see cref="IHttpClientFactory"/> for the <see cref="OpenDreamInstaller"/>.
|
||||
/// </summary>
|
||||
readonly IAbstractHttpClientFactory httpClientFactory;
|
||||
readonly IHttpClientFactory httpClientFactory;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="OpenDreamInstaller"/> class.
|
||||
@@ -100,7 +100,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
IProcessExecutor processExecutor,
|
||||
IRepositoryManager repositoryManager,
|
||||
IAsyncDelayer asyncDelayer,
|
||||
IAbstractHttpClientFactory httpClientFactory,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
IOptions<GeneralConfiguration> generalConfigurationOptions,
|
||||
IOptions<SessionConfiguration> sessionConfigurationOptions)
|
||||
: base(ioManager, logger)
|
||||
|
||||
@@ -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
|
||||
/// <param name="processExecutor">The <see cref="IProcessExecutor"/> for the <see cref="OpenDreamInstaller"/>.</param>
|
||||
/// <param name="repositoryManager">The <see cref="IRepositoryManager"/> for the <see cref="OpenDreamInstaller"/>.</param>
|
||||
/// <param name="asyncDelayer">The <see cref="IAsyncDelayer"/> for the <see cref="OpenDreamInstaller"/>.</param>
|
||||
/// <param name="httpClientFactory">The <see cref="IAbstractHttpClientFactory"/> for the <see cref="OpenDreamInstaller"/>.</param>
|
||||
/// <param name="httpClientFactory">The <see cref="IHttpClientFactory"/> for the <see cref="OpenDreamInstaller"/>.</param>
|
||||
/// <param name="generalConfigurationOptions">The <see cref="IOptions{TOptions}"/> of <see cref="GeneralConfiguration"/> for the <see cref="OpenDreamInstaller"/>.</param>
|
||||
/// <param name="sessionConfigurationOptions">The <see cref="IOptions{TOptions}"/> of <see cref="SessionConfiguration"/> for the <see cref="OpenDreamInstaller"/>.</param>
|
||||
/// <param name="linkFactory">The value of <see cref="linkFactory"/>.</param>
|
||||
@@ -47,7 +47,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
IProcessExecutor processExecutor,
|
||||
IRepositoryManager repositoryManager,
|
||||
IAsyncDelayer asyncDelayer,
|
||||
IAbstractHttpClientFactory httpClientFactory,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
IOptions<GeneralConfiguration> generalConfigurationOptions,
|
||||
IOptions<SessionConfiguration> sessionConfigurationOptions,
|
||||
IFilesystemLinkFactory linkFactory)
|
||||
|
||||
@@ -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<IAbstractHttpClientFactory, AbstractHttpClientFactory>();
|
||||
services
|
||||
.AddHttpClient()
|
||||
.ConfigureHttpClientDefaults(
|
||||
builder => builder.ConfigureHttpClient(
|
||||
client => client.DefaultRequestHeaders.UserAgent.Add(
|
||||
assemblyInformationProvider.ProductInfoHeaderValue)));
|
||||
|
||||
// configure metrics
|
||||
var prometheusPort = postSetupServices.GeneralConfiguration.PrometheusPort;
|
||||
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="IAbstractHttpClientFactory"/> for the <see cref="FileDownloader"/>.
|
||||
/// The <see cref="IHttpClientFactory"/> for the <see cref="FileDownloader"/>.
|
||||
/// </summary>
|
||||
readonly IAbstractHttpClientFactory httpClientFactory;
|
||||
readonly IHttpClientFactory httpClientFactory;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ILogger"/> for the <see cref="FileDownloader"/>.
|
||||
@@ -27,7 +26,7 @@ namespace Tgstation.Server.Host.IO
|
||||
/// </summary>
|
||||
/// <param name="httpClientFactory">The value of <see cref="httpClientFactory"/>.</param>
|
||||
/// <param name="logger">The value of <see cref="logger"/>.</param>
|
||||
public FileDownloader(IAbstractHttpClientFactory httpClientFactory, ILogger<FileDownloader> logger)
|
||||
public FileDownloader(IHttpClientFactory httpClientFactory, ILogger<FileDownloader> logger)
|
||||
{
|
||||
this.httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));
|
||||
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
|
||||
@@ -14,9 +14,9 @@ namespace Tgstation.Server.Host.IO
|
||||
sealed class RequestFileStreamProvider : IFileStreamProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="IHttpClient"/> for the <see cref="RequestFileStreamProvider"/>.
|
||||
/// The <see cref="HttpClient"/> for the <see cref="RequestFileStreamProvider"/>.
|
||||
/// </summary>
|
||||
readonly IHttpClient httpClient;
|
||||
readonly HttpClient httpClient;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IFileDownloader"/> for the <see cref="RequestFileStreamProvider"/>.
|
||||
@@ -43,7 +43,7 @@ namespace Tgstation.Server.Host.IO
|
||||
/// </summary>
|
||||
/// <param name="httpClient">The value of <see cref="httpClient"/>.</param>
|
||||
/// <param name="requestMessage">The value of <see cref="requestMessage"/>.</param>
|
||||
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));
|
||||
|
||||
@@ -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
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DiscordOAuthValidator"/> class.
|
||||
/// </summary>
|
||||
/// <param name="httpClientFactory">The <see cref="IAbstractHttpClientFactory"/> for the <see cref="GenericOAuthValidator"/>.</param>
|
||||
/// <param name="httpClientFactory">The <see cref="IHttpClientFactory"/> for the <see cref="GenericOAuthValidator"/>.</param>
|
||||
/// <param name="logger">The <see cref="ILogger"/> for the <see cref="GenericOAuthValidator"/>.</param>
|
||||
/// <param name="oAuthConfiguration">The <see cref="OAuthConfiguration"/> for the <see cref="GenericOAuthValidator"/>.</param>
|
||||
public DiscordOAuthValidator(
|
||||
IAbstractHttpClientFactory httpClientFactory,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
ILogger<DiscordOAuthValidator> logger,
|
||||
OAuthConfiguration oAuthConfiguration)
|
||||
: base(httpClientFactory, logger, oAuthConfiguration)
|
||||
|
||||
@@ -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
|
||||
/// <summary>
|
||||
/// The <see cref="IHttpClientFactory"/> for the <see cref="GenericOAuthValidator"/>.
|
||||
/// </summary>
|
||||
readonly IAbstractHttpClientFactory httpClientFactory;
|
||||
readonly IHttpClientFactory httpClientFactory;
|
||||
|
||||
/// <summary>
|
||||
/// Gets <see cref="JsonSerializerSettings"/> that should be used.
|
||||
@@ -74,7 +73,7 @@ namespace Tgstation.Server.Host.Security.OAuth
|
||||
/// <param name="logger">The value of <see cref="Logger"/>.</param>
|
||||
/// <param name="oAuthConfiguration">The value of <see cref="OAuthConfiguration"/>.</param>
|
||||
public GenericOAuthValidator(
|
||||
IAbstractHttpClientFactory httpClientFactory,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
ILogger<GenericOAuthValidator> logger,
|
||||
OAuthConfiguration oAuthConfiguration)
|
||||
{
|
||||
@@ -178,10 +177,10 @@ namespace Tgstation.Server.Host.Security.OAuth
|
||||
protected abstract OAuthTokenRequest CreateTokenRequest(string code);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new configured <see cref="IHttpClient"/>.
|
||||
/// Create a new configured <see cref="HttpClient"/>.
|
||||
/// </summary>
|
||||
/// <returns>A new configured <see cref="IHttpClient"/>.</returns>
|
||||
IHttpClient CreateHttpClient()
|
||||
/// <returns>A new configured <see cref="HttpClient"/>.</returns>
|
||||
HttpClient CreateHttpClient()
|
||||
{
|
||||
var httpClient = httpClientFactory.CreateClient();
|
||||
try
|
||||
|
||||
@@ -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
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InvisionCommunityOAuthValidator"/> class.
|
||||
/// </summary>
|
||||
/// <param name="httpClientFactory">The <see cref="IAbstractHttpClientFactory"/> for the <see cref="GenericOAuthValidator"/>.</param>
|
||||
/// <param name="httpClientFactory">The <see cref="IHttpClientFactory"/> for the <see cref="GenericOAuthValidator"/>.</param>
|
||||
/// <param name="logger">The <see cref="ILogger"/> for the <see cref="GenericOAuthValidator"/>.</param>
|
||||
/// <param name="oAuthConfiguration">The <see cref="OAuthConfiguration"/> for the <see cref="GenericOAuthValidator"/>.</param>
|
||||
public InvisionCommunityOAuthValidator(
|
||||
IAbstractHttpClientFactory httpClientFactory,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
ILogger<InvisionCommunityOAuthValidator> logger,
|
||||
OAuthConfiguration oAuthConfiguration)
|
||||
: base(httpClientFactory, logger, oAuthConfiguration)
|
||||
|
||||
@@ -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
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="KeycloakOAuthValidator"/> class.
|
||||
/// </summary>
|
||||
/// <param name="httpClientFactory">The <see cref="IAbstractHttpClientFactory"/> for the <see cref="GenericOAuthValidator"/>.</param>
|
||||
/// <param name="httpClientFactory">The <see cref="IHttpClientFactory"/> for the <see cref="GenericOAuthValidator"/>.</param>
|
||||
/// <param name="logger">The <see cref="ILogger"/> for the <see cref="GenericOAuthValidator"/>.</param>
|
||||
/// <param name="oAuthConfiguration">The <see cref="OAuthConfiguration"/> for the <see cref="GenericOAuthValidator"/>.</param>
|
||||
public KeycloakOAuthValidator(
|
||||
IAbstractHttpClientFactory httpClientFactory,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
ILogger<KeycloakOAuthValidator> logger,
|
||||
OAuthConfiguration oAuthConfiguration)
|
||||
: base(httpClientFactory, logger, oAuthConfiguration)
|
||||
|
||||
@@ -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 <see cref="OAuthProviders"/> class.
|
||||
/// </summary>
|
||||
/// <param name="gitHubServiceFactory">The <see cref="IGitHubServiceFactory"/> to use.</param>
|
||||
/// <param name="httpClientFactory">The <see cref="IAbstractHttpClientFactory"/> to use.</param>
|
||||
/// <param name="httpClientFactory">The <see cref="IHttpClientFactory"/> to use.</param>
|
||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/> to use.</param>
|
||||
/// <param name="securityConfigurationOptions">The <see cref="IOptions{TOptions}"/> containing the <see cref="SecurityConfiguration"/> to use.</param>
|
||||
public OAuthProviders(
|
||||
IGitHubServiceFactory gitHubServiceFactory,
|
||||
IAbstractHttpClientFactory httpClientFactory,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
ILoggerFactory loggerFactory,
|
||||
IOptions<SecurityConfiguration> securityConfigurationOptions)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IAbstractHttpClientFactory"/> for the <see cref="SwarmService"/>.
|
||||
/// The <see cref="IHttpClientFactory"/> for the <see cref="SwarmService"/>.
|
||||
/// </summary>
|
||||
readonly IAbstractHttpClientFactory httpClientFactory;
|
||||
readonly IHttpClientFactory httpClientFactory;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IAsyncDelayer"/> for the <see cref="SwarmService"/>.
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
{
|
||||
/// <inheritdoc />
|
||||
sealed class AbstractHttpClientFactory : IAbstractHttpClientFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// The real <see cref="IHttpClientFactory"/>.
|
||||
/// </summary>
|
||||
readonly IHttpClientFactory httpClientFactory;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IAssemblyInformationProvider"/> for the <see cref="AbstractHttpClientFactory"/>.
|
||||
/// </summary>
|
||||
readonly IAssemblyInformationProvider assemblyInformationProvider;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ILogger"/> for the <see cref="AbstractHttpClientFactory"/>.
|
||||
/// </summary>
|
||||
readonly ILogger<AbstractHttpClientFactory> logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AbstractHttpClientFactory"/> class.
|
||||
/// </summary>
|
||||
/// <param name="httpClientFactory">The value of <see cref="httpClientFactory"/>.</param>
|
||||
/// <param name="assemblyInformationProvider">The value of <see cref="assemblyInformationProvider"/>.</param>
|
||||
/// <param name="logger">The value of <see cref="logger"/>.</param>
|
||||
public AbstractHttpClientFactory(
|
||||
IHttpClientFactory httpClientFactory,
|
||||
IAssemblyInformationProvider assemblyInformationProvider,
|
||||
ILogger<AbstractHttpClientFactory> 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));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
#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
|
||||
}
|
||||
}
|
||||
@@ -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<IHttpClient>();
|
||||
httpClient.Setup(x => x.SendAsync(It.IsNotNull<HttpRequestMessage>(), It.IsAny<HttpCompletionOption>(), It.IsAny<CancellationToken>())).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<IHttpClient>();
|
||||
httpClient.Setup(x => x.SendAsync(It.IsNotNull<HttpRequestMessage>(), It.IsAny<HttpCompletionOption>(), It.IsAny<CancellationToken>())).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"),
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Tgstation.Server.Client\Tgstation.Server.Client.csproj" />
|
||||
<ProjectReference Include="..\Tgstation.Server.Common.Tests\Tgstation.Server.Common.Tests.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace Tgstation.Server.Common.Extensions.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests for <see cref="VersionExtensions"/>.
|
||||
/// </summary>
|
||||
[TestClass]
|
||||
public sealed class TestVersionExtensions
|
||||
{
|
||||
[TestMethod]
|
||||
public void TestSemver()
|
||||
{
|
||||
Assert.AreEqual(new Version(1, 2, 3), new Version(1, 2, 3, 4).Semver());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Tgstation.Server.Common.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Simple mock <see cref="HttpMessageHandler"/>.
|
||||
/// </summary>
|
||||
public sealed class MockHttpMessageHandler : HttpMessageHandler
|
||||
{
|
||||
readonly Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> callback;
|
||||
|
||||
public MockHttpMessageHandler(Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> callback)
|
||||
{
|
||||
this.callback = callback ?? throw new ArgumentNullException(nameof(callback));
|
||||
}
|
||||
|
||||
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
=> callback(request, cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="../../build/TestCommon.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>$(TgsFrameworkVersion)</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Tgstation.Server.Common\Tgstation.Server.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -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<IProcessExecutor>(),
|
||||
mockRepositoryManager.Object,
|
||||
Mock.Of<IAsyncDelayer>(),
|
||||
Mock.Of<IAbstractHttpClientFactory>(),
|
||||
Mock.Of<IHttpClientFactory>(),
|
||||
mockGeneralConfigOptions.Object,
|
||||
mockSessionConfigOptions.Object);
|
||||
|
||||
|
||||
@@ -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<ArgumentNullException>(() => new FileDownloader(null, null));
|
||||
Assert.ThrowsException<ArgumentNullException>(() => new FileDownloader(Mock.Of<IAbstractHttpClientFactory>(), null));
|
||||
_ = new FileDownloader(Mock.Of<IAbstractHttpClientFactory>(), Mock.Of<ILogger<FileDownloader>>());
|
||||
Assert.ThrowsException<ArgumentNullException>(() => new FileDownloader(Mock.Of<IHttpClientFactory>(), null));
|
||||
_ = new FileDownloader(Mock.Of<IHttpClientFactory>(), Mock.Of<ILogger<FileDownloader>>());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@@ -65,11 +67,21 @@ Please see the following for more context:
|
||||
builder.SetMinimumLevel(LogLevel.Trace);
|
||||
});
|
||||
|
||||
var mockHttpClientFactory = new Mock<IHttpClientFactory>();
|
||||
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<FileDownloader>());
|
||||
}
|
||||
catch
|
||||
|
||||
@@ -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<ArgumentNullException>(() => new RequestFileStreamProvider(null, null));
|
||||
var mockClient = Mock.Of<IHttpClient>();
|
||||
var mockClient = new HttpClient();
|
||||
Assert.ThrowsException<ArgumentNullException>(() => 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<IHttpClient>();
|
||||
|
||||
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<CancellationToken>()))
|
||||
.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<IHttpClient>();
|
||||
|
||||
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<CancellationToken>()))
|
||||
.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<IHttpClient>();
|
||||
|
||||
var response = new HttpResponseMessage()
|
||||
{
|
||||
@@ -110,17 +113,17 @@ namespace Tgstation.Server.Host.IO.Tests
|
||||
|
||||
var tcs = new TaskCompletionSource<HttpResponseMessage>();
|
||||
|
||||
var ran = false;
|
||||
var request = new HttpRequestMessage();
|
||||
mockHttpClient
|
||||
.Setup(x => x.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, It.IsAny<CancellationToken>()))
|
||||
.Returns<HttpRequestMessage, HttpCompletionOption, CancellationToken>((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<TaskCanceledException>(() => task1.AsTask());
|
||||
await Assert.ThrowsExceptionAsync<TaskCanceledException>(() => task2.AsTask());
|
||||
await Assert.ThrowsExceptionAsync<TaskCanceledException>(() => task3.AsTask());
|
||||
await Assert.ThrowsExceptionAsync<TaskCanceledException>(task1.AsTask);
|
||||
await Assert.ThrowsExceptionAsync<TaskCanceledException>(task2.AsTask);
|
||||
await Assert.ThrowsExceptionAsync<TaskCanceledException>(task3.AsTask);
|
||||
|
||||
mockHttpClient.VerifyAll();
|
||||
Assert.IsTrue(ran);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<SwarmService, FileTransferService, SwarmController> createSwarmController, Mock<IHttpClient> clientMock, ILogger logger)
|
||||
public SwarmRpcMapper(Func<SwarmService, FileTransferService, SwarmController> createSwarmController, ILogger logger, out HttpMessageHandler handlerMock)
|
||||
{
|
||||
this.createSwarmController = createSwarmController;
|
||||
clientMock
|
||||
.Setup(x => x.SendAsync(It.IsNotNull<HttpRequestMessage>(), It.IsAny<HttpCompletionOption>(), It.IsAny<CancellationToken>()))
|
||||
.Returns(MapRequest);
|
||||
handlerMock = new MockHttpMessageHandler(MapRequest);
|
||||
this.logger = logger;
|
||||
AsyncRequests = true;
|
||||
}
|
||||
@@ -63,7 +61,6 @@ namespace Tgstation.Server.Host.Swarm.Tests
|
||||
|
||||
async Task<HttpResponseMessage> MapRequest(
|
||||
HttpRequestMessage request,
|
||||
HttpCompletionOption httpCompletionOption,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var (config, transferService, node) = configToNodes.FirstOrDefault(
|
||||
|
||||
@@ -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<IHttpClient> mockHttpClient;
|
||||
readonly Mock<IDatabaseContextFactory> mockDBContextFactory;
|
||||
readonly Mock<IDatabaseSeeder> mockDatabaseSeeder;
|
||||
readonly ISetup<IDatabaseSeeder, ValueTask> mockDatabaseSeederInitialize;
|
||||
@@ -121,10 +121,6 @@ namespace Tgstation.Server.Host.Swarm.Tests
|
||||
.Setup(x => x.UseContextTaskReturn(It.IsNotNull<Func<IDatabaseContext, Task>>()))
|
||||
.Callback<Func<IDatabaseContext, Task>>((func) => func(mockDatabaseContext));
|
||||
|
||||
var mockHttpClientFactory = new Mock<IAbstractHttpClientFactory>();
|
||||
mockHttpClient = new Mock<IHttpClient>();
|
||||
mockHttpClientFactory.Setup(x => x.CreateClient()).Returns(mockHttpClient.Object);
|
||||
|
||||
var mockAsyncDelayer = new Mock<IAsyncDelayer>();
|
||||
mockAsyncDelayer.Setup(
|
||||
x => x.Delay(It.IsAny<TimeSpan>(), It.IsAny<CancellationToken>()))
|
||||
@@ -161,8 +157,8 @@ namespace Tgstation.Server.Host.Swarm.Tests
|
||||
targetTransfer,
|
||||
mockOptions.Object,
|
||||
loggerFactory.CreateLogger<SwarmController>()),
|
||||
mockHttpClient,
|
||||
loggerFactory.CreateLogger($"SwarmRpcMapper-{swarmConfiguration.Identifier}"));
|
||||
loggerFactory.CreateLogger($"SwarmRpcMapper-{swarmConfiguration.Identifier}"),
|
||||
out var mockMessageHandler);
|
||||
|
||||
mockServerUpdater
|
||||
.Setup(x => x.BeginUpdate(It.IsNotNull<ISwarmService>(), It.IsAny<IFileStreamProvider>(), It.IsNotNull<Version>(), It.IsAny<CancellationToken>()))
|
||||
@@ -175,6 +171,9 @@ namespace Tgstation.Server.Host.Swarm.Tests
|
||||
|
||||
var mockTokenFactory = new MockTokenFactory();
|
||||
|
||||
var mockHttpClientFactory = new Mock<IHttpClientFactory>();
|
||||
mockHttpClientFactory.Setup(x => x.CreateClient(String.Empty)).Returns(() => new HttpClient(mockMessageHandler));
|
||||
|
||||
var runCount = 0;
|
||||
void RecreateControllerAndService()
|
||||
{
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Tgstation.Server.Host\Tgstation.Server.Host.csproj" />
|
||||
<ProjectReference Include="..\Tgstation.Server.Common.Tests\Tgstation.Server.Common.Tests.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -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<IHttpClientFactory>();
|
||||
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<FileDownloader>(
|
||||
TestingUtils.CreateLoggerFactoryForLogger(
|
||||
logger,
|
||||
out _))
|
||||
: Mock.Of<ILogger<FileDownloader>>());
|
||||
}
|
||||
|
||||
static async Task<MemoryStream> CacheFile(ILogger logger, Uri url, string bearerToken, string path, CancellationToken cancellationToken)
|
||||
{
|
||||
|
||||
@@ -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<ILogger<RepositoryManager>>(),
|
||||
genConfig),
|
||||
Mock.Of<IAsyncDelayer>(),
|
||||
Mock.Of<IAbstractHttpClientFactory>(),
|
||||
Mock.Of<IHttpClientFactory>(),
|
||||
Options.Create(genConfig),
|
||||
Options.Create(new SessionConfiguration()))
|
||||
: new PlatformIdentifier().IsWindows
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
/// <inheritdoc />
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<ILogger<Host.IO.FileDownloader>>());
|
||||
var downloader = CachingFileDownloader.CreateRealDownloader(Mock.Of<ILogger<Host.IO.FileDownloader>>());
|
||||
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<ILogger<Host.IO.FileDownloader>>());
|
||||
var downloader = CachingFileDownloader.CreateRealDownloader(Mock.Of<ILogger<Host.IO.FileDownloader>>());
|
||||
var gitHubToken = Environment.GetEnvironmentVariable("TGS_TEST_GITHUB_TOKEN");
|
||||
if (String.IsNullOrWhiteSpace(gitHubToken))
|
||||
gitHubToken = null;
|
||||
|
||||
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user