diff --git a/.circleci/config.yml b/.circleci/config.yml index 876d46b5c..114d2b2e1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -8,13 +8,13 @@ jobs: resource_class: medium+ steps: - checkout - - run: dotnet tool restore && dotnet cake + - run: dotnet dev-certs https && dotnet tool restore && dotnet cake release: docker: - image: ocelot2/circleci-build:latest steps: - checkout - - run: dotnet tool restore && dotnet cake --target=Release + - run: dotnet dev-certs https && dotnet tool restore && dotnet cake --target=Release workflows: version: 2 main: diff --git a/docs/features/configuration.rst b/docs/features/configuration.rst index 87198ea1d..51631b768 100644 --- a/docs/features/configuration.rst +++ b/docs/features/configuration.rst @@ -26,6 +26,7 @@ Here is an example Route configuration. You don't need to set all of these thing "DownstreamPathTemplate": "/", "DownstreamHttpMethod": "", "DownstreamHttpVersion": "", + "DownstreamHttpVersionPolicy": "", "AddHeadersToRequest": {}, "AddClaimsToRequest": {}, "RouteClaimsRequirement": {}, @@ -404,11 +405,76 @@ Registering a callback } } +.. _config-http-version: + DownstreamHttpVersion --------------------- Ocelot allows you to choose the HTTP version it will use to make the proxy request. It can be set as ``1.0``, ``1.1`` or ``2.0``. +* `HttpVersion Class `_ + +.. _config-version-policy: + +DownstreamHttpVersionPolicy [#f5]_ +---------------------------------- + +This routing property enables the configuration of the ``VersionPolicy`` property within ``HttpRequestMessage`` objects for downstream HTTP requests. +For additional details, refer to the following documentation: + +* `HttpRequestMessage.VersionPolicy Property `_ +* `HttpVersionPolicy Enum `_ +* `HttpVersion Class `_ + +The ``DownstreamHttpVersionPolicy`` option is intricately linked with the :ref:`config-http-version` setting. +Therefore, merely specifying ``DownstreamHttpVersion`` may sometimes be inadequate, particularly if your downstream services or Ocelot logs report HTTP connection errors such as ``PROTOCOL_ERROR``. +In these routes, selecting the precise ``DownstreamHttpVersionPolicy`` value is crucial for the ``HttpVersion`` policy to prevent such protocol errors. + +HTTP/2 version policy +^^^^^^^^^^^^^^^^^^^^^ + +**Given** you aim to ensure a smooth HTTP/2 connection setup for the Ocelot app and downstream services with SSL enabled: + +.. code-block:: json + + { + "DownstreamScheme": "https", + "DownstreamHttpVersion": "2.0", + "DownstreamHttpVersionPolicy": "", // empty + "DangerousAcceptAnyServerCertificateValidator": true + } + +**And** you configure global settings to use Kestrel with this snippet: + +.. code-block:: csharp + + var builder = WebApplication.CreateBuilder(args); + builder.WebHost.ConfigureKestrel(serverOptions => + { + serverOptions.ConfigureEndpointDefaults(listenOptions => + { + listenOptions.Protocols = HttpProtocols.Http2; + }); + }); + +**When** all components are set to communicate exclusively via HTTP/2 without TLS (plain HTTP). + +**Then** the downstream services may display error messages such as: + +.. code-block:: + + HTTP/2 connection error (PROTOCOL_ERROR): Invalid HTTP/2 connection preface + +To resolve the issue, ensure that ``HttpRequestMessage`` has its ``VersionPolicy`` set to ``RequestVersionOrHigher``. +Therefore, the ``DownstreamHttpVersionPolicy`` should be defined as follows: + +.. code-block:: json + + { + "DownstreamHttpVersion": "2.0", + "DownstreamHttpVersionPolicy": "RequestVersionOrHigher" // ! + } + Dependency Injection -------------------- @@ -434,8 +500,10 @@ You can find additional details in the dedicated :ref:`di-configuration-overview .. [#f2] ":ref:`config-merging-tomemory`" subfeature is based on the ``MergeOcelotJson`` enumeration type with values: ``ToFile`` and ``ToMemory``. The 1st one is implicit by default, and the second one is exactly what you need when merging to memory. See more details on implementations in the `ConfigurationBuilderExtensions`_ class. .. [#f3] :ref:`di-the-addocelot-method` adds default ASP.NET services to DI container. You could call another extended :ref:`di-addocelotusingbuilder-method` while configuring services to develop your own :ref:`di-custom-builder`. See more instructions in the ":ref:`di-addocelotusingbuilder-method`" section of :doc:`../features/dependencyinjection` feature. .. [#f4] ":ref:`config-consul-key`" feature was requested in `issue 346 `_ as a part of version `7.0.0 `_. +.. [#f5] ":ref:`config-version-policy`" feature was requested in `issue 1672 `_ as a part of version `24.0`_. .. _20.0: https://github.com/ThreeMammals/Ocelot/releases/tag/20.0.0 .. _23.2: https://github.com/ThreeMammals/Ocelot/releases/tag/23.2.0 +.. _24.0: https://github.com/ThreeMammals/Ocelot/releases/tag/24.0.0 .. _ocelot.json: https://github.com/ThreeMammals/Ocelot/blob/main/test/Ocelot.ManualTest/ocelot.json .. _ConfigurationBuilderExtensions: https://github.com/ThreeMammals/Ocelot/blob/develop/src/Ocelot/DependencyInjection/ConfigurationBuilderExtensions.cs diff --git a/docs/make.bat b/docs/make.bat old mode 100755 new mode 100644 diff --git a/src/Ocelot/Configuration/Builder/DownstreamRouteBuilder.cs b/src/Ocelot/Configuration/Builder/DownstreamRouteBuilder.cs index f8e6dc159..ffff82e17 100644 --- a/src/Ocelot/Configuration/Builder/DownstreamRouteBuilder.cs +++ b/src/Ocelot/Configuration/Builder/DownstreamRouteBuilder.cs @@ -40,6 +40,7 @@ public class DownstreamRouteBuilder private SecurityOptions _securityOptions; private string _downstreamHttpMethod; private Version _downstreamHttpVersion; + private HttpVersionPolicy _downstreamHttpVersionPolicy; private Dictionary _upstreamHeaders; public DownstreamRouteBuilder() @@ -268,6 +269,12 @@ public DownstreamRouteBuilder WithUpstreamHeaders(Dictionary(); @@ -28,6 +30,7 @@ IVersionCreator versionCreator _qosOptionsCreator = qosOptionsCreator; _httpHandlerOptionsCreator = httpHandlerOptionsCreator; _versionCreator = versionCreator; + _versionPolicyCreator = versionPolicyCreator; } public InternalConfiguration Create(FileConfiguration fileConfiguration, List routes) @@ -43,6 +46,8 @@ public InternalConfiguration Create(FileConfiguration fileConfiguration, List Create(FileConfiguration fileConfiguration) @@ -27,12 +29,14 @@ private Route SetUpDynamicRoute(FileDynamicRoute fileDynamicRoute, FileGlobalCon .Create(fileDynamicRoute.RateLimitRule, globalConfiguration); var version = _versionCreator.Create(fileDynamicRoute.DownstreamHttpVersion); + var versionPolicy = _versionPolicyCreator.Create(fileDynamicRoute.DownstreamHttpVersionPolicy); var downstreamRoute = new DownstreamRouteBuilder() .WithEnableRateLimiting(rateLimitOption.EnableRateLimiting) .WithRateLimitOptions(rateLimitOption) .WithServiceName(fileDynamicRoute.ServiceName) .WithDownstreamHttpVersion(version) + .WithDownstreamHttpVersionPolicy(versionPolicy) .Build(); var route = new RouteBuilder() diff --git a/src/Ocelot/Configuration/Creator/HttpVersionPolicyCreator.cs b/src/Ocelot/Configuration/Creator/HttpVersionPolicyCreator.cs new file mode 100644 index 000000000..0c8af7123 --- /dev/null +++ b/src/Ocelot/Configuration/Creator/HttpVersionPolicyCreator.cs @@ -0,0 +1,20 @@ +namespace Ocelot.Configuration.Creator; + +/// +/// Default implementation of the interface. +/// +public class HttpVersionPolicyCreator : IVersionPolicyCreator +{ + /// + /// Creates a by a string. + /// + /// The string representation of the version policy. + /// An enumeration value. + public HttpVersionPolicy Create(string downstreamHttpVersionPolicy) => downstreamHttpVersionPolicy switch + { + VersionPolicies.RequestVersionExact => HttpVersionPolicy.RequestVersionExact, + VersionPolicies.RequestVersionOrHigher => HttpVersionPolicy.RequestVersionOrHigher, + VersionPolicies.RequestVersionOrLower => HttpVersionPolicy.RequestVersionOrLower, + _ => HttpVersionPolicy.RequestVersionOrLower, + }; +} diff --git a/src/Ocelot/Configuration/Creator/IVersionPolicyCreator.cs b/src/Ocelot/Configuration/Creator/IVersionPolicyCreator.cs new file mode 100644 index 000000000..3d25d8cea --- /dev/null +++ b/src/Ocelot/Configuration/Creator/IVersionPolicyCreator.cs @@ -0,0 +1,14 @@ +namespace Ocelot.Configuration.Creator; + +/// +/// Defines conversions from version policy strings to enumeration values. +/// +public interface IVersionPolicyCreator +{ + /// + /// Creates a by a string. + /// + /// The string representation of the version policy. + /// An enumeration value. + HttpVersionPolicy Create(string downstreamHttpVersionPolicy); +} diff --git a/src/Ocelot/Configuration/Creator/RoutesCreator.cs b/src/Ocelot/Configuration/Creator/RoutesCreator.cs index cb7a6c451..4c94f6c71 100644 --- a/src/Ocelot/Configuration/Creator/RoutesCreator.cs +++ b/src/Ocelot/Configuration/Creator/RoutesCreator.cs @@ -1,6 +1,6 @@ using Ocelot.Configuration.Builder; using Ocelot.Configuration.File; - + namespace Ocelot.Configuration.Creator { public class RoutesCreator : IRoutesCreator @@ -21,6 +21,7 @@ public class RoutesCreator : IRoutesCreator private readonly IRouteKeyCreator _routeKeyCreator; private readonly ISecurityOptionsCreator _securityOptionsCreator; private readonly IVersionCreator _versionCreator; + private readonly IVersionPolicyCreator _versionPolicyCreator; public RoutesCreator( IClaimsToThingCreator claimsToThingCreator, @@ -38,6 +39,7 @@ public RoutesCreator( IRouteKeyCreator routeKeyCreator, ISecurityOptionsCreator securityOptionsCreator, IVersionCreator versionCreator, + IVersionPolicyCreator versionPolicyCreator, IUpstreamHeaderTemplatePatternCreator upstreamHeaderTemplatePatternCreator) { _routeKeyCreator = routeKeyCreator; @@ -56,6 +58,7 @@ public RoutesCreator( _loadBalancerOptionsCreator = loadBalancerOptionsCreator; _securityOptionsCreator = securityOptionsCreator; _versionCreator = versionCreator; + _versionPolicyCreator = versionPolicyCreator; _upstreamHeaderTemplatePatternCreator = upstreamHeaderTemplatePatternCreator; } @@ -106,6 +109,8 @@ private DownstreamRoute SetUpDownstreamRoute(FileRoute fileRoute, FileGlobalConf var downstreamHttpVersion = _versionCreator.Create(fileRoute.DownstreamHttpVersion); + var downstreamHttpVersionPolicy = _versionPolicyCreator.Create(fileRoute.DownstreamHttpVersionPolicy); + var cacheOptions = _cacheOptionsCreator.Create(fileRoute.FileCacheOptions, globalConfiguration, fileRoute.UpstreamPathTemplate, fileRoute.UpstreamHttpMethod); var route = new DownstreamRouteBuilder() @@ -143,6 +148,7 @@ private DownstreamRoute SetUpDownstreamRoute(FileRoute fileRoute, FileGlobalConf .WithDangerousAcceptAnyServerCertificateValidator(fileRoute.DangerousAcceptAnyServerCertificateValidator) .WithSecurityOptions(securityOptions) .WithDownstreamHttpVersion(downstreamHttpVersion) + .WithDownstreamHttpVersionPolicy(downstreamHttpVersionPolicy) .WithDownStreamHttpMethod(fileRoute.DownstreamHttpMethod) .Build(); @@ -151,14 +157,14 @@ private DownstreamRoute SetUpDownstreamRoute(FileRoute fileRoute, FileGlobalConf private Route SetUpRoute(FileRoute fileRoute, DownstreamRoute downstreamRoutes) { - var upstreamTemplatePattern = _upstreamTemplatePatternCreator.Create(fileRoute); + var upstreamTemplatePattern = _upstreamTemplatePatternCreator.Create(fileRoute); var upstreamHeaderTemplates = _upstreamHeaderTemplatePatternCreator.Create(fileRoute); var route = new RouteBuilder() .WithUpstreamHttpMethod(fileRoute.UpstreamHttpMethod) .WithUpstreamPathTemplate(upstreamTemplatePattern) .WithDownstreamRoute(downstreamRoutes) - .WithUpstreamHost(fileRoute.UpstreamHost) + .WithUpstreamHost(fileRoute.UpstreamHost) .WithUpstreamHeaders(upstreamHeaderTemplates) .Build(); diff --git a/src/Ocelot/Configuration/Creator/VersionPolicies.cs b/src/Ocelot/Configuration/Creator/VersionPolicies.cs new file mode 100644 index 000000000..8073d47ab --- /dev/null +++ b/src/Ocelot/Configuration/Creator/VersionPolicies.cs @@ -0,0 +1,11 @@ +namespace Ocelot.Configuration.Creator; + +/// +/// Constants for conversions in concrete classes for the interface. +/// +public class VersionPolicies +{ + public const string RequestVersionExact = nameof(RequestVersionExact); + public const string RequestVersionOrLower = nameof(RequestVersionOrLower); + public const string RequestVersionOrHigher = nameof(RequestVersionOrHigher); +} diff --git a/src/Ocelot/Configuration/DownstreamRoute.cs b/src/Ocelot/Configuration/DownstreamRoute.cs index f71563cb0..ab4b6d5de 100644 --- a/src/Ocelot/Configuration/DownstreamRoute.cs +++ b/src/Ocelot/Configuration/DownstreamRoute.cs @@ -40,6 +40,7 @@ public DownstreamRoute( SecurityOptions securityOptions, string downstreamHttpMethod, Version downstreamHttpVersion, + HttpVersionPolicy downstreamHttpVersionPolicy, Dictionary upstreamHeaders) { DangerousAcceptAnyServerCertificateValidator = dangerousAcceptAnyServerCertificateValidator; @@ -75,7 +76,8 @@ public DownstreamRoute( AddHeadersToUpstream = addHeadersToUpstream; SecurityOptions = securityOptions; DownstreamHttpMethod = downstreamHttpMethod; - DownstreamHttpVersion = downstreamHttpVersion; + DownstreamHttpVersion = downstreamHttpVersion; + DownstreamHttpVersionPolicy = downstreamHttpVersionPolicy; UpstreamHeaders = upstreamHeaders ?? new(); } @@ -112,7 +114,19 @@ public DownstreamRoute( public bool DangerousAcceptAnyServerCertificateValidator { get; } public SecurityOptions SecurityOptions { get; } public string DownstreamHttpMethod { get; } - public Version DownstreamHttpVersion { get; } + public Version DownstreamHttpVersion { get; } + + /// The enum specifies behaviors for selecting and negotiating the HTTP version for a request. + /// An enum value being mapped from a constant. + /// + /// Related to the property. + /// + /// HttpVersionPolicy Enum + /// HttpVersion Class + /// HttpRequestMessage.VersionPolicy Property + /// + /// + public HttpVersionPolicy DownstreamHttpVersionPolicy { get; } public Dictionary UpstreamHeaders { get; } } } diff --git a/src/Ocelot/Configuration/File/FileDynamicRoute.cs b/src/Ocelot/Configuration/File/FileDynamicRoute.cs index fb93c2f91..21ad814af 100644 --- a/src/Ocelot/Configuration/File/FileDynamicRoute.cs +++ b/src/Ocelot/Configuration/File/FileDynamicRoute.cs @@ -1,3 +1,5 @@ +using Ocelot.Configuration.Creator; + namespace Ocelot.Configuration.File { public class FileDynamicRoute @@ -5,5 +7,17 @@ public class FileDynamicRoute public string ServiceName { get; set; } public FileRateLimitRule RateLimitRule { get; set; } public string DownstreamHttpVersion { get; set; } + + /// The enum specifies behaviors for selecting and negotiating the HTTP version for a request. + /// A value of defined constants. + /// + /// Related to the property. + /// + /// HttpVersionPolicy Enum + /// HttpVersion Class + /// HttpRequestMessage.VersionPolicy Property + /// + /// + public string DownstreamHttpVersionPolicy { get; set; } } } diff --git a/src/Ocelot/Configuration/File/FileGlobalConfiguration.cs b/src/Ocelot/Configuration/File/FileGlobalConfiguration.cs index 04497cca1..340ca04ff 100644 --- a/src/Ocelot/Configuration/File/FileGlobalConfiguration.cs +++ b/src/Ocelot/Configuration/File/FileGlobalConfiguration.cs @@ -1,4 +1,6 @@ -namespace Ocelot.Configuration.File +using Ocelot.Configuration.Creator; + +namespace Ocelot.Configuration.File { public class FileGlobalConfiguration { @@ -30,6 +32,18 @@ public FileGlobalConfiguration() public string DownstreamHttpVersion { get; set; } + /// The enum specifies behaviors for selecting and negotiating the HTTP version for a request. + /// A value of defined constants. + /// + /// Related to the property. + /// + /// HttpVersionPolicy Enum + /// HttpVersion Class + /// HttpRequestMessage.VersionPolicy Property + /// + /// + public string DownstreamHttpVersionPolicy { get; set; } + public FileCacheOptions CacheOptions { get; set; } } } diff --git a/src/Ocelot/Configuration/File/FileRoute.cs b/src/Ocelot/Configuration/File/FileRoute.cs index 874609e77..fe5eedf89 100644 --- a/src/Ocelot/Configuration/File/FileRoute.cs +++ b/src/Ocelot/Configuration/File/FileRoute.cs @@ -1,4 +1,6 @@ -namespace Ocelot.Configuration.File +using Ocelot.Configuration.Creator; + +namespace Ocelot.Configuration.File { public class FileRoute : IRoute, ICloneable { @@ -41,9 +43,21 @@ public FileRoute(FileRoute from) public List DownstreamHostAndPorts { get; set; } public string DownstreamHttpMethod { get; set; } public string DownstreamHttpVersion { get; set; } + + /// The enum specifies behaviors for selecting and negotiating the HTTP version for a request. + /// A value of defined constants. + /// + /// Related to the property. + /// + /// HttpVersionPolicy Enum + /// HttpVersion Class + /// HttpRequestMessage.VersionPolicy Property + /// + /// + public string DownstreamHttpVersionPolicy { get; set; } public string DownstreamPathTemplate { get; set; } - public string DownstreamScheme { get; set; } - public FileCacheOptions FileCacheOptions { get; set; } + public string DownstreamScheme { get; set; } + public FileCacheOptions FileCacheOptions { get; set; } public FileHttpHandlerOptions HttpHandlerOptions { get; set; } public string Key { get; set; } public FileLoadBalancerOptions LoadBalancerOptions { get; set; } @@ -87,6 +101,7 @@ public static void DeepCopy(FileRoute from, FileRoute to) to.DownstreamHostAndPorts = from.DownstreamHostAndPorts.Select(x => new FileHostAndPort(x)).ToList(); to.DownstreamHttpMethod = from.DownstreamHttpMethod; to.DownstreamHttpVersion = from.DownstreamHttpVersion; + to.DownstreamHttpVersionPolicy = from.DownstreamHttpVersionPolicy; to.DownstreamPathTemplate = from.DownstreamPathTemplate; to.DownstreamScheme = from.DownstreamScheme; to.FileCacheOptions = new(from.FileCacheOptions); diff --git a/src/Ocelot/Configuration/IInternalConfiguration.cs b/src/Ocelot/Configuration/IInternalConfiguration.cs index da839cf8b..59ef78549 100644 --- a/src/Ocelot/Configuration/IInternalConfiguration.cs +++ b/src/Ocelot/Configuration/IInternalConfiguration.cs @@ -1,3 +1,5 @@ +using Ocelot.Configuration.File; + namespace Ocelot.Configuration { public interface IInternalConfiguration @@ -19,5 +21,9 @@ public interface IInternalConfiguration HttpHandlerOptions HttpHandlerOptions { get; } Version DownstreamHttpVersion { get; } + + /// Global HTTP version policy. It is related to property. + /// An enumeration value. + HttpVersionPolicy? DownstreamHttpVersionPolicy { get; } } } diff --git a/src/Ocelot/Configuration/InternalConfiguration.cs b/src/Ocelot/Configuration/InternalConfiguration.cs index 86eb5472b..7d047cfe6 100644 --- a/src/Ocelot/Configuration/InternalConfiguration.cs +++ b/src/Ocelot/Configuration/InternalConfiguration.cs @@ -1,3 +1,5 @@ +using Ocelot.Configuration.File; + namespace Ocelot.Configuration { public class InternalConfiguration : IInternalConfiguration @@ -11,7 +13,8 @@ public InternalConfiguration( string downstreamScheme, QoSOptions qoSOptions, HttpHandlerOptions httpHandlerOptions, - Version downstreamHttpVersion) + Version downstreamHttpVersion, + HttpVersionPolicy? downstreamHttpVersionPolicy) { Routes = routes; AdministrationPath = administrationPath; @@ -22,6 +25,7 @@ public InternalConfiguration( QoSOptions = qoSOptions; HttpHandlerOptions = httpHandlerOptions; DownstreamHttpVersion = downstreamHttpVersion; + DownstreamHttpVersionPolicy = downstreamHttpVersionPolicy; } public List Routes { get; } @@ -34,5 +38,9 @@ public InternalConfiguration( public HttpHandlerOptions HttpHandlerOptions { get; } public Version DownstreamHttpVersion { get; } + + /// Global HTTP version policy. It is related to property. + /// An enumeration value. + public HttpVersionPolicy? DownstreamHttpVersionPolicy { get; } } } diff --git a/src/Ocelot/Configuration/Validator/RouteFluentValidator.cs b/src/Ocelot/Configuration/Validator/RouteFluentValidator.cs index f383bf75c..900c53189 100644 --- a/src/Ocelot/Configuration/Validator/RouteFluentValidator.cs +++ b/src/Ocelot/Configuration/Validator/RouteFluentValidator.cs @@ -1,6 +1,7 @@ using FluentValidation; using Microsoft.AspNetCore.Authentication; using Ocelot.Configuration.File; +using Ocelot.Configuration.Creator; namespace Ocelot.Configuration.Validator { @@ -84,6 +85,11 @@ public RouteFluentValidator(IAuthenticationSchemeProvider authenticationSchemePr { RuleFor(r => r.DownstreamHttpVersion).Matches("^[0-9]([.,][0-9]{1,1})?$"); }); + + When(route => !string.IsNullOrEmpty(route.DownstreamHttpVersionPolicy), () => + { + RuleFor(r => r.DownstreamHttpVersionPolicy).Matches($@"^({VersionPolicies.RequestVersionExact}|{VersionPolicies.RequestVersionOrHigher}|{VersionPolicies.RequestVersionOrLower})$"); + }); } private async Task IsSupportedAuthenticationProviders(FileAuthenticationOptions options, CancellationToken cancellationToken) diff --git a/src/Ocelot/DependencyInjection/OcelotBuilder.cs b/src/Ocelot/DependencyInjection/OcelotBuilder.cs index 70bf5338a..f25f5a5f8 100644 --- a/src/Ocelot/DependencyInjection/OcelotBuilder.cs +++ b/src/Ocelot/DependencyInjection/OcelotBuilder.cs @@ -137,6 +137,7 @@ public OcelotBuilder(IServiceCollection services, IConfiguration configurationRo Services.TryAddSingleton(); Services.TryAddSingleton(); Services.TryAddSingleton(); + Services.TryAddSingleton(); Services.TryAddSingleton(); // Add security diff --git a/src/Ocelot/Request/Mapper/RequestMapper.cs b/src/Ocelot/Request/Mapper/RequestMapper.cs index 883c42350..aa78e0a63 100644 --- a/src/Ocelot/Request/Mapper/RequestMapper.cs +++ b/src/Ocelot/Request/Mapper/RequestMapper.cs @@ -18,10 +18,10 @@ public HttpRequestMessage Map(HttpRequest request, DownstreamRoute downstreamRou Method = MapMethod(request, downstreamRoute), RequestUri = MapUri(request), Version = downstreamRoute.DownstreamHttpVersion, + VersionPolicy = downstreamRoute.DownstreamHttpVersionPolicy, }; MapHeaders(request, requestMessage); - return requestMessage; } @@ -55,7 +55,7 @@ private static void AddContentHeaders(HttpRequest request, HttpContent content) // The performance might be improved by retrieving the matching headers from the request // instead of calling request.Headers.TryGetValue for each used content header - var matchingHeaders = ContentHeaders.Where(header => request.Headers.ContainsKey(header)); + var matchingHeaders = ContentHeaders.Where(request.Headers.ContainsKey); foreach (var key in matchingHeaders) { diff --git a/test/Ocelot.AcceptanceTests/DefaultVersionPolicyTests.cs b/test/Ocelot.AcceptanceTests/DefaultVersionPolicyTests.cs new file mode 100644 index 000000000..c9a1d1419 --- /dev/null +++ b/test/Ocelot.AcceptanceTests/DefaultVersionPolicyTests.cs @@ -0,0 +1,166 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Ocelot.Configuration.Creator; +using Ocelot.Configuration.File; + +namespace Ocelot.AcceptanceTests; + +[Trait("Feat", "1672")] +public sealed class DefaultVersionPolicyTests : Steps +{ + private const string Body = "supercalifragilistic"; + + public DefaultVersionPolicyTests() + { + } + + [Fact] + public void Should_return_bad_gateway_when_request_higher_receive_lower() + { + var port = PortFinder.GetRandomPort(); + var route = GivenHttpsRoute(port, "2.0", VersionPolicies.RequestVersionOrHigher); + var configuration = GivenConfiguration(route); + this.Given(x => GivenThereIsAServiceRunningOn(port, HttpProtocols.Http1)) + .And(x => GivenThereIsAConfiguration(configuration)) + .And(x => GivenOcelotIsRunning()) + .When(x => WhenIGetUrlOnTheApiGateway("/")) + .Then(x => ThenTheStatusCodeShouldBe(HttpStatusCode.BadGateway)) + .BDDfy(); + } + + [Fact] + public void Should_return_bad_gateway_when_request_lower_receive_higher() + { + var port = PortFinder.GetRandomPort(); + var route = GivenHttpsRoute(port, "1.1", VersionPolicies.RequestVersionOrLower); + var configuration = GivenConfiguration(route); + this.Given(x => GivenThereIsAServiceRunningOn(port, HttpProtocols.Http2)) + .And(x => GivenThereIsAConfiguration(configuration)) + .And(x => GivenOcelotIsRunning()) + .When(x => WhenIGetUrlOnTheApiGateway("/")) + .Then(x => ThenTheStatusCodeShouldBe(HttpStatusCode.BadGateway)) + .BDDfy(); + } + + [Fact] + public void Should_return_bad_gateway_when_request_exact_receive_different() + { + var port = PortFinder.GetRandomPort(); + var route = GivenHttpsRoute(port, "1.1", VersionPolicies.RequestVersionExact); + var configuration = GivenConfiguration(route); + this.Given(x => GivenThereIsAServiceRunningOn(port, HttpProtocols.Http2)) + .And(x => GivenThereIsAConfiguration(configuration)) + .And(x => GivenOcelotIsRunning()) + .When(x => WhenIGetUrlOnTheApiGateway("/")) + .Then(x => ThenTheStatusCodeShouldBe(HttpStatusCode.BadGateway)) + .BDDfy(); + } + + [Fact] + public void Should_return_ok_when_request_version_exact_receive_exact() + { + var port = PortFinder.GetRandomPort(); + var route = GivenHttpsRoute(port, "2.0", VersionPolicies.RequestVersionExact); + var configuration = GivenConfiguration(route); + this.Given(x => GivenThereIsAServiceRunningOn(port, HttpProtocols.Http2)) + .And(x => GivenThereIsAConfiguration(configuration)) + .And(x => GivenOcelotIsRunning()) + .When(x => WhenIGetUrlOnTheApiGateway("/")) + .Then(x => ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .BDDfy(); + } + + [Fact] + public void Should_return_ok_when_request_version_lower_receive_lower() + { + var port = PortFinder.GetRandomPort(); + var route = GivenHttpsRoute(port, "2.0", VersionPolicies.RequestVersionOrLower); + var configuration = GivenConfiguration(route); + this.Given(x => GivenThereIsAServiceRunningOn(port, HttpProtocols.Http1)) + .And(x => GivenThereIsAConfiguration(configuration)) + .And(x => GivenOcelotIsRunning()) + .When(x => WhenIGetUrlOnTheApiGateway("/")) + .Then(x => ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .BDDfy(); + } + + [Fact] + public void Should_return_ok_when_request_version_lower_receive_exact() + { + var port = PortFinder.GetRandomPort(); + var route = GivenHttpsRoute(port, "2.0", VersionPolicies.RequestVersionOrLower); + var configuration = GivenConfiguration(route); + this.Given(x => GivenThereIsAServiceRunningOn(port, HttpProtocols.Http2)) + .And(x => GivenThereIsAConfiguration(configuration)) + .And(x => GivenOcelotIsRunning()) + .When(x => WhenIGetUrlOnTheApiGateway("/")) + .Then(x => ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .BDDfy(); + } + + [Fact] + public void Should_return_ok_when_request_version_higher_receive_higher() + { + var port = PortFinder.GetRandomPort(); + var route = GivenHttpsRoute(port, "1.1", VersionPolicies.RequestVersionOrHigher); + var configuration = GivenConfiguration(route); + this.Given(x => GivenThereIsAServiceRunningOn(port, HttpProtocols.Http2)) + .And(x => GivenThereIsAConfiguration(configuration)) + .And(x => GivenOcelotIsRunning()) + .When(x => WhenIGetUrlOnTheApiGateway("/")) + .Then(x => ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .BDDfy(); + } + + [Fact] + public void Should_return_ok_when_request_version_higher_receive_exact() + { + var port = PortFinder.GetRandomPort(); + var route = GivenHttpsRoute(port, "1.1", VersionPolicies.RequestVersionOrHigher); + var configuration = GivenConfiguration(route); + this.Given(x => GivenThereIsAServiceRunningOn(port, HttpProtocols.Http1)) + .And(x => GivenThereIsAConfiguration(configuration)) + .And(x => GivenOcelotIsRunning()) + .When(x => WhenIGetUrlOnTheApiGateway("/")) + .Then(x => ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .BDDfy(); + } + + private static void GivenThereIsAServiceRunningOn(int port, HttpProtocols protocols) + { + var url = $"{Uri.UriSchemeHttps}://localhost:{port}"; + var builder = new WebHostBuilder() + .UseUrls(url) + .UseKestrel() + .ConfigureKestrel(serverOptions => + { + serverOptions.ConfigureEndpointDefaults(listenOptions => { listenOptions.Protocols = protocols; }); + }) + .UseContentRoot(Directory.GetCurrentDirectory()) + .Configure(app => + { + app.Run(async context => + { + context.Response.StatusCode = (int)HttpStatusCode.OK; + await context.Response.WriteAsync(Body); + }); + }) + .Build(); + + builder.Start(); + } + + private static FileRoute GivenHttpsRoute(int port, string httpVersion, string versionPolicy) => new() + { + UpstreamPathTemplate = "/", + UpstreamHttpMethod = new() { HttpMethods.Get }, + DownstreamPathTemplate = "/", + DownstreamHostAndPorts = new() { new("localhost", port) }, + DownstreamScheme = Uri.UriSchemeHttps, // !!! + DownstreamHttpVersion = httpVersion, + DownstreamHttpVersionPolicy = versionPolicy, + DangerousAcceptAnyServerCertificateValidator = true, + }; +} diff --git a/test/Ocelot.AcceptanceTests/PollyQoSTests.cs b/test/Ocelot.AcceptanceTests/PollyQoSTests.cs index 58481afa3..597731755 100644 --- a/test/Ocelot.AcceptanceTests/PollyQoSTests.cs +++ b/test/Ocelot.AcceptanceTests/PollyQoSTests.cs @@ -198,11 +198,11 @@ private void GivenThereIsAPossiblyBrokenServiceRunningOn(string url, string resp { if (requestCount == 2) { - // in Polly v8 - // MinimumThroughput (ExceptionsAllowedBeforeBreaking) must be 2 or more - // BreakDuration (DurationOfBreak) must be 500 or more - // Timeout (TimeoutValue) must be 1000 or more - // so we wait for 2.1 seconds to make sure the circuit is open + // In Polly v8: + // MinimumThroughput (ExceptionsAllowedBeforeBreaking) must be 2 or more + // BreakDuration (DurationOfBreak) must be 500 or more + // Timeout (TimeoutValue) must be 1000 or more + // So, we wait for 2.1 seconds to make sure the circuit is open // DurationOfBreak * ExceptionsAllowedBeforeBreaking + Timeout // 500 * 2 + 1000 = 2000 minimum + 100 milliseconds to exceed the minimum await Task.Delay(2100); diff --git a/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs b/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs index c2157e24d..a5c1d7c94 100644 --- a/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs +++ b/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs @@ -2,7 +2,7 @@ namespace Ocelot.AcceptanceTests { - public class ReturnsErrorTests : IDisposable + public sealed class ReturnsErrorTests : IDisposable { private readonly Steps _steps; private readonly ServiceHandler _serviceHandler; diff --git a/test/Ocelot.Benchmarks/DownstreamRouteFinderMiddlewareBenchmarks.cs b/test/Ocelot.Benchmarks/DownstreamRouteFinderMiddlewareBenchmarks.cs index 4e99d1fe0..95124e6bf 100644 --- a/test/Ocelot.Benchmarks/DownstreamRouteFinderMiddlewareBenchmarks.cs +++ b/test/Ocelot.Benchmarks/DownstreamRouteFinderMiddlewareBenchmarks.cs @@ -52,7 +52,7 @@ public void SetUp() }, }; httpContext.Request.Headers.Append("Host", "most"); - httpContext.Items.SetIInternalConfiguration(new InternalConfiguration(new List(), null, null, null, null, null, null, null, null)); + httpContext.Items.SetIInternalConfiguration(new InternalConfiguration(new List(), null, null, null, null, null, null, null, null, null)); _httpContext = httpContext; } diff --git a/test/Ocelot.IntegrationTests/AdministrationTests.cs b/test/Ocelot.IntegrationTests/AdministrationTests.cs index 87ff03fd1..7495307a6 100644 --- a/test/Ocelot.IntegrationTests/AdministrationTests.cs +++ b/test/Ocelot.IntegrationTests/AdministrationTests.cs @@ -884,7 +884,7 @@ private void ThenTheResultHaveMultiLineIndentedJson() const string indent = " "; const int total = 52, skip = 1; var lines = _response.Content.ReadAsStringAsync().Result.Split(Environment.NewLine); - lines.Length.ShouldBe(total); + lines.Length.ShouldBeGreaterThanOrEqualTo(total); lines.First().ShouldNotStartWith(indent); lines.Skip(skip).Take(total - skip - 1).ToList() diff --git a/test/Ocelot.UnitTests/Configuration/ConfigurationCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/ConfigurationCreatorTests.cs index 8f6c7f803..7b3f98a2a 100644 --- a/test/Ocelot.UnitTests/Configuration/ConfigurationCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/ConfigurationCreatorTests.cs @@ -15,6 +15,7 @@ public class ConfigurationCreatorTests : UnitTest private readonly Mock _hhoCreator; private readonly Mock _lboCreator; private readonly Mock _vCreator; + private readonly Mock _versionPolicyCreator; private FileConfiguration _fileConfig; private List _routes; private ServiceProviderConfiguration _spc; @@ -27,6 +28,7 @@ public class ConfigurationCreatorTests : UnitTest public ConfigurationCreatorTests() { _vCreator = new Mock(); + _versionPolicyCreator = new Mock(); _lboCreator = new Mock(); _hhoCreator = new Mock(); _qosCreator = new Mock(); @@ -114,7 +116,7 @@ private void GivenTheDependenciesAreSetUp() private void WhenICreate() { var serviceProvider = _serviceCollection.BuildServiceProvider(); - _creator = new ConfigurationCreator(_spcCreator.Object, _qosCreator.Object, _hhoCreator.Object, serviceProvider, _lboCreator.Object, _vCreator.Object); + _creator = new ConfigurationCreator(_spcCreator.Object, _qosCreator.Object, _hhoCreator.Object, serviceProvider, _lboCreator.Object, _vCreator.Object, _versionPolicyCreator.Object); _result = _creator.Create(_fileConfig, _routes); } } diff --git a/test/Ocelot.UnitTests/Configuration/DynamicsCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/DynamicsCreatorTests.cs index aec6ffb75..63c7c5237 100644 --- a/test/Ocelot.UnitTests/Configuration/DynamicsCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/DynamicsCreatorTests.cs @@ -2,7 +2,7 @@ using Ocelot.Configuration.Builder; using Ocelot.Configuration.Creator; using Ocelot.Configuration.File; - + namespace Ocelot.UnitTests.Configuration { public class DynamicsCreatorTests : UnitTest @@ -10,17 +10,20 @@ public class DynamicsCreatorTests : UnitTest private readonly DynamicsCreator _creator; private readonly Mock _rloCreator; private readonly Mock _versionCreator; + private readonly Mock _versionPolicyCreator; private List _result; private FileConfiguration _fileConfig; private RateLimitOptions _rlo1; private RateLimitOptions _rlo2; private Version _version; + private HttpVersionPolicy _versionPolicy; public DynamicsCreatorTests() { _versionCreator = new Mock(); + _versionPolicyCreator = new Mock(); _rloCreator = new Mock(); - _creator = new DynamicsCreator(_rloCreator.Object, _versionCreator.Object); + _creator = new DynamicsCreator(_rloCreator.Object, _versionCreator.Object, _versionPolicyCreator.Object); } [Fact] @@ -50,6 +53,7 @@ public void should_return_re_routes() EnableRateLimiting = false, }, DownstreamHttpVersion = "1.1", + DownstreamHttpVersionPolicy = VersionPolicies.RequestVersionOrLower, }, new() { @@ -59,6 +63,7 @@ public void should_return_re_routes() EnableRateLimiting = true, }, DownstreamHttpVersion = "2.0", + DownstreamHttpVersionPolicy = VersionPolicies.RequestVersionOrHigher, }, }, }; @@ -66,6 +71,7 @@ public void should_return_re_routes() this.Given(_ => GivenThe(fileConfig)) .And(_ => GivenTheRloCreatorReturns()) .And(_ => GivenTheVersionCreatorReturns()) + .And(_ => GivenTheVersionPolicyCreatorReturns()) .When(_ => WhenICreate()) .Then(_ => ThenTheRoutesAreReturned()) .And(_ => ThenTheRloCreatorIsCalledCorrectly()) @@ -86,6 +92,9 @@ private void ThenTheVersionCreatorIsCalledCorrectly() { _versionCreator.Verify(x => x.Create(_fileConfig.DynamicRoutes[0].DownstreamHttpVersion), Times.Once); _versionCreator.Verify(x => x.Create(_fileConfig.DynamicRoutes[1].DownstreamHttpVersion), Times.Once); + + _versionPolicyCreator.Verify(x => x.Create(_fileConfig.DynamicRoutes[0].DownstreamHttpVersionPolicy), Times.Once); + _versionPolicyCreator.Verify(x => x.Create(_fileConfig.DynamicRoutes[1].DownstreamHttpVersionPolicy), Times.Once); } private void ThenTheRoutesAreReturned() @@ -94,11 +103,13 @@ private void ThenTheRoutesAreReturned() _result[0].DownstreamRoute[0].EnableEndpointEndpointRateLimiting.ShouldBeFalse(); _result[0].DownstreamRoute[0].RateLimitOptions.ShouldBe(_rlo1); _result[0].DownstreamRoute[0].DownstreamHttpVersion.ShouldBe(_version); + _result[0].DownstreamRoute[0].DownstreamHttpVersionPolicy.ShouldBe(_versionPolicy); _result[0].DownstreamRoute[0].ServiceName.ShouldBe(_fileConfig.DynamicRoutes[0].ServiceName); _result[1].DownstreamRoute[0].EnableEndpointEndpointRateLimiting.ShouldBeTrue(); _result[1].DownstreamRoute[0].RateLimitOptions.ShouldBe(_rlo2); _result[1].DownstreamRoute[0].DownstreamHttpVersion.ShouldBe(_version); + _result[1].DownstreamRoute[0].DownstreamHttpVersionPolicy.ShouldBe(_versionPolicy); _result[1].DownstreamRoute[0].ServiceName.ShouldBe(_fileConfig.DynamicRoutes[1].ServiceName); } @@ -107,6 +118,12 @@ private void GivenTheVersionCreatorReturns() _version = new Version("1.1"); _versionCreator.Setup(x => x.Create(It.IsAny())).Returns(_version); } + + private void GivenTheVersionPolicyCreatorReturns() + { + _versionPolicy = HttpVersionPolicy.RequestVersionOrLower; + _versionPolicyCreator.Setup(x => x.Create(It.IsAny())).Returns(_versionPolicy); + } private void GivenTheRloCreatorReturns() { diff --git a/test/Ocelot.UnitTests/Configuration/FileConfigurationSetterTests.cs b/test/Ocelot.UnitTests/Configuration/FileConfigurationSetterTests.cs index 2c2201a33..74709d949 100644 --- a/test/Ocelot.UnitTests/Configuration/FileConfigurationSetterTests.cs +++ b/test/Ocelot.UnitTests/Configuration/FileConfigurationSetterTests.cs @@ -32,7 +32,17 @@ public void should_set_configuration() { var fileConfig = new FileConfiguration(); var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); - var config = new InternalConfiguration(new List(), string.Empty, serviceProviderConfig, "asdf", new LoadBalancerOptionsBuilder().Build(), string.Empty, new QoSOptionsBuilder().Build(), new HttpHandlerOptionsBuilder().Build(), new Version("1.1")); + var config = new InternalConfiguration( + new List(), + string.Empty, + serviceProviderConfig, + "asdf", + new LoadBalancerOptionsBuilder().Build(), + string.Empty, + new QoSOptionsBuilder().Build(), + new HttpHandlerOptionsBuilder().Build(), + new Version("1.1"), + HttpVersionPolicy.RequestVersionOrLower); this.Given(x => GivenTheFollowingConfiguration(fileConfig)) .And(x => GivenTheRepoReturns(new OkResponse())) diff --git a/test/Ocelot.UnitTests/Configuration/FileInternalConfigurationCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/FileInternalConfigurationCreatorTests.cs index b8fb5b7f6..802a4588e 100644 --- a/test/Ocelot.UnitTests/Configuration/FileInternalConfigurationCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/FileInternalConfigurationCreatorTests.cs @@ -79,7 +79,7 @@ private void GivenTheDependenciesAreSetUp() _routes = new List { new RouteBuilder().Build() }; _aggregates = new List { new RouteBuilder().Build() }; _dynamics = new List { new RouteBuilder().Build() }; - _internalConfig = new InternalConfiguration(null, string.Empty, null, string.Empty, null, string.Empty, null, null, null); + _internalConfig = new InternalConfiguration(null, string.Empty, null, string.Empty, null, string.Empty, null, null, null, null); _routesCreator.Setup(x => x.Create(It.IsAny())).Returns(_routes); _aggregatesCreator.Setup(x => x.Create(It.IsAny(), It.IsAny>())).Returns(_aggregates); diff --git a/test/Ocelot.UnitTests/Configuration/HttpVersionPolicyCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/HttpVersionPolicyCreatorTests.cs new file mode 100644 index 000000000..813752d60 --- /dev/null +++ b/test/Ocelot.UnitTests/Configuration/HttpVersionPolicyCreatorTests.cs @@ -0,0 +1,50 @@ +using Ocelot.Configuration.Creator; + +namespace Ocelot.UnitTests.Configuration; + +[Trait("Feat", "1672")] +public sealed class HttpVersionPolicyCreatorTests : UnitTest +{ + private readonly HttpVersionPolicyCreator _creator; + + public HttpVersionPolicyCreatorTests() + { + _creator = new HttpVersionPolicyCreator(); + } + + [Theory] + [InlineData(VersionPolicies.RequestVersionOrLower, HttpVersionPolicy.RequestVersionOrLower)] + [InlineData(VersionPolicies.RequestVersionExact, HttpVersionPolicy.RequestVersionExact)] + [InlineData(VersionPolicies.RequestVersionOrHigher, HttpVersionPolicy.RequestVersionOrHigher)] + public void Should_create_version_policy_based_on_input(string versionPolicy, HttpVersionPolicy expected) + { + // Arrange, Act + var actual = _creator.Create(versionPolicy); + + // Assert + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData("")] + [InlineData(null)] + [InlineData("invalid version")] + public void Should_default_to_request_version_or_lower(string versionPolicy) + { + // Arrange, Act + var actual = _creator.Create(versionPolicy); + + // Assert + Assert.Equal(HttpVersionPolicy.RequestVersionOrLower, actual); + } + + [Fact] + public void Should_default_to_request_version_or_lower_when_setting_gibberish() + { + // Arrange, Act + var actual = _creator.Create("string is gibberish"); + + // Assert + Assert.Equal(HttpVersionPolicy.RequestVersionOrLower, actual); + } +} diff --git a/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs b/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs index 85d6bf210..e6f502438 100644 --- a/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs +++ b/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs @@ -3,7 +3,7 @@ using Ocelot.Configuration.ChangeTracking; using Ocelot.Configuration.Repository; using Ocelot.Responses; - + namespace Ocelot.UnitTests.Configuration { public class InMemoryConfigurationRepositoryTests : UnitTest @@ -115,6 +115,7 @@ public List Routes public QoSOptions QoSOptions { get; } public HttpHandlerOptions HttpHandlerOptions { get; } public Version DownstreamHttpVersion { get; } + public HttpVersionPolicy? DownstreamHttpVersionPolicy { get; } } } } diff --git a/test/Ocelot.UnitTests/Configuration/RoutesCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/RoutesCreatorTests.cs index c9fc698ff..5f8a481bc 100644 --- a/test/Ocelot.UnitTests/Configuration/RoutesCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/RoutesCreatorTests.cs @@ -25,6 +25,7 @@ public class RoutesCreatorTests : UnitTest private readonly Mock _rrkCreator; private readonly Mock _soCreator; private readonly Mock _versionCreator; + private readonly Mock _versionPolicyCreator; private FileConfiguration _fileConfig; private RouteOptions _rro; private string _requestId; @@ -40,7 +41,8 @@ public class RoutesCreatorTests : UnitTest private List _dhp; private LoadBalancerOptions _lbo; private List _result; - private Version _expectedVersion; + private Version _expectedVersion; + private HttpVersionPolicy _expectedVersionPolicy; private Dictionary _uht; public RoutesCreatorTests() @@ -60,6 +62,7 @@ public RoutesCreatorTests() _rrkCreator = new Mock(); _soCreator = new Mock(); _versionCreator = new Mock(); + _versionPolicyCreator = new Mock(); _uhtpCreator = new Mock(); _creator = new RoutesCreator( @@ -78,8 +81,8 @@ public RoutesCreatorTests() _rrkCreator.Object, _soCreator.Object, _versionCreator.Object, - _uhtpCreator.Object - ); + _versionPolicyCreator.Object, + _uhtpCreator.Object); } [Fact] @@ -156,6 +159,7 @@ private void ThenTheDependenciesAreCalledCorrectly() private void GivenTheDependenciesAreSetUpCorrectly() { _expectedVersion = new Version("1.1"); + _expectedVersionPolicy = HttpVersionPolicy.RequestVersionOrLower; _rro = new RouteOptions(false, false, false, false, false); _requestId = "testy"; _rrk = "besty"; @@ -169,7 +173,7 @@ private void GivenTheDependenciesAreSetUpCorrectly() _hho = new HttpHandlerOptionsBuilder().Build(); _ht = new HeaderTransformations(new List(), new List(), new List(), new List()); _dhp = new List(); - _lbo = new LoadBalancerOptionsBuilder().Build(); + _lbo = new LoadBalancerOptionsBuilder().Build(); _uht = new Dictionary(); _rroCreator.Setup(x => x.Create(It.IsAny())).Returns(_rro); @@ -185,7 +189,8 @@ private void GivenTheDependenciesAreSetUpCorrectly() _hfarCreator.Setup(x => x.Create(It.IsAny())).Returns(_ht); _daCreator.Setup(x => x.Create(It.IsAny())).Returns(_dhp); _lboCreator.Setup(x => x.Create(It.IsAny())).Returns(_lbo); - _versionCreator.Setup(x => x.Create(It.IsAny())).Returns(_expectedVersion); + _versionCreator.Setup(x => x.Create(It.IsAny())).Returns(_expectedVersion); + _versionPolicyCreator.Setup(x => x.Create(It.IsAny())).Returns(_expectedVersionPolicy); _uhtpCreator.Setup(x => x.Create(It.IsAny())).Returns(_uht); } @@ -215,6 +220,7 @@ private void WhenICreate() private void ThenTheRouteIsSet(FileRoute expected, int routeIndex) { _result[routeIndex].DownstreamRoute[0].DownstreamHttpVersion.ShouldBe(_expectedVersion); + _result[routeIndex].DownstreamRoute[0].DownstreamHttpVersionPolicy.ShouldBe(_expectedVersionPolicy); _result[routeIndex].DownstreamRoute[0].IsAuthenticated.ShouldBe(_rro.IsAuthenticated); _result[routeIndex].DownstreamRoute[0].IsAuthorized.ShouldBe(_rro.IsAuthorized); _result[routeIndex].DownstreamRoute[0].IsCached.ShouldBe(_rro.IsCached); @@ -255,7 +261,7 @@ private void ThenTheRouteIsSet(FileRoute expected, int routeIndex) .ShouldContain(x => x == expected.UpstreamHttpMethod[1]); _result[routeIndex].UpstreamHost.ShouldBe(expected.UpstreamHost); _result[routeIndex].DownstreamRoute.Count.ShouldBe(1); - _result[routeIndex].UpstreamTemplatePattern.ShouldBe(_upt); + _result[routeIndex].UpstreamTemplatePattern.ShouldBe(_upt); _result[routeIndex].UpstreamHeaderTemplates.ShouldBe(_uht); } diff --git a/test/Ocelot.UnitTests/Configuration/Validation/FileConfigurationFluentValidatorTests.cs b/test/Ocelot.UnitTests/Configuration/Validation/FileConfigurationFluentValidatorTests.cs index f3998c878..54b61aed0 100644 --- a/test/Ocelot.UnitTests/Configuration/Validation/FileConfigurationFluentValidatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/Validation/FileConfigurationFluentValidatorTests.cs @@ -33,7 +33,7 @@ public FileConfigurationFluentValidatorTests() _authProvider = new Mock(); _provider = _services.BuildServiceProvider(); - // Todo - replace with mocks + // TODO Replace with mocks _configurationValidator = new FileConfigurationFluentValidator(_provider, new RouteFluentValidator(_authProvider.Object, new HostAndPortValidator(), new FileQoSOptionsFluentValidator(_provider)), new FileGlobalConfigurationFluentValidator(new FileQoSOptionsFluentValidator(_provider))); } diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteCreatorTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteCreatorTests.cs index f4cb323f4..741af9d54 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteCreatorTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteCreatorTests.cs @@ -39,7 +39,17 @@ public DownstreamRouteCreatorTests() [Fact] public void should_create_downstream_route() { - var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1")); + var configuration = new InternalConfiguration( + null, + "doesnt matter", + null, + "doesnt matter", + _loadBalancerOptions, + "http", + _qoSOptions, + _handlerOptions, + new Version("1.1"), + HttpVersionPolicy.RequestVersionOrLower); this.Given(_ => GivenTheConfiguration(configuration)) .When(_ => WhenICreate()) @@ -66,7 +76,17 @@ public void should_create_downstream_route_with_rate_limit_options() var routes = new List { route }; - var configuration = new InternalConfiguration(routes, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1")); + var configuration = new InternalConfiguration( + routes, + "doesnt matter", + null, + "doesnt matter", + _loadBalancerOptions, + "http", + _qoSOptions, + _handlerOptions, + new Version("1.1"), + HttpVersionPolicy.RequestVersionOrLower); this.Given(_ => GivenTheConfiguration(configuration)) .When(_ => WhenICreate()) @@ -78,7 +98,17 @@ public void should_create_downstream_route_with_rate_limit_options() [Fact] public void should_cache_downstream_route() { - var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1")); + var configuration = new InternalConfiguration( + null, + "doesnt matter", + null, + "doesnt matter", + _loadBalancerOptions, + "http", + _qoSOptions, + _handlerOptions, + new Version("1.1"), + HttpVersionPolicy.RequestVersionOrLower); this.Given(_ => GivenTheConfiguration(configuration, "/geoffisthebest/")) .When(_ => WhenICreate()) @@ -91,7 +121,17 @@ public void should_cache_downstream_route() [Fact] public void should_not_cache_downstream_route() { - var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1")); + var configuration = new InternalConfiguration( + null, + "doesnt matter", + null, + "doesnt matter", + _loadBalancerOptions, + "http", + _qoSOptions, + _handlerOptions, + new Version("1.1"), + HttpVersionPolicy.RequestVersionOrLower); this.Given(_ => GivenTheConfiguration(configuration, "/geoffistheworst/")) .When(_ => WhenICreate()) @@ -105,7 +145,17 @@ public void should_not_cache_downstream_route() public void should_create_downstream_route_with_no_path() { var upstreamUrlPath = "/auth/"; - var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1")); + var configuration = new InternalConfiguration( + null, + "doesnt matter", + null, + "doesnt matter", + _loadBalancerOptions, + "http", + _qoSOptions, + _handlerOptions, + new Version("1.1"), + HttpVersionPolicy.RequestVersionOrLower); this.Given(_ => GivenTheConfiguration(configuration, upstreamUrlPath)) .When(_ => WhenICreate()) @@ -117,7 +167,17 @@ public void should_create_downstream_route_with_no_path() public void should_create_downstream_route_with_only_first_segment_no_traling_slash() { var upstreamUrlPath = "/auth"; - var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1")); + var configuration = new InternalConfiguration( + null, + "doesnt matter", + null, + "doesnt matter", + _loadBalancerOptions, + "http", + _qoSOptions, + _handlerOptions, + new Version("1.1"), + HttpVersionPolicy.RequestVersionOrLower); this.Given(_ => GivenTheConfiguration(configuration, upstreamUrlPath)) .When(_ => WhenICreate()) @@ -129,7 +189,17 @@ public void should_create_downstream_route_with_only_first_segment_no_traling_sl public void should_create_downstream_route_with_segments_no_traling_slash() { var upstreamUrlPath = "/auth/test"; - var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1")); + var configuration = new InternalConfiguration( + null, + "doesnt matter", + null, + "doesnt matter", + _loadBalancerOptions, + "http", + _qoSOptions, + _handlerOptions, + new Version("1.1"), + HttpVersionPolicy.RequestVersionOrHigher); this.Given(_ => GivenTheConfiguration(configuration, upstreamUrlPath)) .When(_ => WhenICreate()) @@ -141,7 +211,17 @@ public void should_create_downstream_route_with_segments_no_traling_slash() public void should_create_downstream_route_and_remove_query_string() { var upstreamUrlPath = "/auth/test?test=1&best=2"; - var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1")); + var configuration = new InternalConfiguration( + null, + "doesnt matter", + null, + "doesnt matter", + _loadBalancerOptions, + "http", + _qoSOptions, + _handlerOptions, + new Version("1.1"), + HttpVersionPolicy.RequestVersionOrLower); this.Given(_ => GivenTheConfiguration(configuration, upstreamUrlPath)) .When(_ => WhenICreate()) @@ -153,7 +233,17 @@ public void should_create_downstream_route_and_remove_query_string() public void should_create_downstream_route_for_sticky_sessions() { var loadBalancerOptions = new LoadBalancerOptionsBuilder().WithType(nameof(CookieStickySessions)).WithKey("boom").WithExpiryInMs(1).Build(); - var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1")); + var configuration = new InternalConfiguration( + null, + "doesnt matter", + null, + "doesnt matter", + loadBalancerOptions, + "http", + _qoSOptions, + _handlerOptions, + new Version("1.1"), + HttpVersionPolicy.RequestVersionOrLower); this.Given(_ => GivenTheConfiguration(configuration)) .When(_ => WhenICreate()) @@ -169,7 +259,17 @@ public void should_create_downstream_route_with_qos() .WithTimeoutValue(1) .Build(); - var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", qoSOptions, _handlerOptions, new Version("1.1")); + var configuration = new InternalConfiguration( + null, + "doesnt matter", + null, + "doesnt matter", + _loadBalancerOptions, + "http", + qoSOptions, + _handlerOptions, + new Version("1.1"), + HttpVersionPolicy.RequestVersionOrLower); this.Given(_ => GivenTheConfiguration(configuration)) .And(_ => GivenTheQosCreatorReturns(qoSOptions)) @@ -181,7 +281,17 @@ public void should_create_downstream_route_with_qos() [Fact] public void should_create_downstream_route_with_handler_options() { - var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1")); + var configuration = new InternalConfiguration( + null, + "doesnt matter", + null, + "doesnt matter", + _loadBalancerOptions, + "http", + _qoSOptions, + _handlerOptions, + new Version("1.1"), + HttpVersionPolicy.RequestVersionOrLower); this.Given(_ => GivenTheConfiguration(configuration)) .When(_ => WhenICreate()) diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs index eb6ebe68f..c96b81e69 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs @@ -39,7 +39,17 @@ public DownstreamRouteFinderMiddlewareTests() [Fact] public void should_call_scoped_data_repository_correctly() { - var config = new InternalConfiguration(null, null, new ServiceProviderConfigurationBuilder().Build(), string.Empty, new LoadBalancerOptionsBuilder().Build(), string.Empty, new QoSOptionsBuilder().Build(), new HttpHandlerOptionsBuilder().Build(), new Version("1.1")); + var config = new InternalConfiguration( + null, + null, + new ServiceProviderConfigurationBuilder().Build(), + string.Empty, + new LoadBalancerOptionsBuilder().Build(), + string.Empty, + new QoSOptionsBuilder().Build(), + new HttpHandlerOptionsBuilder().Build(), + new Version("1.1"), + HttpVersionPolicy.RequestVersionOrLower); var downstreamRoute = new DownstreamRouteBuilder() .WithDownstreamPathTemplate("any old string") diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs index ec6026a5b..2c2e04510 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs @@ -907,7 +907,17 @@ private void GivenTheHeadersMatcherReturns(bool headersMatch) private void GivenTheConfigurationIs(List routesConfig, string adminPath, ServiceProviderConfiguration serviceProviderConfig) { _routesConfig = routesConfig; - _config = new InternalConfiguration(_routesConfig, adminPath, serviceProviderConfig, string.Empty, new LoadBalancerOptionsBuilder().Build(), string.Empty, new QoSOptionsBuilder().Build(), new HttpHandlerOptionsBuilder().Build(), new Version("1.1")); + _config = new InternalConfiguration( + _routesConfig, + adminPath, + serviceProviderConfig, + string.Empty, + new LoadBalancerOptionsBuilder().Build(), + string.Empty, + new QoSOptionsBuilder().Build(), + new HttpHandlerOptionsBuilder().Build(), + new Version("1.1"), + HttpVersionPolicy.RequestVersionOrLower); } private void GivenThereIsAnUpstreamUrlPath(string upstreamUrlPath) diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteProviderFactoryTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteProviderFactoryTests.cs index 20426362a..2eb2a092b 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteProviderFactoryTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteProviderFactoryTests.cs @@ -151,12 +151,32 @@ private void WhenIGet() private void GivenTheRoutes(List routes) { - _config = new InternalConfiguration(routes, string.Empty, null, string.Empty, new LoadBalancerOptionsBuilder().Build(), string.Empty, new QoSOptionsBuilder().Build(), new HttpHandlerOptionsBuilder().Build(), new Version("1.1")); + _config = new InternalConfiguration( + routes, + string.Empty, + null, + string.Empty, + new LoadBalancerOptionsBuilder().Build(), + string.Empty, + new QoSOptionsBuilder().Build(), + new HttpHandlerOptionsBuilder().Build(), + new Version("1.1"), + HttpVersionPolicy.RequestVersionOrLower); } private void GivenTheRoutes(List routes, ServiceProviderConfiguration config) { - _config = new InternalConfiguration(routes, string.Empty, config, string.Empty, new LoadBalancerOptionsBuilder().Build(), string.Empty, new QoSOptionsBuilder().Build(), new HttpHandlerOptionsBuilder().Build(), new Version("1.1")); + _config = new InternalConfiguration( + routes, + string.Empty, + config, + string.Empty, + new LoadBalancerOptionsBuilder().Build(), + string.Empty, + new QoSOptionsBuilder().Build(), + new HttpHandlerOptionsBuilder().Build(), + new Version("1.1"), + HttpVersionPolicy.RequestVersionOrLower); } } } diff --git a/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs b/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs index 615eb704e..6f2d5333c 100644 --- a/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs @@ -545,7 +545,7 @@ public void should_fix_issue_748(string upstreamTemplate, string downstreamTempl private void GivenTheServiceProviderConfigIs(ServiceProviderConfiguration config) { - var configuration = new InternalConfiguration(null, null, config, null, null, null, null, null, null); + var configuration = new InternalConfiguration(null, null, config, null, null, null, null, null, null, null); _httpContext.Items.SetIInternalConfiguration(configuration); } diff --git a/test/Ocelot.UnitTests/Errors/ExceptionHandlerMiddlewareTests.cs b/test/Ocelot.UnitTests/Errors/ExceptionHandlerMiddlewareTests.cs index ab72f90e2..9bb883aa3 100644 --- a/test/Ocelot.UnitTests/Errors/ExceptionHandlerMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Errors/ExceptionHandlerMiddlewareTests.cs @@ -42,7 +42,7 @@ public ExceptionHandlerMiddlewareTests() [Fact] public void NoDownstreamException() { - var config = new InternalConfiguration(null, null, null, null, null, null, null, null, null); + var config = new InternalConfiguration(null, null, null, null, null, null, null, null, null, null); this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream()) .And(_ => GivenTheConfigurationIs(config)) @@ -55,7 +55,7 @@ public void NoDownstreamException() [Fact] public void DownstreamException() { - var config = new InternalConfiguration(null, null, null, null, null, null, null, null, null); + var config = new InternalConfiguration(null, null, null, null, null, null, null, null, null, null); this.Given(_ => GivenAnExceptionWillBeThrownDownstream()) .And(_ => GivenTheConfigurationIs(config)) @@ -67,7 +67,7 @@ public void DownstreamException() [Fact] public void ShouldSetRequestId() { - var config = new InternalConfiguration(null, null, null, "requestidkey", null, null, null, null, null); + var config = new InternalConfiguration(null, null, null, "requestidkey", null, null, null, null, null, null); this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream()) .And(_ => GivenTheConfigurationIs(config)) @@ -80,7 +80,7 @@ public void ShouldSetRequestId() [Fact] public void ShouldSetAspDotNetRequestId() { - var config = new InternalConfiguration(null, null, null, null, null, null, null, null, null); + var config = new InternalConfiguration(null, null, null, null, null, null, null, null, null, null); this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream()) .And(_ => GivenTheConfigurationIs(config)) diff --git a/test/Ocelot.UnitTests/Eureka/EurekaMiddlewareConfigurationProviderTests.cs b/test/Ocelot.UnitTests/Eureka/EurekaMiddlewareConfigurationProviderTests.cs index ad981a59b..f020707be 100644 --- a/test/Ocelot.UnitTests/Eureka/EurekaMiddlewareConfigurationProviderTests.cs +++ b/test/Ocelot.UnitTests/Eureka/EurekaMiddlewareConfigurationProviderTests.cs @@ -16,7 +16,7 @@ public void ShouldNotBuild() { var configRepo = new Mock(); configRepo.Setup(x => x.Get()) - .Returns(new OkResponse(new InternalConfiguration(null, null, null, null, null, null, null, null, null))); + .Returns(new OkResponse(new InternalConfiguration(null, null, null, null, null, null, null, null, null, null))); var services = new ServiceCollection(); services.AddSingleton(configRepo.Object); var sp = services.BuildServiceProvider(); @@ -31,7 +31,7 @@ public void ShouldBuild() var client = new Mock(); var configRepo = new Mock(); configRepo.Setup(x => x.Get()) - .Returns(new OkResponse(new InternalConfiguration(null, null, serviceProviderConfig, null, null, null, null, null, null))); + .Returns(new OkResponse(new InternalConfiguration(null, null, serviceProviderConfig, null, null, null, null, null, null, null))); var services = new ServiceCollection(); services.AddSingleton(configRepo.Object); services.AddSingleton(client.Object); diff --git a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs index f5b5dd925..fd46e9a2a 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs @@ -131,7 +131,7 @@ private void WhenICallTheMiddleware() private void GivenTheConfigurationIs(ServiceProviderConfiguration config) { _config = config; - var configuration = new InternalConfiguration(null, null, config, null, null, null, null, null, null); + var configuration = new InternalConfiguration(null, null, config, null, null, null, null, null, null, null); _httpContext.Items.SetIInternalConfiguration(configuration); } diff --git a/test/Ocelot.UnitTests/Polly/PollyQoSProviderTests.cs b/test/Ocelot.UnitTests/Polly/PollyQoSProviderTests.cs index 8c08a46e0..bc56a1a1f 100644 --- a/test/Ocelot.UnitTests/Polly/PollyQoSProviderTests.cs +++ b/test/Ocelot.UnitTests/Polly/PollyQoSProviderTests.cs @@ -1,6 +1,5 @@ using Ocelot.Configuration.Builder; using Ocelot.Logging; -using Ocelot.Provider.Polly; using Ocelot.Provider.Polly.v7; using Polly; using Polly.CircuitBreaker; @@ -29,7 +28,7 @@ public void Should_build() } [Fact] - public void should_build_and_wrap_contains_two_policies() + public void Should_build_and_wrap_contains_two_policies() { var pollyQosProvider = PollyQoSProviderFactory(); var pollyPolicyWrapper = PolicyWrapperFactory("/", pollyQosProvider); @@ -70,7 +69,7 @@ public void should_build_and_wrap_contains_two_policies() } [Fact] - public void should_build_and_contains_one_policy_when_with_exceptions_allowed_before_breaking_is_zero() + public void Should_build_and_contains_one_policy_when_with_exceptions_allowed_before_breaking_is_zero() { var pollyQosProvider = PollyQoSProviderFactory(); var pollyPolicyWrapper = PolicyWrapperFactory("/", pollyQosProvider, true); @@ -86,7 +85,7 @@ public void should_build_and_contains_one_policy_when_with_exceptions_allowed_be } [Fact] - public void should_return_same_circuit_breaker_for_given_route() + public void Should_return_same_circuit_breaker_for_given_route() { var pollyQosProvider = PollyQoSProviderFactory(); var pollyPolicyWrapper = PolicyWrapperFactory("/", pollyQosProvider); @@ -95,7 +94,7 @@ public void should_return_same_circuit_breaker_for_given_route() } [Fact] - public void should_return_different_circuit_breaker_for_two_different_routes() + public void Should_return_different_circuit_breaker_for_two_different_routes() { var pollyQosProvider = PollyQoSProviderFactory(); var pollyPolicyWrapper = PolicyWrapperFactory("/", pollyQosProvider); @@ -113,7 +112,7 @@ public void should_return_different_circuit_breaker_for_two_different_routes() [InlineData(HttpStatusCode.VariantAlsoNegotiates)] [InlineData(HttpStatusCode.InsufficientStorage)] [InlineData(HttpStatusCode.LoopDetected)] - public async Task should_throw_broken_circuit_exception_after_two_exceptions(HttpStatusCode errorCode) + public async Task Should_throw_broken_circuit_exception_after_two_exceptions(HttpStatusCode errorCode) { var pollyPolicyWrapper = PolicyWrapperFactory("/", PollyQoSProviderFactory()); @@ -125,7 +124,7 @@ await Assert.ThrowsAsync>(async () = } [Fact] - public async Task should_not_throw_broken_circuit_exception_if_status_code_ok() + public async Task Should_not_throw_broken_circuit_exception_if_status_code_ok() { var pollyPolicyWrapper = PolicyWrapperFactory("/", PollyQoSProviderFactory()); @@ -135,9 +134,9 @@ public async Task should_not_throw_broken_circuit_exception_if_status_code_ok() Assert.Equal(HttpStatusCode.OK, (await pollyPolicyWrapper.AsyncPollyPolicy.ExecuteAsync(() => Task.FromResult(response))).StatusCode); } - [Fact(Skip = "TODO", DisplayName = "TODO " + nameof(should_throw_and_before_delay_should_not_allow_requests))] + [Fact(Skip = "TODO", DisplayName = "TODO " + nameof(Should_throw_and_before_delay_should_not_allow_requests))] [Trait("TODO", "Fix after the release")] - public async Task should_throw_and_before_delay_should_not_allow_requests() + public async Task Should_throw_and_before_delay_should_not_allow_requests() { var pollyPolicyWrapper = PolicyWrapperFactory("/", PollyQoSProviderFactory()); @@ -154,7 +153,7 @@ await Assert.ThrowsAsync>(async () = } [Fact] - public async Task should_throw_but_after_delay_should_allow_one_more_internal_server_error() + public async Task Should_throw_but_after_delay_should_allow_one_more_internal_server_error() { var pollyPolicyWrapper = PolicyWrapperFactory("/", PollyQoSProviderFactory()); @@ -170,7 +169,7 @@ await Assert.ThrowsAsync>(async () = } [Fact] - public async Task should_throw_but_after_delay_should_allow_one_more_internal_server_error_and_throw() + public async Task Should_throw_but_after_delay_should_allow_one_more_internal_server_error_and_throw() { var pollyPolicyWrapper = PolicyWrapperFactory("/", PollyQoSProviderFactory()); @@ -188,7 +187,7 @@ await Assert.ThrowsAsync>(async () = } [Fact] - public async Task should_throw_but_after_delay_should_allow_one_more_ok_request_and_put_counter_back_to_zero() + public async Task Should_throw_but_after_delay_should_allow_one_more_ok_request_and_put_counter_back_to_zero() { var pollyPolicyWrapper = PolicyWrapperFactory("/", PollyQoSProviderFactory()); @@ -208,14 +207,12 @@ await Assert.ThrowsAsync>(async () = await pollyPolicyWrapper.AsyncPollyPolicy.ExecuteAsync(() => Task.FromResult(response))); } - private PollyQoSProvider PollyQoSProviderFactory() + private static PollyQoSProvider PollyQoSProviderFactory() { var factory = new Mock(); factory.Setup(x => x.CreateLogger()) .Returns(new Mock().Object); - - var pollyQoSProvider = new PollyQoSProvider(factory.Object); - return pollyQoSProvider; + return new PollyQoSProvider(factory.Object); } private static PollyPolicyWrapper PolicyWrapperFactory(string routeTemplate, PollyQoSProvider pollyQoSProvider, bool inactiveExceptionsAllowedBeforeBreaking = false)