From 5c8938f67e79d6eb4771863659430637881ae351 Mon Sep 17 00:00:00 2001 From: Raman Maksimchuk Date: Thu, 12 Dec 2024 15:52:07 +0300 Subject: [PATCH] #2219 Remove the BDDfy framework from the unit testing project (#2235) * Day 1 * Day 2 * Day 3 * Day 4 * Day 5 * Day 6 --- test/Ocelot.Testing/StreamExtensions.cs | 11 + .../OcelotAdministrationBuilderTests.cs | 33 +- .../AuthenticationMiddlewareTests.cs | 161 +- .../AuthorizationMiddlewareTests.cs | 23 +- .../Authorization/ClaimsAuthorizerTests.cs | 152 +- .../Cache/CacheOptionsCreatorTests.cs | 45 +- .../Cache/DefaultCacheKeyGeneratorTests.cs | 111 +- .../Cache/DefaultMemoryCacheTests.cs | 40 +- .../Cache/OutputCacheMiddlewareTests.cs | 55 +- .../OcelotBuilderExtensionsTests.cs | 11 +- .../CacheManager/OcelotCacheManagerCache.cs | 38 +- .../OutputCacheMiddlewareRealCacheTests.cs | 20 +- .../Claims/AddClaimsToRequestTests.cs | 79 +- .../Claims/ClaimsToClaimsMiddlewareTests.cs | 29 +- .../Configuration/AggregatesCreatorTests.cs | 42 +- .../AuthenticationOptionsCreatorTests.cs | 7 +- .../Configuration/CacheOptionsCreatorTests.cs | 24 +- ...elotConfigurationChangeTokenSourceTests.cs | 16 +- .../OcelotConfigurationChangeTokenTests.cs | 40 +- .../ClaimToThingConfigurationParserTests.cs | 124 +- .../ClaimsToThingCreatorTests.cs | 44 +- .../ConfigurationCreatorTests.cs | 38 +- .../DefaultMetadataCreatorTests.cs | 86 +- .../DiskFileConfigurationRepositoryTests.cs | 21 +- .../DownstreamAddressesCreatorTests.cs | 80 +- .../DownstreamRouteExtensionsTests.cs | 10 +- .../Configuration/DynamicsCreatorTests.cs | 48 +- .../FileConfigurationPollerTests.cs | 82 +- .../FileConfigurationSetterTests.cs | 67 +- .../FileInternalConfigurationCreatorTests.cs | 51 +- .../FileModels/FileQoSOptionsTests.cs | 1 + .../Configuration/HashCreationTests.cs | 10 +- .../HeaderFindAndReplaceCreatorTests.cs | 165 +- .../HttpHandlerOptionsCreatorTests.cs | 149 +- .../HttpVersionPolicyCreatorTests.cs | 3 +- .../InMemoryConfigurationRepositoryTests.cs | 61 +- .../LoadBalancerOptionsCreatorTests.cs | 41 +- .../Configuration/QoSOptionsCreatorTests.cs | 39 +- .../RateLimitOptionsCreatorTests.cs | 71 +- .../Configuration/RequestIdKeyCreatorTests.cs | 67 +- .../Configuration/RouteKeyCreatorTests.cs | 72 +- .../Configuration/RouteOptionsCreatorTests.cs | 7 +- .../Configuration/RoutesCreatorTests.cs | 44 +- .../SecurityOptionsCreatorTests.cs | 11 +- ...erviceProviderConfigurationCreatorTests.cs | 50 + .../ServiceProviderCreatorTests.cs | 72 - ...streamHeaderTemplatePatternCreatorTests.cs | 8 +- .../UpstreamTemplatePatternCreatorTests.cs | 251 +-- .../FileConfigurationFluentValidatorTests.cs | 658 ++++---- .../FileQoSOptionsFluentValidatorTests.cs | 70 +- .../Validation/HostAndPortValidatorTests.cs | 58 +- .../Validation/RouteFluentValidatorTests.cs | 302 ++-- .../Configuration/VersionCreatorTests.cs | 47 +- .../ConsulFileConfigurationRepositoryTests.cs | 165 +- .../Consul/ConsulProviderFactoryTests.cs | 2 +- test/Ocelot.UnitTests/Consul/ConsulTests.cs | 26 +- .../DefaultConsulServiceBuilderTests.cs | 1 - .../Consul/OcelotBuilderExtensionsTests.cs | 54 +- ...lingConsulServiceDiscoveryProviderTests.cs | 31 +- .../FileConfigurationControllerTests.cs | 104 +- .../Controllers/OutputCacheControllerTests.cs | 26 +- .../ConfigurationBuilderExtensionsTests.cs | 4 +- .../DependencyInjection/OcelotBuilderTests.cs | 370 ++--- .../ChangeDownstreamPathTemplateTests.cs | 178 +-- .../ClaimsToDownstreamPathMiddlewareTests.cs | 42 +- .../DownstreamRouteCreatorTests.cs | 178 ++- .../DownstreamRouteFinderMiddlewareTests.cs | 32 +- .../DownstreamRouteFinderTests.cs | 1348 ++++++++--------- .../DownstreamRouteProviderFactoryTests.cs | 176 ++- ...eaderPlaceholderNameAndValueFinderTests.cs | 76 +- .../HeadersToHeaderTemplatesMatcherTests.cs | 101 +- .../UrlMatcher/RegExUrlMatcherTests.cs | 397 ++--- ...lPathPlaceholderNameAndValueFinderTests.cs | 9 +- .../DownstreamPathPlaceholderReplacerTests.cs | 286 ++-- .../DownstreamUrlCreatorMiddlewareTests.cs | 4 +- test/Ocelot.UnitTests/Errors/ErrorTests.cs | 7 +- .../Errors/ExceptionHandlerMiddlewareTests.cs | 138 +- ...ekaMiddlewareConfigurationProviderTests.cs | 10 + .../Eureka/EurekaProviderFactoryTests.cs | 15 +- .../EurekaServiceDiscoveryProviderTests.cs | 71 +- .../Eureka/OcelotBuilderExtensionsTests.cs | 6 +- .../AddHeadersToRequestClaimToThingTests.cs | 135 +- .../Headers/AddHeadersToRequestPlainTests.cs | 67 +- .../Headers/AddHeadersToResponseTests.cs | 103 +- .../Headers/ClaimsToHeadersMiddlewareTests.cs | 54 +- .../HttpContextRequestHeaderReplacerTests.cs | 74 +- ...ttpHeadersTransformationMiddlewareTests.cs | 33 +- .../HttpResponseHeaderReplacerTests.cs | 189 +-- .../Headers/RemoveHeadersTests.cs | 40 +- .../Infrastructure/ClaimParserTests.cs | 141 +- .../ConfigAwarePlaceholdersTests.cs | 40 +- .../Infrastructure/HttpDataRepositoryTests.cs | 66 +- .../Infrastructure/InMemoryBusTests.cs | 31 +- .../Infrastructure/PlaceholdersTests.cs | 94 +- .../Infrastructure/ScopesAuthorizerTests.cs | 108 +- .../Kubernetes/PollKubeTests.cs | 19 +- .../CookieStickySessionsCreatorTests.cs | 53 +- .../LoadBalancer/CookieStickySessionsTests.cs | 197 +-- ...elegateInvokingLoadBalancerCreatorTests.cs | 80 +- .../LeastConnectionCreatorTests.cs | 56 +- .../LoadBalancer/LeastConnectionTests.cs | 153 +- .../LoadBalancer/LoadBalancerFactoryTests.cs | 179 +-- .../LoadBalancer/LoadBalancerHouseTests.cs | 151 +- .../LoadBalancerMiddlewareTests.cs | 209 +-- .../LoadBalancer/LoadBalancerOptionsTests.cs | 5 +- .../NoLoadBalancerCreatorTests.cs | 55 +- .../LoadBalancer/NoLoadBalancerTests.cs | 72 +- .../LoadBalancer/RoundRobinCreatorTests.cs | 54 +- .../LoadBalancer/RoundRobinTests.cs | 48 +- .../Logging/OcelotDiagnosticListenerTests.cs | 68 +- .../Logging/OcelotLoggerTests.cs | 50 +- .../Middleware/BaseUrlFinderTests.cs | 37 +- .../OcelotPipelineExtensionsTests.cs | 40 +- .../Middleware/OcelotPiplineBuilderTests.cs | 67 +- .../DefinedAggregatorProviderTests.cs | 72 +- .../MultiplexingMiddlewareTests.cs | 57 +- .../ResponseAggregatorFactoryTests.cs | 41 +- .../SimpleJsonResponseAggregatorTests.cs | 101 +- .../UserDefinedResponseAggregatorTests.cs | 90 +- test/Ocelot.UnitTests/Ocelot.UnitTests.csproj | 4 - .../Polly/OcelotBuilderExtensionsTests.cs | 11 +- ...esiliencePipelineDelegatingHandlerTests.cs | 7 +- .../QueryStrings/AddQueriesToRequestTests.cs | 159 +- .../ClaimsToQueryStringMiddlewareTests.cs | 55 +- .../RateLimitingMiddlewareTests.cs | 18 +- .../Repository/HttpDataRepositoryTests.cs | 53 + .../ScopedRequestDataRepositoryTests.cs | 74 - .../Creator/DownstreamRequestCreatorTests.cs | 73 +- ...streamRequestInitialiserMiddlewareTests.cs | 105 +- .../Request/DownstreamRequestTests.cs | 15 +- .../Request/Mapper/RequestMapperTests.cs | 578 +++---- .../Request/Mapper/StreamHttpContentTests.cs | 19 +- .../RequestId/RequestIdMiddlewareTests.cs | 131 +- ...atingHandlerHandlerProviderFactoryTests.cs | 420 +++-- .../Requester/FakeDelegatingHandler.cs | 38 +- .../HttpExceptionToErrorMapperTests.cs | 11 + .../Requester/HttpRequesterMiddlewareTests.cs | 132 +- .../Requester/MessageInvokerPoolTests.cs | 184 +-- .../Requester/QoSFactoryTests.cs | 17 +- .../Requester/TracingHandlerFactoryTests.cs | 5 +- test/Ocelot.UnitTests/Responder/AnyError.cs | 6 +- .../ErrorsToHttpStatusCodeMapperTests.cs | 59 +- .../Responder/HttpContextResponderTests.cs | 36 +- .../Responder/ResponderMiddlewareTests.cs | 63 +- .../Security/IPSecurityPolicyTests.cs | 367 ++--- .../ConfigurationServiceProviderTests.cs | 36 +- .../ServiceDiscoveryProviderFactoryTests.cs | 191 +-- ...viceFabricServiceDiscoveryProviderTests.cs | 45 +- .../ServiceDiscovery/ServiceRegistryTests.cs | 96 +- test/Ocelot.UnitTests/UnitTest.cs | 5 +- test/Ocelot.UnitTests/Usings.cs | 1 - .../WebSockets/MockWebSocket.cs | 36 +- .../WebSocketsProxyMiddlewareTests.cs | 46 +- 153 files changed, 6214 insertions(+), 7713 deletions(-) create mode 100644 test/Ocelot.Testing/StreamExtensions.cs create mode 100644 test/Ocelot.UnitTests/Configuration/ServiceProviderConfigurationCreatorTests.cs delete mode 100644 test/Ocelot.UnitTests/Configuration/ServiceProviderCreatorTests.cs create mode 100644 test/Ocelot.UnitTests/Repository/HttpDataRepositoryTests.cs delete mode 100644 test/Ocelot.UnitTests/Repository/ScopedRequestDataRepositoryTests.cs diff --git a/test/Ocelot.Testing/StreamExtensions.cs b/test/Ocelot.Testing/StreamExtensions.cs new file mode 100644 index 000000000..797aabc1f --- /dev/null +++ b/test/Ocelot.Testing/StreamExtensions.cs @@ -0,0 +1,11 @@ +namespace Ocelot.Testing; + +public static class StreamExtensions +{ + public static string AsString(this Stream stream) + { + using var reader = new StreamReader(stream); + var text = reader.ReadToEnd(); + return text; + } +} diff --git a/test/Ocelot.UnitTests/Administration/OcelotAdministrationBuilderTests.cs b/test/Ocelot.UnitTests/Administration/OcelotAdministrationBuilderTests.cs index 863cbe520..efa6182f0 100644 --- a/test/Ocelot.UnitTests/Administration/OcelotAdministrationBuilderTests.cs +++ b/test/Ocelot.UnitTests/Administration/OcelotAdministrationBuilderTests.cs @@ -36,26 +36,33 @@ private static IWebHostEnvironment GetHostingEnvironment() //keep [Fact] - public void should_set_up_administration_with_identity_server_options() + public void Should_set_up_administration_with_identity_server_options() { - Action options = o => { }; + // Arrange + static void options(JwtBearerOptions o) + { + } - this.Given(x => WhenISetUpOcelotServices()) - .When(x => WhenISetUpAdministration(options)) - .Then(x => ThenAnExceptionIsntThrown()) - .Then(x => ThenTheCorrectAdminPathIsRegitered()) - .BDDfy(); + // Act + WhenISetUpOcelotServices(); + WhenISetUpAdministration(options); + + // Assert + ThenAnExceptionIsntThrown(); + ThenTheCorrectAdminPathIsRegitered(); } //keep [Fact] - public void should_set_up_administration() + public void Should_set_up_administration() { - this.Given(x => WhenISetUpOcelotServices()) - .When(x => WhenISetUpAdministration()) - .Then(x => ThenAnExceptionIsntThrown()) - .Then(x => ThenTheCorrectAdminPathIsRegitered()) - .BDDfy(); + // Arrange, Act + WhenISetUpOcelotServices(); + WhenISetUpAdministration(); + + // Assert + ThenAnExceptionIsntThrown(); + ThenTheCorrectAdminPathIsRegitered(); } private void WhenISetUpAdministration() diff --git a/test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs b/test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs index 6bf7003e2..9f0384113 100644 --- a/test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs @@ -18,7 +18,7 @@ public class AuthenticationMiddlewareTests : UnitTest private readonly Mock _factory; private readonly Mock _logger; private readonly Mock _serviceProvider; - private readonly HttpContext _httpContext; + private readonly DefaultHttpContext _httpContext; private AuthenticationMiddleware _middleware; private RequestDelegate _next; @@ -64,30 +64,33 @@ public void MiddlewareName_Cstor_ReturnsTypeName() [Fact] public void Should_call_next_middleware_if_route_is_not_authenticated() { - var methods = new List { "Get" }; - this.Given(x => GivenTheDownStreamRouteIs(new DownstreamRouteBuilder() - .WithUpstreamHttpMethod(methods) - .Build() - )) - .When(x => WhenICallTheMiddleware()) - .Then(x => ThenTheUserIsAuthenticated()) - .BDDfy(); + // Arrange + GivenTheDownStreamRouteIs(new DownstreamRouteBuilder() + .WithUpstreamHttpMethod(new() { HttpMethods.Get }) + .Build()); + + // Act + WhenICallTheMiddleware(); + + // Assert + ThenTheUserIsAuthenticated(); } [Fact] public void Should_call_next_middleware_if_route_is_using_options_method() { - const string OPTIONS = "OPTIONS"; - var methods = new List { OPTIONS }; - this.Given(x => GivenTheDownStreamRouteIs(new DownstreamRouteBuilder() - .WithUpstreamHttpMethod(methods) - .WithIsAuthenticated(true) - .Build() - )) - .And(x => GivenTheRequestIsUsingMethod(OPTIONS)) - .When(x => WhenICallTheMiddleware()) - .Then(x => ThenTheUserIsAuthenticated()) - .BDDfy(); + // Arrange + GivenTheDownStreamRouteIs(new DownstreamRouteBuilder() + .WithUpstreamHttpMethod(new() { HttpMethods.Options }) + .WithIsAuthenticated(true) + .Build()); + GivenTheRequestIsUsingMethod(HttpMethods.Options); + + // Act + WhenICallTheMiddleware(); + + // Assert + ThenTheUserIsAuthenticated(); } [Theory] @@ -95,74 +98,82 @@ public void Should_call_next_middleware_if_route_is_using_options_method() [InlineData(true)] public void Should_call_next_middleware_if_route_is_using_several_options_authentication_providers(bool isMultipleKeys) { + // Arrange var multipleKeys = new string[] { string.Empty, "Fail", "Test" }; var options = new AuthenticationOptions(null, !isMultipleKeys ? "Test" : null, isMultipleKeys ? multipleKeys : null ); - var methods = new List { "Get" }; - this.Given(x => GivenTheDownStreamRouteIs(new DownstreamRouteBuilder() - .WithAuthenticationOptions(options) - .WithIsAuthenticated(true) - .WithUpstreamHttpMethod(methods) - .Build() - )) - .And(x => GivenTheRequestIsUsingMethod(methods.First())) - .And(x => GivenTheAuthenticationIsFail()) - .And(x => GivenTheAuthenticationIsSuccess()) - .And(x => GivenTheAuthenticationThrowsException()) - .When(x => WhenICallTheMiddleware()) - .Then(x => ThenTheUserIsAuthenticated()) - .BDDfy(); + var methods = new List { HttpMethods.Get }; + GivenTheDownStreamRouteIs(new DownstreamRouteBuilder() + .WithAuthenticationOptions(options) + .WithIsAuthenticated(true) + .WithUpstreamHttpMethod(methods) + .Build()); + GivenTheRequestIsUsingMethod(methods.First()); + GivenTheAuthenticationIsFail(); + GivenTheAuthenticationIsSuccess(); + GivenTheAuthenticationThrowsException(); + + // Act + WhenICallTheMiddleware(); + + // Assert + ThenTheUserIsAuthenticated(); } [Fact] public void Should_provide_backward_compatibility_if_route_has_several_options_authentication_providers() { + // Arrange var options = new AuthenticationOptions(null, "Test", new string[] { string.Empty, "Fail", "Test" } ); - var methods = new List { "Get" }; - this.Given(x => GivenTheDownStreamRouteIs(new DownstreamRouteBuilder() - .WithAuthenticationOptions(options) - .WithIsAuthenticated(true) - .WithUpstreamHttpMethod(methods) - .Build() - )) - .And(x => GivenTheRequestIsUsingMethod(methods.First())) - .And(x => GivenTheAuthenticationIsFail()) - .And(x => GivenTheAuthenticationIsSuccess()) - .And(x => GivenTheAuthenticationThrowsException()) - .When(x => WhenICallTheMiddleware()) - .Then(x => ThenTheUserIsAuthenticated()) - .BDDfy(); + var methods = new List { HttpMethods.Get }; + GivenTheDownStreamRouteIs(new DownstreamRouteBuilder() + .WithAuthenticationOptions(options) + .WithIsAuthenticated(true) + .WithUpstreamHttpMethod(methods) + .Build()); + GivenTheRequestIsUsingMethod(methods.First()); + GivenTheAuthenticationIsFail(); + GivenTheAuthenticationIsSuccess(); + GivenTheAuthenticationThrowsException(); + + // Act + WhenICallTheMiddleware(); + + // Assert + ThenTheUserIsAuthenticated(); } [Fact] public void Should_not_call_next_middleware_and_return_no_result_if_all_multiple_keys_were_failed() { + // Arrange var options = new AuthenticationOptions(null, null, new string[] { string.Empty, "Fail", "Fail", "UnknownScheme" } ); - var methods = new List { "Get" }; + var methods = new List { HttpMethods.Get }; + GivenTheDownStreamRouteIs(new DownstreamRouteBuilder() + .WithAuthenticationOptions(options) + .WithIsAuthenticated(true) + .WithUpstreamHttpMethod(methods) + .Build()); + GivenTheRequestIsUsingMethod(methods.First()); + GivenTheAuthenticationIsFail(); + GivenTheAuthenticationIsSuccess(); + + // Act + WhenICallTheMiddleware(); - this.Given(x => GivenTheDownStreamRouteIs(new DownstreamRouteBuilder() - .WithAuthenticationOptions(options) - .WithIsAuthenticated(true) - .WithUpstreamHttpMethod(methods) - .Build() - )) - .And(x => GivenTheRequestIsUsingMethod(methods.First())) - .And(x => GivenTheAuthenticationIsFail()) - .And(x => GivenTheAuthenticationIsSuccess()) - .When(x => WhenICallTheMiddleware()) - .Then(x => ThenTheUserIsNotAuthenticated()) - .BDDfy(); + // Assert + ThenTheUserIsNotAuthenticated(); _httpContext.User.Identity.IsAuthenticated.ShouldBeFalse(); _logWarningMessages.Count.ShouldBe(1); _logWarningMessages.First().ShouldStartWith("Client has NOT been authenticated for path"); - _httpContext.Items.Errors().First().ShouldBeOfType(typeof(UnauthenticatedError)); + _httpContext.Items.Errors().First().ShouldBeOfType(); } [Theory] @@ -170,6 +181,7 @@ public void Should_not_call_next_middleware_and_return_no_result_if_all_multiple [InlineData(2)] public void Should_not_call_next_middleware_and_return_no_result_if_providers_keys_are_empty(int keysCount) { + // Arrange var emptyKeys = new string[keysCount]; for (int i = 0; i < emptyKeys.Length; i++) { @@ -184,11 +196,14 @@ public void Should_not_call_next_middleware_and_return_no_result_if_providers_ke .WithUpstreamHttpMethod(methods) .WithDownstreamPathTemplate("/" + nameof(Should_not_call_next_middleware_and_return_no_result_if_providers_keys_are_empty)) .Build(); - this.Given(x => GivenTheDownStreamRouteIs(route)) - .And(x => GivenTheRequestIsUsingMethod(methods.First())) - .When(x => WhenICallTheMiddleware()) - .Then(x => ThenTheUserIsNotAuthenticated()) - .BDDfy(); + GivenTheDownStreamRouteIs(route); + GivenTheRequestIsUsingMethod(methods.First()); + + // Act + WhenICallTheMiddleware(); + + // Assert + ThenTheUserIsNotAuthenticated(); _httpContext.User.Identity.IsAuthenticated.ShouldBeFalse(); _logWarningMessages.Count.ShouldBe(2); _logWarningMessages[0].ShouldStartWith($"Impossible to authenticate client for path '/{nameof(Should_not_call_next_middleware_and_return_no_result_if_providers_keys_are_empty)}':"); @@ -196,7 +211,7 @@ public void Should_not_call_next_middleware_and_return_no_result_if_providers_ke _httpContext.Items.Errors().Count(e => e.GetType() == typeof(UnauthenticatedError)).ShouldBe(1); } - private List _logWarningMessages = new(); + private readonly List _logWarningMessages = new(); private void GivenTheAuthenticationIsFail() { @@ -263,13 +278,3 @@ private async void WhenICallTheMiddleware() await _middleware.Invoke(_httpContext); } } - -public static class StreamExtensions -{ - public static string AsString(this Stream stream) - { - using var reader = new StreamReader(stream); - var text = reader.ReadToEnd(); - return text; - } -} diff --git a/test/Ocelot.UnitTests/Authorization/AuthorizationMiddlewareTests.cs b/test/Ocelot.UnitTests/Authorization/AuthorizationMiddlewareTests.cs index 6d915eefa..3cbf3256f 100644 --- a/test/Ocelot.UnitTests/Authorization/AuthorizationMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Authorization/AuthorizationMiddlewareTests.cs @@ -19,7 +19,7 @@ public class AuthorizationMiddlewareTests : UnitTest private readonly Mock _logger; private readonly AuthorizationMiddleware _middleware; private readonly RequestDelegate _next; - private readonly HttpContext _httpContext; + private readonly DefaultHttpContext _httpContext; public AuthorizationMiddlewareTests() { @@ -34,18 +34,23 @@ public AuthorizationMiddlewareTests() } [Fact] - public void should_call_authorization_service() + public async Task Should_call_authorization_service() { - this.Given(x => x.GivenTheDownStreamRouteIs(new List(), + // Arrange + GivenTheDownStreamRouteIs( + new List(), new DownstreamRouteBuilder() .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().Build()) .WithIsAuthorized(true) - .WithUpstreamHttpMethod(new List { "Get" }) - .Build())) - .And(x => x.GivenTheAuthServiceReturns(new OkResponse(true))) - .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.ThenTheAuthServiceIsCalledCorrectly()) - .BDDfy(); + .WithUpstreamHttpMethod(new() { HttpMethods.Get }) + .Build()); + GivenTheAuthServiceReturns(new OkResponse(true)); + + // Act + await WhenICallTheMiddleware(); + + // Assert + ThenTheAuthServiceIsCalledCorrectly(); } private async Task WhenICallTheMiddleware() diff --git a/test/Ocelot.UnitTests/Authorization/ClaimsAuthorizerTests.cs b/test/Ocelot.UnitTests/Authorization/ClaimsAuthorizerTests.cs index 9fcb5dbe9..8d1a02956 100644 --- a/test/Ocelot.UnitTests/Authorization/ClaimsAuthorizerTests.cs +++ b/test/Ocelot.UnitTests/Authorization/ClaimsAuthorizerTests.cs @@ -20,89 +20,109 @@ public ClaimsAuthorizerTests() } [Fact] - public void should_authorize_user() + public void Should_authorize_user() { - this.Given(x => x.GivenAClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new List - { - new("UserType", "registered"), - })))) - .And(x => x.GivenARouteClaimsRequirement(new Dictionary - { - {"UserType", "registered"}, - })) - .When(x => x.WhenICallTheAuthorizer()) - .Then(x => x.ThenTheUserIsAuthorized()) - .BDDfy(); + // Arrange + GivenAClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new List + { + new("UserType", "registered"), + }))); + GivenARouteClaimsRequirement(new Dictionary + { + {"UserType", "registered"}, + }); + + // Act + WhenICallTheAuthorizer(); + + // Assert + ThenTheUserIsAuthorized(); } [Fact] - public void should_authorize_dynamic_user() + public void Should_authorize_dynamic_user() { - this.Given(x => x.GivenAClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new List - { - new("userid", "14"), - })))) - .And(x => x.GivenARouteClaimsRequirement(new Dictionary - { - {"userid", "{userId}"}, - })) - .And(x => x.GivenAPlaceHolderNameAndValueList(new List - { - new("{userId}", "14"), - })) - .When(x => x.WhenICallTheAuthorizer()) - .Then(x => x.ThenTheUserIsAuthorized()) - .BDDfy(); + // Arrange + GivenAClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new List + { + new("userid", "14"), + }))); + GivenARouteClaimsRequirement(new Dictionary + { + {"userid", "{userId}"}, + }); + GivenAPlaceHolderNameAndValueList(new List + { + new("{userId}", "14"), + }); + + // Act + WhenICallTheAuthorizer(); + + // Assert + ThenTheUserIsAuthorized(); } [Fact] - public void should_not_authorize_dynamic_user() + public void Should_not_authorize_dynamic_user() { - this.Given(x => x.GivenAClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new List - { - new("userid", "15"), - })))) - .And(x => x.GivenARouteClaimsRequirement(new Dictionary - { - {"userid", "{userId}"}, - })) - .And(x => x.GivenAPlaceHolderNameAndValueList(new List - { - new("{userId}", "14"), - })) - .When(x => x.WhenICallTheAuthorizer()) - .Then(x => x.ThenTheUserIsntAuthorized()) - .BDDfy(); + // Arrange + GivenAClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new List + { + new("userid", "15"), + }))); + GivenARouteClaimsRequirement(new Dictionary + { + {"userid", "{userId}"}, + }); + GivenAPlaceHolderNameAndValueList(new List + { + new("{userId}", "14"), + }); + + // Act + WhenICallTheAuthorizer(); + + // Assert + ThenTheUserIsntAuthorized(); } [Fact] - public void should_authorize_user_multiple_claims_of_same_type() + public void Should_authorize_user_multiple_claims_of_same_type() { - this.Given(x => x.GivenAClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new List - { - new("UserType", "guest"), - new("UserType", "registered"), - })))) - .And(x => x.GivenARouteClaimsRequirement(new Dictionary - { - {"UserType", "registered"}, - })) - .When(x => x.WhenICallTheAuthorizer()) - .Then(x => x.ThenTheUserIsAuthorized()) - .BDDfy(); + // Arrange + GivenAClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new List + { + new("UserType", "guest"), + new("UserType", "registered"), + }))); + GivenARouteClaimsRequirement(new Dictionary + { + {"UserType", "registered"}, + }); + + // Act + WhenICallTheAuthorizer(); + + // Assert + ThenTheUserIsAuthorized(); } [Fact] - public void should_not_authorize_user() + public void Should_not_authorize_user() { - this.Given(x => x.GivenAClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new List())))) - .And(x => x.GivenARouteClaimsRequirement(new Dictionary - { - { "UserType", "registered" }, - })) - .When(x => x.WhenICallTheAuthorizer()) - .Then(x => x.ThenTheUserIsntAuthorized()) - .BDDfy(); + // Arrange + GivenAClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new List()))); + GivenARouteClaimsRequirement(new Dictionary + { + { "UserType", "registered" }, + }); + + // Act + WhenICallTheAuthorizer(); + + // Assert + ThenTheUserIsntAuthorized(); } private void GivenAClaimsPrincipal(ClaimsPrincipal claimsPrincipal) diff --git a/test/Ocelot.UnitTests/Cache/CacheOptionsCreatorTests.cs b/test/Ocelot.UnitTests/Cache/CacheOptionsCreatorTests.cs index fe34b3787..2e287b1ae 100644 --- a/test/Ocelot.UnitTests/Cache/CacheOptionsCreatorTests.cs +++ b/test/Ocelot.UnitTests/Cache/CacheOptionsCreatorTests.cs @@ -1,4 +1,4 @@ -using Ocelot.Configuration; +using Microsoft.AspNetCore.Http; using Ocelot.Configuration.Creator; using Ocelot.Configuration.File; @@ -6,27 +6,29 @@ namespace Ocelot.UnitTests.Cache; public class CacheOptionsCreatorTests : UnitTest { - private CacheOptions _cacheOptions; - private FileRoute _route; + private readonly CacheOptionsCreator _creator = new(); [Fact] - public void should_create_region() + public void Should_create_region() { + // Arrange var route = new FileRoute { - UpstreamHttpMethod = new List { "Get" }, + UpstreamHttpMethod = new() { HttpMethods.Get }, UpstreamPathTemplate = "/testdummy", }; - this.Given(_ => GivenTheRoute(route)) - .When(_ => WhenICreateTheRegion()) - .Then(_ => ThenTheRegionIs("Gettestdummy")) - .BDDfy(); + // Act + var actual = _creator.Create(route.FileCacheOptions, new FileGlobalConfiguration(), route.UpstreamPathTemplate, route.UpstreamHttpMethod); + + // Assert + actual.Region.ShouldBe($"{HttpMethods.Get}testdummy"); } [Fact] - public void should_use_region() + public void Should_use_region() { + // Arrange var route = new FileRoute { FileCacheOptions = new FileCacheOptions @@ -35,25 +37,10 @@ public void should_use_region() }, }; - this.Given(_ => GivenTheRoute(route)) - .When(_ => WhenICreateTheRegion()) - .Then(_ => ThenTheRegionIs("region")) - .BDDfy(); - } - - private void GivenTheRoute(FileRoute route) - { - _route = route; - } + // Act + var actual = _creator.Create(route.FileCacheOptions, new FileGlobalConfiguration(), route.UpstreamPathTemplate, route.UpstreamHttpMethod); - private void WhenICreateTheRegion() - { - var cacheOptionsCreator = new CacheOptionsCreator(); - _cacheOptions = cacheOptionsCreator.Create(_route.FileCacheOptions, new FileGlobalConfiguration(), _route.UpstreamPathTemplate, _route.UpstreamHttpMethod); - } - - private void ThenTheRegionIs(string expected) - { - _cacheOptions.Region.ShouldBe(expected); + // Assert + actual.Region.ShouldBe("region"); } } diff --git a/test/Ocelot.UnitTests/Cache/DefaultCacheKeyGeneratorTests.cs b/test/Ocelot.UnitTests/Cache/DefaultCacheKeyGeneratorTests.cs index 50c7de6c9..afbb7bb1a 100644 --- a/test/Ocelot.UnitTests/Cache/DefaultCacheKeyGeneratorTests.cs +++ b/test/Ocelot.UnitTests/Cache/DefaultCacheKeyGeneratorTests.cs @@ -1,4 +1,5 @@ -using Ocelot.Cache; +using Microsoft.AspNetCore.Http; +using Ocelot.Cache; using Ocelot.Configuration; using Ocelot.Configuration.Builder; using Ocelot.Request.Middleware; @@ -9,105 +10,97 @@ namespace Ocelot.UnitTests.Cache; public sealed class DefaultCacheKeyGeneratorTests : UnitTest, IDisposable { - private readonly ICacheKeyGenerator _cacheKeyGenerator; + private readonly DefaultCacheKeyGenerator _generator; private readonly HttpRequestMessage _request; - private const string verb = "GET"; + private readonly string verb = HttpMethods.Get; private const string url = "https://some.url/blah?abcd=123"; private const string header = nameof(DefaultCacheKeyGeneratorTests); private const string headerName = "auth"; public DefaultCacheKeyGeneratorTests() { - _cacheKeyGenerator = new DefaultCacheKeyGenerator(); - + _generator = new DefaultCacheKeyGenerator(); _request = new HttpRequestMessage { - Method = new HttpMethod(verb), - RequestUri = new Uri(url), + Method = new(verb), + RequestUri = new(url), }; _request.Headers.Add(headerName, header); } [Fact] - public void should_generate_cache_key_with_request_content() + public async Task Should_generate_cache_key_with_request_content() { + // Arrange const string noHeader = null; - const string content = nameof(should_generate_cache_key_with_request_content); + const string content = nameof(Should_generate_cache_key_with_request_content); var cachekey = MD5Helper.GenerateMd5($"{verb}-{url}-{content}"); - CacheOptions options = new CacheOptions(100, "region", noHeader, true); + var options = new CacheOptions(100, "region", noHeader, true); + var route = GivenDownstreamRoute(options); + _request.Content = new StringContent(content); + + // Act + var generatedCacheKey = await WhenGenerateRequestCacheKey(route); - this.Given(x => x.GivenDownstreamRoute(options)) - .And(x => GivenHasContent(content)) - .When(x => x.WhenGenerateRequestCacheKey()) - .Then(x => x.ThenGeneratedCacheKeyIs(cachekey)) - .BDDfy(); + // Assert + generatedCacheKey.ShouldBe(cachekey); } [Fact] - public void should_generate_cache_key_without_request_content() + public async Task Should_generate_cache_key_without_request_content() { + // Arrange CacheOptions options = null; var cachekey = MD5Helper.GenerateMd5($"{verb}-{url}"); + var route = GivenDownstreamRoute(options); - this.Given(x => x.GivenDownstreamRoute(options)) - .When(x => x.WhenGenerateRequestCacheKey()) - .Then(x => x.ThenGeneratedCacheKeyIs(cachekey)) - .BDDfy(); + // Act + var generatedCacheKey = await WhenGenerateRequestCacheKey(route); + + // Assert + generatedCacheKey.ShouldBe(cachekey); } [Fact] - public void should_generate_cache_key_with_cache_options_header() + public async Task Should_generate_cache_key_with_cache_options_header() { - CacheOptions options = new CacheOptions(100, "region", headerName, false); + // Arrange + var options = new CacheOptions(100, "region", headerName, false); var cachekey = MD5Helper.GenerateMd5($"{verb}-{url}-{header}"); + var route = GivenDownstreamRoute(options); + + // Act + var generatedCacheKey = await WhenGenerateRequestCacheKey(route); - this.Given(x => x.GivenDownstreamRoute(options)) - .When(x => x.WhenGenerateRequestCacheKey()) - .Then(x => x.ThenGeneratedCacheKeyIs(cachekey)) - .BDDfy(); + // Assert + generatedCacheKey.ShouldBe(cachekey); } [Fact] - public void should_generate_cache_key_happy_path() + public async Task Should_generate_cache_key_happy_path() { - const string content = nameof(should_generate_cache_key_happy_path); - CacheOptions options = new CacheOptions(100, "region", headerName, true); + // Arrange + const string content = nameof(Should_generate_cache_key_happy_path); + var options = new CacheOptions(100, "region", headerName, true); var cachekey = MD5Helper.GenerateMd5($"{verb}-{url}-{header}-{content}"); - - this.Given(x => x.GivenDownstreamRoute(options)) - .And(x => GivenHasContent(content)) - .When(x => x.WhenGenerateRequestCacheKey()) - .Then(x => x.ThenGeneratedCacheKeyIs(cachekey)) - .BDDfy(); - } - - private DownstreamRoute _downstreamRoute; - - private void GivenDownstreamRoute(CacheOptions options) - { - _downstreamRoute = new DownstreamRouteBuilder() - .WithKey("key1") - .WithCacheOptions(options) - .Build(); - } - - private void GivenHasContent(string content) - { + var route = GivenDownstreamRoute(options); _request.Content = new StringContent(content); - } - private string _generatedCacheKey; + // Act + var generatedCacheKey = await WhenGenerateRequestCacheKey(route); - private async Task WhenGenerateRequestCacheKey() - { - _generatedCacheKey = await _cacheKeyGenerator.GenerateRequestCacheKey(new DownstreamRequest(_request), _downstreamRoute); + // Assert + generatedCacheKey.ShouldBe(cachekey); } - private void ThenGeneratedCacheKeyIs(string expected) - { - _generatedCacheKey.ShouldBe(expected); - } + private static DownstreamRoute GivenDownstreamRoute(CacheOptions options) => new DownstreamRouteBuilder() + .WithKey("key1") + .WithCacheOptions(options) + .Build(); + + private ValueTask WhenGenerateRequestCacheKey(DownstreamRoute route) + => _generator.GenerateRequestCacheKey(new DownstreamRequest(_request), route); public void Dispose() { @@ -117,12 +110,10 @@ public void Dispose() internal class HttpContentStub : HttpContent { - private readonly string _content; private readonly MemoryStream _stream; public HttpContentStub(string content) { - _content = content; _stream = new MemoryStream(Encoding.ASCII.GetBytes(content)); var field = typeof(HttpContent).GetField("_bufferedContent", BindingFlags.NonPublic | BindingFlags.Instance); diff --git a/test/Ocelot.UnitTests/Cache/DefaultMemoryCacheTests.cs b/test/Ocelot.UnitTests/Cache/DefaultMemoryCacheTests.cs index 2b69d6152..5edbad022 100644 --- a/test/Ocelot.UnitTests/Cache/DefaultMemoryCacheTests.cs +++ b/test/Ocelot.UnitTests/Cache/DefaultMemoryCacheTests.cs @@ -13,66 +13,94 @@ public DefaultMemoryCacheTests() } [Fact] - public void should_cache() + public void Should_cache() { + // Arrange var fake = new Fake(1); _cache.Add("1", fake, TimeSpan.FromSeconds(100), "region"); + + // Act var result = _cache.Get("1", "region"); + + // Assert result.ShouldBe(fake); fake.Value.ShouldBe(1); } [Fact] - public void doesnt_exist() + public void Doesnt_exist() { + // Arrange, Act var result = _cache.Get("1", "region"); + + // Assert result.ShouldBeNull(); } [Fact] - public void should_add_and_delete() + public void Should_add_and_delete() { + // Arrange var fake = new Fake(1); _cache.Add("1", fake, TimeSpan.FromSeconds(100), "region"); var newFake = new Fake(1); _cache.AddAndDelete("1", newFake, TimeSpan.FromSeconds(100), "region"); + + // Act var result = _cache.Get("1", "region"); + + // Assert result.ShouldBe(newFake); newFake.Value.ShouldBe(1); } [Fact] - public void should_clear_region() + public void Should_clear_region() { + // Arrange var fake1 = new Fake(1); var fake2 = new Fake(2); _cache.Add("1", fake1, TimeSpan.FromSeconds(100), "region"); _cache.Add("2", fake2, TimeSpan.FromSeconds(100), "region"); _cache.ClearRegion("region"); + + // Act, Assert var result1 = _cache.Get("1", "region"); result1.ShouldBeNull(); + + // Act, Assert var result2 = _cache.Get("2", "region"); result2.ShouldBeNull(); } [Fact] - public void should_clear_key_if_ttl_expired() + public void Should_clear_key_if_ttl_expired() { + // Arrange var fake = new Fake(1); _cache.Add("1", fake, TimeSpan.FromMilliseconds(50), "region"); Thread.Sleep(200); + + // Act var result = _cache.Get("1", "region"); + + // Assert result.ShouldBeNull(); } [Theory] [InlineData(0)] [InlineData(-1)] - public void should_not_add_to_cache_if_timespan_empty(int ttl) + public void Should_not_add_to_cache_if_timespan_empty(int ttl) { + // Arrange var fake = new Fake(1); _cache.Add("1", fake, TimeSpan.FromSeconds(ttl), "region"); + + // Act var result = _cache.Get("1", "region"); + + // Assert result.ShouldBeNull(); } diff --git a/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs b/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs index ec8698cdc..7ce107907 100644 --- a/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs @@ -19,12 +19,10 @@ public class OutputCacheMiddlewareTests : UnitTest private readonly RequestDelegate _next; private readonly ICacheKeyGenerator _cacheKeyGenerator; private CachedResponse _response; - private readonly HttpContext _httpContext; - private Mock _repo; + private readonly DefaultHttpContext _httpContext; public OutputCacheMiddlewareTests() { - _repo = new Mock(); _httpContext = new DefaultHttpContext(); _cache = new Mock>(); _loggerFactory = new Mock(); @@ -36,50 +34,59 @@ public OutputCacheMiddlewareTests() } [Fact] - public void should_returned_cached_item_when_it_is_in_cache() + public async Task Should_returned_cached_item_when_it_is_in_cache() { + // Arrange var headers = new Dictionary> { { "test", new List { "test" } }, }; - var contentHeaders = new Dictionary> { { "content-type", new List { "application/json" } }, }; - var cachedResponse = new CachedResponse(HttpStatusCode.OK, headers, string.Empty, contentHeaders, "some reason"); - this.Given(x => x.GivenThereIsACachedResponse(cachedResponse)) - .And(x => x.GivenTheDownstreamRouteIs()) - .When(x => x.WhenICallTheMiddlewareAsync()) - .Then(x => x.ThenTheCacheGetIsCalledCorrectly()) - .BDDfy(); + GivenThereIsACachedResponse(cachedResponse); + GivenTheDownstreamRouteIs(); + + // Act + await WhenICallTheMiddlewareAsync(); + + // Assert + ThenTheCacheGetIsCalledCorrectly(); } [Fact] - public void should_returned_cached_item_when_it_is_in_cache_expires_header() + public async Task Should_returned_cached_item_when_it_is_in_cache_expires_header() { + // Arrange var contentHeaders = new Dictionary> { { "Expires", new List { "-1" } }, }; - var cachedResponse = new CachedResponse(HttpStatusCode.OK, new Dictionary>(), string.Empty, contentHeaders, "some reason"); - this.Given(x => x.GivenThereIsACachedResponse(cachedResponse)) - .And(x => x.GivenTheDownstreamRouteIs()) - .When(x => x.WhenICallTheMiddlewareAsync()) - .Then(x => x.ThenTheCacheGetIsCalledCorrectly()) - .BDDfy(); + GivenThereIsACachedResponse(cachedResponse); + GivenTheDownstreamRouteIs(); + + // Act + await WhenICallTheMiddlewareAsync(); + + // Assert + ThenTheCacheGetIsCalledCorrectly(); } [Fact] - public void should_continue_with_pipeline_and_cache_response() + public async Task Should_continue_with_pipeline_and_cache_response() { - this.Given(x => x.GivenResponseIsNotCached(new HttpResponseMessage())) - .And(x => x.GivenTheDownstreamRouteIs()) - .When(x => x.WhenICallTheMiddlewareAsync()) - .Then(x => x.ThenTheCacheAddIsCalledCorrectly()) - .BDDfy(); + // Arrange + GivenResponseIsNotCached(new HttpResponseMessage()); + GivenTheDownstreamRouteIs(); + + // Act + await WhenICallTheMiddlewareAsync(); + + // Assert + ThenTheCacheAddIsCalledCorrectly(); } private async Task WhenICallTheMiddlewareAsync() diff --git a/test/Ocelot.UnitTests/CacheManager/OcelotBuilderExtensionsTests.cs b/test/Ocelot.UnitTests/CacheManager/OcelotBuilderExtensionsTests.cs index 0028444b7..62472c2b5 100644 --- a/test/Ocelot.UnitTests/CacheManager/OcelotBuilderExtensionsTests.cs +++ b/test/Ocelot.UnitTests/CacheManager/OcelotBuilderExtensionsTests.cs @@ -39,13 +39,12 @@ private static IWebHostEnvironment GetHostingEnvironment() } [Fact] - public void should_set_up_cache_manager() + public void Should_set_up_cache_manager() { - this.Given(x => WhenISetUpOcelotServices()) - .When(x => WhenISetUpCacheManager()) - .Then(x => ThenAnExceptionIsntThrown()) - .And(x => OnlyOneVersionOfEachCacheIsRegistered()) - .BDDfy(); + WhenISetUpOcelotServices(); + WhenISetUpCacheManager(); + ThenAnExceptionIsntThrown(); + OnlyOneVersionOfEachCacheIsRegistered(); } private void OnlyOneVersionOfEachCacheIsRegistered() diff --git a/test/Ocelot.UnitTests/CacheManager/OcelotCacheManagerCache.cs b/test/Ocelot.UnitTests/CacheManager/OcelotCacheManagerCache.cs index 5465c3349..99e2cd288 100644 --- a/test/Ocelot.UnitTests/CacheManager/OcelotCacheManagerCache.cs +++ b/test/Ocelot.UnitTests/CacheManager/OcelotCacheManagerCache.cs @@ -20,29 +20,39 @@ public OcelotCacheManagerCache() } [Fact] - public void should_get_from_cache() + public void Should_get_from_cache() { - this.Given(x => x.GivenTheFollowingIsCached("someKey", "someRegion", "someValue")) - .When(x => x.WhenIGetFromTheCache()) - .Then(x => x.ThenTheResultIs("someValue")) - .BDDfy(); + // Arrange + GivenTheFollowingIsCached("someKey", "someRegion", "someValue"); + + // Act + WhenIGetFromTheCache(); + + // Assert + ThenTheResultIs("someValue"); } [Fact] - public void should_add_to_cache() + public void Should_add_to_cache() { - this.When(x => x.WhenIAddToTheCache("someKey", "someValue", TimeSpan.FromSeconds(1))) - .Then(x => x.ThenTheCacheIsCalledCorrectly()) - .BDDfy(); + // Arrange, Act + WhenIAddToTheCache("someKey", "someValue", TimeSpan.FromSeconds(1)); + + // Assert + ThenTheCacheIsCalledCorrectly(); } [Fact] - public void should_delete_key_from_cache() + public void Should_delete_key_from_cache() { - this.Given(_ => GivenTheFollowingRegion("fookey")) - .When(_ => WhenIDeleteTheRegion("fookey")) - .Then(_ => ThenTheRegionIsDeleted("fookey")) - .BDDfy(); + // Arrange + GivenTheFollowingRegion("fookey"); + + // Act + WhenIDeleteTheRegion("fookey"); + + // Assert + ThenTheRegionIsDeleted("fookey"); } private void WhenIDeleteTheRegion(string region) diff --git a/test/Ocelot.UnitTests/CacheManager/OutputCacheMiddlewareRealCacheTests.cs b/test/Ocelot.UnitTests/CacheManager/OutputCacheMiddlewareRealCacheTests.cs index 8ec49b102..3b8d34b82 100644 --- a/test/Ocelot.UnitTests/CacheManager/OutputCacheMiddlewareRealCacheTests.cs +++ b/test/Ocelot.UnitTests/CacheManager/OutputCacheMiddlewareRealCacheTests.cs @@ -13,13 +13,13 @@ namespace Ocelot.UnitTests.CacheManager; public class OutputCacheMiddlewareRealCacheTests : UnitTest { - private readonly IOcelotCache _cacheManager; + private readonly OcelotCacheManagerCache _cacheManager; private readonly ICacheKeyGenerator _cacheKeyGenerator; private readonly OutputCacheMiddleware _middleware; private readonly RequestDelegate _next; private readonly Mock _loggerFactory; private readonly Mock _logger; - private readonly HttpContext _httpContext; + private readonly DefaultHttpContext _httpContext; public OutputCacheMiddlewareRealCacheTests() { @@ -39,20 +39,22 @@ public OutputCacheMiddlewareRealCacheTests() } [Fact] - public void should_cache_content_headers() + public async Task Should_cache_content_headers() { + // Arrange var content = new StringContent("{\"Test\": 1}") { Headers = { ContentType = new MediaTypeHeaderValue("application/json") }, }; - var response = new DownstreamResponse(content, HttpStatusCode.OK, new List>>(), "fooreason"); + GivenResponseIsNotCached(response); + GivenTheDownstreamRouteIs(); + + // Act + await WhenICallTheMiddleware(); - this.Given(x => x.GivenResponseIsNotCached(response)) - .And(x => x.GivenTheDownstreamRouteIs()) - .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.ThenTheContentTypeHeaderIsCached()) - .BDDfy(); + // Assert + ThenTheContentTypeHeaderIsCached(); } private async Task WhenICallTheMiddleware() diff --git a/test/Ocelot.UnitTests/Claims/AddClaimsToRequestTests.cs b/test/Ocelot.UnitTests/Claims/AddClaimsToRequestTests.cs index c57e97b96..7c8bc102e 100644 --- a/test/Ocelot.UnitTests/Claims/AddClaimsToRequestTests.cs +++ b/test/Ocelot.UnitTests/Claims/AddClaimsToRequestTests.cs @@ -24,8 +24,9 @@ public AddClaimsToRequestTests() } [Fact] - public void should_add_claims_to_context() + public void Should_add_claims_to_context() { + // Arrange var context = new DefaultHttpContext { User = new ClaimsPrincipal(new ClaimsIdentity(new List @@ -33,22 +34,24 @@ public void should_add_claims_to_context() new("test", "data"), })), }; + GivenClaimsToThings(new List + { + new("claim-key", string.Empty, string.Empty, 0), + }); + GivenHttpContext(context); + GivenTheClaimParserReturns(new OkResponse("value")); - this.Given( - x => x.GivenClaimsToThings(new List - { - new("claim-key", string.Empty, string.Empty, 0), - })) - .Given(x => x.GivenHttpContext(context)) - .And(x => x.GivenTheClaimParserReturns(new OkResponse("value"))) - .When(x => x.WhenIAddClaimsToTheRequest()) - .Then(x => x.ThenTheResultIsSuccess()) - .BDDfy(); + // Act + WhenIAddClaimsToTheRequest(); + + // Assert + ThenTheResultIsSuccess(); } [Fact] - public void if_claims_exists_should_replace_it() + public void If_claims_exists_should_replace_it() { + // Arrange var context = new DefaultHttpContext { User = new ClaimsPrincipal(new ClaimsIdentity(new List @@ -57,35 +60,39 @@ public void if_claims_exists_should_replace_it() new("new-key", "data"), })), }; + GivenClaimsToThings(new List + { + new("existing-key", "new-key", string.Empty, 0), + }); + GivenHttpContext(context); + GivenTheClaimParserReturns(new OkResponse("value")); - this.Given( - x => x.GivenClaimsToThings(new List - { - new("existing-key", "new-key", string.Empty, 0), - })) - .Given(x => x.GivenHttpContext(context)) - .And(x => x.GivenTheClaimParserReturns(new OkResponse("value"))) - .When(x => x.WhenIAddClaimsToTheRequest()) - .Then(x => x.ThenTheResultIsSuccess()) - .BDDfy(); + // Act + WhenIAddClaimsToTheRequest(); + + // Assert + ThenTheResultIsSuccess(); } [Fact] - public void should_return_error() + public void Should_return_error() { - this.Given( - x => x.GivenClaimsToThings(new List - { - new(string.Empty, string.Empty, string.Empty, 0), - })) - .Given(x => x.GivenHttpContext(new DefaultHttpContext())) - .And(x => x.GivenTheClaimParserReturns(new ErrorResponse(new List - { - new AnyError(), - }))) - .When(x => x.WhenIAddClaimsToTheRequest()) - .Then(x => x.ThenTheResultIsError()) - .BDDfy(); + // Arrange + GivenClaimsToThings(new List + { + new(string.Empty, string.Empty, string.Empty, 0), + }); + GivenHttpContext(new DefaultHttpContext()); + GivenTheClaimParserReturns(new ErrorResponse(new List + { + new AnyError(), + })); + + // Act + WhenIAddClaimsToTheRequest(); + + // Assert + ThenTheResultIsError(); } private void GivenClaimsToThings(List configuration) diff --git a/test/Ocelot.UnitTests/Claims/ClaimsToClaimsMiddlewareTests.cs b/test/Ocelot.UnitTests/Claims/ClaimsToClaimsMiddlewareTests.cs index 8ed247562..d52e8876e 100644 --- a/test/Ocelot.UnitTests/Claims/ClaimsToClaimsMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Claims/ClaimsToClaimsMiddlewareTests.cs @@ -3,6 +3,7 @@ using Ocelot.Claims.Middleware; using Ocelot.Configuration; using Ocelot.Configuration.Builder; +using Ocelot.DownstreamRouteFinder; using Ocelot.DownstreamRouteFinder.UrlMatcher; using Ocelot.Logging; using Ocelot.Middleware; @@ -17,7 +18,7 @@ public class ClaimsToClaimsMiddlewareTests : UnitTest private readonly Mock _logger; private readonly ClaimsToClaimsMiddleware _middleware; private readonly RequestDelegate _next; - private readonly HttpContext _httpContext; + private readonly DefaultHttpContext _httpContext; public ClaimsToClaimsMiddlewareTests() { @@ -31,31 +32,31 @@ public ClaimsToClaimsMiddlewareTests() } [Fact] - public void should_call_claims_to_request_correctly() + public async Task Should_call_claims_to_request_correctly() { - var downstreamRoute = new Ocelot.DownstreamRouteFinder.DownstreamRouteHolder(new List(), + // Arrange + var downstreamRoute = new DownstreamRouteHolder( + new List(), new RouteBuilder() .WithDownstreamRoute(new DownstreamRouteBuilder() .WithDownstreamPathTemplate("any old string") - .WithClaimsToClaims(new List + .WithClaimsToClaims(new() { new("sub", "UserType", "|", 0), }) - .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamHttpMethod(new() { HttpMethods.Get }) .Build()) - .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamHttpMethod(new() { HttpMethods.Get }) .Build()); - this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) - .And(x => x.GivenTheAddClaimsToRequestReturns()) - .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.ThenTheClaimsToRequestIsCalledCorrectly()) - .BDDfy(); - } + GivenTheDownStreamRouteIs(downstreamRoute); + GivenTheAddClaimsToRequestReturns(); - private async Task WhenICallTheMiddleware() - { + // Act await _middleware.Invoke(_httpContext); + + // Assert + ThenTheClaimsToRequestIsCalledCorrectly(); } private void GivenTheDownStreamRouteIs(Ocelot.DownstreamRouteFinder.DownstreamRouteHolder downstreamRoute) diff --git a/test/Ocelot.UnitTests/Configuration/AggregatesCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/AggregatesCreatorTests.cs index fe9d70dbe..710400394 100644 --- a/test/Ocelot.UnitTests/Configuration/AggregatesCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/AggregatesCreatorTests.cs @@ -27,8 +27,9 @@ public AggregatesCreatorTests() } [Fact] - public void should_return_no_aggregates() + public void Should_return_no_aggregates() { + // Arrange var fileConfig = new FileConfiguration { Aggregates = new List @@ -40,19 +41,22 @@ public void should_return_no_aggregates() }, }; var routes = new List(); + GivenThe(fileConfig); + GivenThe(routes); - this.Given(_ => GivenThe(fileConfig)) - .And(_ => GivenThe(routes)) - .When(_ => WhenICreate()) - .Then(_ => TheUtpCreatorIsNotCalled()) - .And(_ => ThenTheResultIsNotNull()) - .And(_ => ThenTheResultIsEmpty()) - .BDDfy(); + // Act + WhenICreate(); + + // Assert + TheUtpCreatorIsNotCalled(); + ThenTheResultIsNotNull(); + ThenTheResultIsEmpty(); } [Fact] - public void should_create_aggregates() + public void Should_create_aggregates() { + // Arrange var fileConfig = new FileConfiguration { Aggregates = new List @@ -75,7 +79,6 @@ public void should_create_aggregates() }, }, }; - var routes = new List { new RouteBuilder().WithDownstreamRoute(new DownstreamRouteBuilder().WithKey("key1").Build()).Build(), @@ -84,14 +87,17 @@ public void should_create_aggregates() new RouteBuilder().WithDownstreamRoute(new DownstreamRouteBuilder().WithKey("key4").Build()).Build(), }; - this.Given(_ => GivenThe(fileConfig)) - .And(_ => GivenThe(routes)) - .And(_ => GivenTheUtpCreatorReturns()) - .And(_ => GivenTheUhtpCreatorReturns()) - .When(_ => WhenICreate()) - .Then(_ => ThenTheUtpCreatorIsCalledCorrectly()) - .And(_ => ThenTheAggregatesAreCreated()) - .BDDfy(); + GivenThe(fileConfig); + GivenThe(routes); + GivenTheUtpCreatorReturns(); + GivenTheUhtpCreatorReturns(); + + // Act + WhenICreate(); + + // Assert + ThenTheUtpCreatorIsCalledCorrectly(); + ThenTheAggregatesAreCreated(); } private void ThenTheAggregatesAreCreated() diff --git a/test/Ocelot.UnitTests/Configuration/AuthenticationOptionsCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/AuthenticationOptionsCreatorTests.cs index d0e8d599e..acbe3cb4b 100644 --- a/test/Ocelot.UnitTests/Configuration/AuthenticationOptionsCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/AuthenticationOptionsCreatorTests.cs @@ -44,9 +44,10 @@ public void Create_OptionsObjIsNull_CreatedSuccessfullyWithEmptyCollections(bool public void Create_OptionsObjIsNotNull_CreatedSuccessfully(bool isAuthenticationProviderKeys) { // Arrange - string authenticationProviderKey = !isAuthenticationProviderKeys ? "Test" : null; - string[] authenticationProviderKeys = isAuthenticationProviderKeys ? - new string[] { "Test #1", "Test #2" } : null; + string authenticationProviderKey = !isAuthenticationProviderKeys + ? "Test" : null; + string[] authenticationProviderKeys = isAuthenticationProviderKeys + ? new string[] { "Test #1", "Test #2" } : null; var fileRoute = new FileRoute() { AuthenticationOptions = new FileAuthenticationOptions diff --git a/test/Ocelot.UnitTests/Configuration/CacheOptionsCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/CacheOptionsCreatorTests.cs index 12ed54cdf..161b20065 100644 --- a/test/Ocelot.UnitTests/Configuration/CacheOptionsCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/CacheOptionsCreatorTests.cs @@ -10,10 +10,14 @@ public class CacheOptionsCreatorTests [Fact] public void ShouldCreateCacheOptions() { + // Arrange var options = FileCacheOptionsFactory(); var cacheOptionsCreator = new CacheOptionsCreator(); + + // Act var result = cacheOptionsCreator.Create(options, null, null, null); + // Assert result.TtlSeconds.ShouldBe(options.TtlSeconds.Value); result.Region.ShouldBe(options.Region); result.Header.ShouldBe(options.Header); @@ -23,11 +27,14 @@ public void ShouldCreateCacheOptions() [Fact] public void ShouldCreateCacheOptionsUsingGlobalConfiguration() { + // Arrange var global = GlobalConfigurationFactory(); - var cacheOptionsCreator = new CacheOptionsCreator(); + + // Act var result = cacheOptionsCreator.Create(new FileCacheOptions(), global, null, null); + // Assert result.TtlSeconds.ShouldBe(global.CacheOptions.TtlSeconds.Value); result.Region.ShouldBe(global.CacheOptions.Region); result.Header.ShouldBe(global.CacheOptions.Header); @@ -37,12 +44,15 @@ public void ShouldCreateCacheOptionsUsingGlobalConfiguration() [Fact] public void RouteCacheOptionsShouldOverrideGlobalConfiguration() { + // Arrange var global = GlobalConfigurationFactory(); var options = FileCacheOptionsFactory(); - var cacheOptionsCreator = new CacheOptionsCreator(); + + // Act var result = cacheOptionsCreator.Create(options, global, null, null); + // Assert result.TtlSeconds.ShouldBe(options.TtlSeconds.Value); result.Region.ShouldBe(options.Region); result.Header.ShouldBe(options.Header); @@ -52,9 +62,13 @@ public void RouteCacheOptionsShouldOverrideGlobalConfiguration() [Fact] public void ShouldCreateCacheOptionsWithDefaults() { + // Arrange var cacheOptionsCreator = new CacheOptionsCreator(); + + // Act var result = cacheOptionsCreator.Create(new FileCacheOptions(), null, "/", new List { "GET" }); + // Assert result.TtlSeconds.ShouldBe(0); result.Region.ShouldBe("GET"); result.Header.ShouldBe(null); @@ -64,15 +78,17 @@ public void ShouldCreateCacheOptionsWithDefaults() [Fact] public void ShouldComputeRegionIfNotProvided() { + // Arrange var global = GlobalConfigurationFactory(); var options = FileCacheOptionsFactory(); - global.CacheOptions.Region = null; options.Region = null; - var cacheOptionsCreator = new CacheOptionsCreator(); + + // Act var result = cacheOptionsCreator.Create(options, global, "/api/values", new List { "GET", "POST" }); + // Assert result.TtlSeconds.ShouldBe(options.TtlSeconds.Value); result.Region.ShouldBe("GETPOSTapivalues"); result.Header.ShouldBe(options.Header); diff --git a/test/Ocelot.UnitTests/Configuration/ChangeTracking/OcelotConfigurationChangeTokenSourceTests.cs b/test/Ocelot.UnitTests/Configuration/ChangeTracking/OcelotConfigurationChangeTokenSourceTests.cs index 523bcc999..06ab0ab76 100644 --- a/test/Ocelot.UnitTests/Configuration/ChangeTracking/OcelotConfigurationChangeTokenSourceTests.cs +++ b/test/Ocelot.UnitTests/Configuration/ChangeTracking/OcelotConfigurationChangeTokenSourceTests.cs @@ -4,7 +4,7 @@ namespace Ocelot.UnitTests.Configuration.ChangeTracking; public class OcelotConfigurationChangeTokenSourceTests : UnitTest { - private readonly IOcelotConfigurationChangeTokenSource _source; + private readonly OcelotConfigurationChangeTokenSource _source; public OcelotConfigurationChangeTokenSourceTests() { @@ -12,20 +12,12 @@ public OcelotConfigurationChangeTokenSourceTests() } [Fact] - public void should_activate_change_token() - { - this.Given(_ => GivenIActivateTheChangeTokenSource()) - .Then(_ => ThenTheChangeTokenShouldBeActivated()) - .BDDfy(); - } - - private void GivenIActivateTheChangeTokenSource() + public void Should_activate_change_token() { + // Arrange, Act _source.Activate(); - } - private void ThenTheChangeTokenShouldBeActivated() - { + // Assert _source.ChangeToken.HasChanged.ShouldBeTrue(); } } diff --git a/test/Ocelot.UnitTests/Configuration/ChangeTracking/OcelotConfigurationChangeTokenTests.cs b/test/Ocelot.UnitTests/Configuration/ChangeTracking/OcelotConfigurationChangeTokenTests.cs index 4963509e5..a2f89388e 100644 --- a/test/Ocelot.UnitTests/Configuration/ChangeTracking/OcelotConfigurationChangeTokenTests.cs +++ b/test/Ocelot.UnitTests/Configuration/ChangeTracking/OcelotConfigurationChangeTokenTests.cs @@ -5,27 +5,35 @@ namespace Ocelot.UnitTests.Configuration.ChangeTracking; public class OcelotConfigurationChangeTokenTests : UnitTest { [Fact] - public void should_call_callback_with_state() + public void Should_call_callback_with_state() { - this.Given(_ => GivenIHaveAChangeToken()) - .And(_ => AndIRegisterACallback()) - .Then(_ => ThenIShouldGetADisposableWrapper()) - .Given(_ => GivenIActivateTheToken()) - .Then(_ => ThenTheCallbackShouldBeCalled()) - .BDDfy(); + // Arrange + GivenIHaveAChangeToken(); + AndIRegisterACallback(); + ThenIShouldGetADisposableWrapper(); + + // Act + GivenIActivateTheToken(); + + // Assert + ThenTheCallbackShouldBeCalled(); } [Fact] - public void should_not_call_callback_if_it_is_disposed() + public void Should_not_call_callback_if_it_is_disposed() { - this.Given(_ => GivenIHaveAChangeToken()) - .And(_ => AndIRegisterACallback()) - .Then(_ => ThenIShouldGetADisposableWrapper()) - .And(_ => GivenIActivateTheToken()) - .And(_ => AndIDisposeTheCallbackWrapper()) - .And(_ => GivenIActivateTheToken()) - .Then(_ => ThenTheCallbackShouldNotBeCalled()) - .BDDfy(); + // Arrange + GivenIHaveAChangeToken(); + AndIRegisterACallback(); + ThenIShouldGetADisposableWrapper(); + + // Act, Assert + GivenIActivateTheToken(); + AndIDisposeTheCallbackWrapper(); + + // Act, Assert + GivenIActivateTheToken(); + ThenTheCallbackShouldNotBeCalled(); } private OcelotConfigurationChangeToken _changeToken; diff --git a/test/Ocelot.UnitTests/Configuration/ClaimToThingConfigurationParserTests.cs b/test/Ocelot.UnitTests/Configuration/ClaimToThingConfigurationParserTests.cs index e56607951..88fabfac1 100644 --- a/test/Ocelot.UnitTests/Configuration/ClaimToThingConfigurationParserTests.cs +++ b/test/Ocelot.UnitTests/Configuration/ClaimToThingConfigurationParserTests.cs @@ -7,105 +7,103 @@ namespace Ocelot.UnitTests.Configuration; public class ClaimToThingConfigurationParserTests : UnitTest { - private Dictionary _dictionary; - private readonly IClaimToThingConfigurationParser _claimToThingConfigurationParser; - private Response _result; + private readonly ClaimToThingConfigurationParser _parser; public ClaimToThingConfigurationParserTests() { - _claimToThingConfigurationParser = new ClaimToThingConfigurationParser(); + _parser = new ClaimToThingConfigurationParser(); } [Fact] - public void returns_no_instructions_error() + public void Returns_no_instructions_error() { - this.Given(x => x.GivenTheDictionaryIs(new Dictionary + // Arrange + var dictionary = new Dictionary { {"CustomerId", string.Empty}, - })) - .When(x => x.WhenICallTheExtractor()) - .Then( - x => - x.ThenAnErrorIsReturned(new ErrorResponse( - new List - { - new NoInstructionsError(">"), - }))) - .BDDfy(); + }; + + // Act + var result = WhenICallTheExtractor(dictionary); + + // Assert + ThenAnErrorIsReturned(result, new ErrorResponse( + new List + { + new NoInstructionsError(">"), + })); } [Fact] - public void returns_no_instructions_not_for_claims_error() + public void Returns_no_instructions_not_for_claims_error() { - this.Given(x => x.GivenTheDictionaryIs(new Dictionary + // Arrange + var dictionary = new Dictionary { {"CustomerId", "Cheese[CustomerId] > value"}, - })) - .When(x => x.WhenICallTheExtractor()) - .Then( - x => - x.ThenAnErrorIsReturned(new ErrorResponse( - new List - { - new InstructionNotForClaimsError(), - }))) - .BDDfy(); + }; + + // Act + var result = WhenICallTheExtractor(dictionary); + + // Assert + ThenAnErrorIsReturned(result, new ErrorResponse(new List + { + new InstructionNotForClaimsError(), + })); } [Fact] - public void can_parse_entry_to_work_out_properties_with_key() + public void Can_parse_entry_to_work_out_properties_with_key() { - this.Given(x => x.GivenTheDictionaryIs(new Dictionary + // Arrange + var dictionary = new Dictionary { {"CustomerId", "Claims[CustomerId] > value"}, - })) - .When(x => x.WhenICallTheExtractor()) - .Then( - x => - x.ThenTheClaimParserPropertiesAreReturned( - new OkResponse( - new ClaimToThing("CustomerId", "CustomerId", string.Empty, 0)))) - .BDDfy(); + }; + + // Act + var result = WhenICallTheExtractor(dictionary); + + // Assert + ThenTheClaimParserPropertiesAreReturned(result, + new OkResponse(new ClaimToThing("CustomerId", "CustomerId", string.Empty, 0))); } [Fact] - public void can_parse_entry_to_work_out_properties_with_key_delimiter_and_index() + public void Can_parse_entry_to_work_out_properties_with_key_delimiter_and_index() { - this.Given(x => x.GivenTheDictionaryIs(new Dictionary + // Arrange + var dictionary = new Dictionary { {"UserId", "Claims[Subject] > value[0] > |"}, - })) - .When(x => x.WhenICallTheExtractor()) - .Then( - x => - x.ThenTheClaimParserPropertiesAreReturned( - new OkResponse( - new ClaimToThing("UserId", "Subject", "|", 0)))) - .BDDfy(); - } + }; - private void ThenAnErrorIsReturned(Response expected) - { - _result.IsError.ShouldBe(expected.IsError); - _result.Errors[0].ShouldBeOfType(expected.Errors[0].GetType()); + // Act + var result = WhenICallTheExtractor(dictionary); + + // Assert + ThenTheClaimParserPropertiesAreReturned(result, + new OkResponse(new ClaimToThing("UserId", "Subject", "|", 0))); } - private void ThenTheClaimParserPropertiesAreReturned(Response expected) + private static void ThenAnErrorIsReturned(Response result, Response expected) { - _result.Data.NewKey.ShouldBe(expected.Data.NewKey); - _result.Data.Delimiter.ShouldBe(expected.Data.Delimiter); - _result.Data.Index.ShouldBe(expected.Data.Index); - _result.IsError.ShouldBe(expected.IsError); + result.IsError.ShouldBe(expected.IsError); + result.Errors[0].ShouldBeOfType(expected.Errors[0].GetType()); } - private void WhenICallTheExtractor() + private static void ThenTheClaimParserPropertiesAreReturned(Response result, Response expected) { - var first = _dictionary.First(); - _result = _claimToThingConfigurationParser.Extract(first.Key, first.Value); + result.Data.NewKey.ShouldBe(expected.Data.NewKey); + result.Data.Delimiter.ShouldBe(expected.Data.Delimiter); + result.Data.Index.ShouldBe(expected.Data.Index); + result.IsError.ShouldBe(expected.IsError); } - private void GivenTheDictionaryIs(Dictionary dictionary) + private Response WhenICallTheExtractor(Dictionary dictionary) { - _dictionary = dictionary; + var first = dictionary.First(); + return _parser.Extract(first.Key, first.Value); } } diff --git a/test/Ocelot.UnitTests/Configuration/ClaimsToThingCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/ClaimsToThingCreatorTests.cs index f3245a713..2606ed404 100644 --- a/test/Ocelot.UnitTests/Configuration/ClaimsToThingCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/ClaimsToThingCreatorTests.cs @@ -28,45 +28,43 @@ public ClaimsToThingCreatorTests() } [Fact] - public void should_return_claims_to_things() + public void Should_return_claims_to_things() { + // Arrange var userInput = new Dictionary { {"CustomerId", "Claims[CustomerId] > value"}, }; + var claimsToThing = new OkResponse(new ClaimToThing("CustomerId", "CustomerId", string.Empty, 0)); + GivenTheFollowingDictionary(userInput); + GivenTheConfigHeaderExtractorReturns(claimsToThing); - var claimsToThing = new OkResponse(new ClaimToThing("CustomerId", "CustomerId", string.Empty, 0)); - - this.Given(x => x.GivenTheFollowingDictionary(userInput)) - .And(x => x.GivenTheConfigHeaderExtractorReturns(claimsToThing)) - .When(x => x.WhenIGetTheThings()) - .Then(x => x.ThenTheConfigParserIsCalledCorrectly()) - .And(x => x.ThenClaimsToThingsAreReturned()) - .BDDfy(); + // Act + WhenIGetTheThings(); + + // Assert + ThenTheConfigParserIsCalledCorrectly(); + ThenClaimsToThingsAreReturned(); } [Fact] - public void should_log_error_if_cannot_parse_claim_to_thing() + public void Should_log_error_if_cannot_parse_claim_to_thing() { + // Arrange var userInput = new Dictionary { {"CustomerId", "Claims[CustomerId] > value"}, }; - var claimsToThing = new ErrorResponse(It.IsAny()); - - this.Given(x => x.GivenTheFollowingDictionary(userInput)) - .And(x => x.GivenTheConfigHeaderExtractorReturns(claimsToThing)) - .When(x => x.WhenIGetTheThings()) - .Then(x => x.ThenTheConfigParserIsCalledCorrectly()) - .And(x => x.ThenNoClaimsToThingsAreReturned()) - .BDDfy(); - } + GivenTheFollowingDictionary(userInput); + GivenTheConfigHeaderExtractorReturns(claimsToThing); - private void ThenTheLoggerIsCalledCorrectly() - { - _logger - .Verify(x => x.LogDebug(It.IsAny), Times.Once); + // Act + WhenIGetTheThings(); + + // Assert + ThenTheConfigParserIsCalledCorrectly(); + ThenNoClaimsToThingsAreReturned(); } private void ThenClaimsToThingsAreReturned() diff --git a/test/Ocelot.UnitTests/Configuration/ConfigurationCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/ConfigurationCreatorTests.cs index 77f745f80..ae4edb01b 100644 --- a/test/Ocelot.UnitTests/Configuration/ConfigurationCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/ConfigurationCreatorTests.cs @@ -37,26 +37,34 @@ public ConfigurationCreatorTests() } [Fact] - public void should_build_configuration_with_no_admin_path() + public void Should_build_configuration_with_no_admin_path() { - this.Given(_ => GivenTheDependenciesAreSetUp()) - .When(_ => WhenICreate()) - .Then(_ => ThenTheDepdenciesAreCalledCorrectly()) - .And(_ => ThenThePropertiesAreSetCorrectly()) - .And(_ => ThenTheAdminPathIsNull()) - .BDDfy(); + // Arrange + GivenTheDependenciesAreSetUp(); + + // Act + WhenICreate(); + + // Assert + ThenTheDepdenciesAreCalledCorrectly(); + ThenThePropertiesAreSetCorrectly(); + ThenTheAdminPathIsNull(); } [Fact] - public void should_build_configuration_with_admin_path() + public void Should_build_configuration_with_admin_path() { - this.Given(_ => GivenTheDependenciesAreSetUp()) - .And(_ => GivenTheAdminPath()) - .When(_ => WhenICreate()) - .Then(_ => ThenTheDepdenciesAreCalledCorrectly()) - .And(_ => ThenThePropertiesAreSetCorrectly()) - .And(_ => ThenTheAdminPathIsSet()) - .BDDfy(); + // Arrange + GivenTheDependenciesAreSetUp(); + GivenTheAdminPath(); + + // Act + WhenICreate(); + + // Assert + ThenTheDepdenciesAreCalledCorrectly(); + ThenThePropertiesAreSetCorrectly(); + ThenTheAdminPathIsSet(); } private void ThenTheAdminPathIsNull() diff --git a/test/Ocelot.UnitTests/Configuration/DefaultMetadataCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/DefaultMetadataCreatorTests.cs index b150c6f3c..65deab007 100644 --- a/test/Ocelot.UnitTests/Configuration/DefaultMetadataCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/DefaultMetadataCreatorTests.cs @@ -7,112 +7,78 @@ namespace Ocelot.UnitTests.Configuration; [Trait("Feat", "738")] public class DefaultMetadataCreatorTests : UnitTest { - private FileGlobalConfiguration _globalConfiguration; - private Dictionary _metadataInRoute; - private MetadataOptions _result; private readonly DefaultMetadataCreator _sut = new(); + private static readonly Dictionary Empty = new(); [Fact] public void Should_return_empty_metadata() { - // Arrange - GivenEmptyMetadataInGlobalConfiguration(); - GivenEmptyMetadataInRoute(); - - // Act - WhenICreate(); + // Arrange, Act + var result = _sut.Create(Empty, new()); // Assert - ThenDownstreamRouteMetadataMustBeEmpty(); + result.Metadata.Keys.ShouldBeEmpty(); } [Fact] public void Should_return_global_metadata() { // Arrange - GivenSomeMetadataInGlobalConfiguration(); - GivenEmptyMetadataInRoute(); + var global = GivenSomeMetadataInGlobalConfiguration(); // Act - WhenICreate(); + var result = _sut.Create(Empty, global); // Assert - ThenDownstreamMetadataMustContain("foo", "bar"); + ThenDownstreamMetadataMustContain(result, "foo", "bar"); } [Fact] public void Should_return_route_metadata() { // Arrange - GivenEmptyMetadataInGlobalConfiguration(); - GivenSomeMetadataInRoute(); + var metadata = GivenSomeMetadataInRoute(); // Act - WhenICreate(); + var result = _sut.Create(metadata, new()); // Assert - ThenDownstreamMetadataMustContain("foo", "baz"); + ThenDownstreamMetadataMustContain(result, "foo", "baz"); } [Fact] public void Should_overwrite_global_metadata() { // Arrange - GivenSomeMetadataInGlobalConfiguration(); - GivenSomeMetadataInRoute(); + var global = GivenSomeMetadataInGlobalConfiguration(); + var metadata = GivenSomeMetadataInRoute(); // Act - WhenICreate(); + var result = _sut.Create(metadata, global); // Assert - ThenDownstreamMetadataMustContain("foo", "baz"); - } - - private void WhenICreate() - { - _result = _sut.Create( _metadataInRoute, _globalConfiguration); - } - - private void GivenEmptyMetadataInGlobalConfiguration() - { - _globalConfiguration = new FileGlobalConfiguration(); + ThenDownstreamMetadataMustContain(result, "foo", "baz"); } - private void GivenSomeMetadataInGlobalConfiguration() + private static FileGlobalConfiguration GivenSomeMetadataInGlobalConfiguration() => new() { - _globalConfiguration = new FileGlobalConfiguration + MetadataOptions = new() { - MetadataOptions = new FileMetadataOptions + Metadata = new Dictionary { - Metadata = new Dictionary - { - ["foo"] = "bar", - }, + ["foo"] = "bar", }, - }; - } + }, + }; - private void GivenEmptyMetadataInRoute() + private static Dictionary GivenSomeMetadataInRoute() => new() { - _metadataInRoute = new Dictionary(); - } - - private void GivenSomeMetadataInRoute() - { - _metadataInRoute = new Dictionary - { - ["foo"] = "baz", - }; - } - - private void ThenDownstreamRouteMetadataMustBeEmpty() - { - _result.Metadata.Keys.ShouldBeEmpty(); - } + ["foo"] = "baz", + }; - private void ThenDownstreamMetadataMustContain(string key, string value) + private static void ThenDownstreamMetadataMustContain(MetadataOptions result, string key, string value) { - _result.Metadata.Keys.ShouldContain(key); - _result.Metadata[key].ShouldBeEquivalentTo(value); + result.Metadata.Keys.ShouldContain(key); + result.Metadata[key].ShouldBeEquivalentTo(value); } } diff --git a/test/Ocelot.UnitTests/Configuration/DiskFileConfigurationRepositoryTests.cs b/test/Ocelot.UnitTests/Configuration/DiskFileConfigurationRepositoryTests.cs index 2823d8f4d..5a37ed05e 100644 --- a/test/Ocelot.UnitTests/Configuration/DiskFileConfigurationRepositoryTests.cs +++ b/test/Ocelot.UnitTests/Configuration/DiskFileConfigurationRepositoryTests.cs @@ -12,7 +12,7 @@ public sealed class DiskFileConfigurationRepositoryTests : FileUnitTest { private readonly Mock _hostingEnvironment; private readonly Mock _changeTokenSource; - private IFileConfigurationRepository _repo; + private DiskFileConfigurationRepository _repo; private FileConfiguration _result; public DiskFileConfigurationRepositoryTests() @@ -36,7 +36,7 @@ public async Task Should_return_file_configuration() GivenTheConfigurationIs(config); // Act - await WhenIGetTheRoutes(); + _result = (await _repo.Get()).Data; // Assert ThenTheFollowingIsReturned(config); @@ -51,7 +51,7 @@ public async Task Should_return_file_configuration_if_environment_name_is_unavai GivenTheConfigurationIs(config); // Act - await WhenIGetTheRoutes(); + _result = (await _repo.Get()).Data; // Assert ThenTheFollowingIsReturned(config); @@ -69,7 +69,7 @@ public async Task Should_set_file_configuration() // Assert ThenTheConfigurationIsStoredAs(config); ThenTheConfigurationJsonIsIndented(config); - AndTheChangeTokenIsActivated(); + _changeTokenSource.Verify(m => m.Activate(), Times.Once); // and the change token is activated } [Fact] @@ -153,7 +153,7 @@ private void ThenTheConfigurationIsStoredAs(FileConfiguration expecteds) } } - private void ThenTheOcelotJsonIsStoredAs(FileInfo ocelotJson, FileConfiguration expecteds) + private static void ThenTheOcelotJsonIsStoredAs(FileInfo ocelotJson, FileConfiguration expecteds) { var actual = File.ReadAllText(ocelotJson.FullName); var expectedText = JsonConvert.SerializeObject(expecteds, Formatting.Indented); @@ -183,12 +183,6 @@ private void ThenTheConfigurationJsonIsIndented(FileConfiguration expecteds, [Ca _files.Add(environmentSpecific); } - private async Task WhenIGetTheRoutes() - { - var response = await _repo.Get(); - _result = response.Data; - } - private void ThenTheFollowingIsReturned(FileConfiguration expecteds) { _result.GlobalConfiguration.RequestIdKey.ShouldBe(expecteds.GlobalConfiguration.RequestIdKey); @@ -212,11 +206,6 @@ private void ThenTheFollowingIsReturned(FileConfiguration expecteds) } } - private void AndTheChangeTokenIsActivated() - { - _changeTokenSource.Verify(m => m.Activate(), Times.Once); - } - private static FileConfiguration FakeFileConfigurationForSet() { var route = GivenRoute("123.12.12.12", "/asdfs/test/{test}"); diff --git a/test/Ocelot.UnitTests/Configuration/DownstreamAddressesCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/DownstreamAddressesCreatorTests.cs index 51fe8f2e5..570c9c8df 100644 --- a/test/Ocelot.UnitTests/Configuration/DownstreamAddressesCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/DownstreamAddressesCreatorTests.cs @@ -6,9 +6,7 @@ namespace Ocelot.UnitTests.Configuration; public class DownstreamAddressesCreatorTests : UnitTest { - public DownstreamAddressesCreator _creator; - private FileRoute _route; - private List _result; + public readonly DownstreamAddressesCreator _creator; public DownstreamAddressesCreatorTests() { @@ -16,93 +14,77 @@ public DownstreamAddressesCreatorTests() } [Fact] - public void should_do_nothing() + public void Should_do_nothing() { + // Arrange var route = new FileRoute(); - var expected = new List(); - this.Given(x => GivenTheFollowingRoute(route)) - .When(x => WhenICreate()) - .Then(x => TheThenFollowingIsReturned(expected)) - .BDDfy(); + // Act + var result = _creator.Create(route); + + // Assert + result.TheThenFollowingIsReturned(expected); } [Fact] - public void should_create_downstream_addresses_from_old_downstream_path_and_port() + public void Should_create_downstream_addresses_from_old_downstream_path_and_port() { + // Arrange var route = new FileRoute { DownstreamHostAndPorts = new List { - new() - { - Host = "test", - Port = 80, - }, + new("test", 80), }, }; - var expected = new List { new("test", 80), }; - this.Given(x => GivenTheFollowingRoute(route)) - .When(x => WhenICreate()) - .Then(x => TheThenFollowingIsReturned(expected)) - .BDDfy(); + // Act + var result = _creator.Create(route); + + // Assert + result.TheThenFollowingIsReturned(expected); } [Fact] - public void should_create_downstream_addresses_from_downstream_host_and_ports() + public void Should_create_downstream_addresses_from_downstream_host_and_ports() { + // Arrange var route = new FileRoute { DownstreamHostAndPorts = new List { - new() - { - Host = "test", - Port = 80, - }, - new() - { - Host = "west", - Port = 443, - }, + new("test", 80), + new("west", 443), }, }; - var expected = new List { new("test", 80), new("west", 443), }; - this.Given(x => GivenTheFollowingRoute(route)) - .When(x => WhenICreate()) - .Then(x => TheThenFollowingIsReturned(expected)) - .BDDfy(); - } - - private void GivenTheFollowingRoute(FileRoute route) - { - _route = route; - } + // Act + var result = _creator.Create(route); - private void WhenICreate() - { - _result = _creator.Create(_route); + // Assert + result.TheThenFollowingIsReturned(expected); } +} - private void TheThenFollowingIsReturned(List expecteds) +internal static class ListOfDownstreamHostAndPortExtensions +{ + public static void TheThenFollowingIsReturned(this List actual, List expecteds) { - _result.Count.ShouldBe(expecteds.Count); + actual.Count.ShouldBe(expecteds.Count); - for (var i = 0; i < _result.Count; i++) + for (var i = 0; i < actual.Count; i++) { - var result = _result[i]; + var result = actual[i]; var expected = expecteds[i]; result.Host.ShouldBe(expected.Host); diff --git a/test/Ocelot.UnitTests/Configuration/DownstreamRouteExtensionsTests.cs b/test/Ocelot.UnitTests/Configuration/DownstreamRouteExtensionsTests.cs index 0c3b3bcc3..b7b49b080 100644 --- a/test/Ocelot.UnitTests/Configuration/DownstreamRouteExtensionsTests.cs +++ b/test/Ocelot.UnitTests/Configuration/DownstreamRouteExtensionsTests.cs @@ -161,10 +161,7 @@ public void Should_throw_error_when_invalid_json() // Act //Assert - Assert.Throws(() => - { - _ = _downstreamRoute.GetMetadata>(key); - }); + Assert.Throws(() => _ = _downstreamRoute.GetMetadata>(key)); } [Fact] @@ -238,10 +235,7 @@ public void Should_throw_error_when_invalid_number() // Act // Assert - Assert.Throws(() => - { - _ = _downstreamRoute.GetMetadata(key); - }); + Assert.Throws(() => _ = _downstreamRoute.GetMetadata(key)); } [Theory] diff --git a/test/Ocelot.UnitTests/Configuration/DynamicsCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/DynamicsCreatorTests.cs index 1f20e69f9..3e25eaf1c 100644 --- a/test/Ocelot.UnitTests/Configuration/DynamicsCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/DynamicsCreatorTests.cs @@ -33,23 +33,26 @@ public DynamicsCreatorTests() public void Should_return_nothing() { // Arrange - var fileConfig = new FileConfiguration(); - GivenThe(fileConfig); + _fileConfig = new FileConfiguration(); // Act - WhenICreate(); + _result = _creator.Create(_fileConfig); // Assert - ThenNothingIsReturned(); - ThenTheRloCreatorIsNotCalled(); - ThenTheMetadataCreatorIsNotCalled(); + _result.Count.ShouldBe(0); + + // Assert: then the RloCreator is not called + _rloCreator.Verify(x => x.Create(It.IsAny(), It.IsAny()), Times.Never); + + // Assert: then the metadata creator is not called + _metadataCreator.Verify(x => x.Create(It.IsAny>(), It.IsAny()), Times.Never); } [Fact] public void Should_return_routes() { // Arrange - var fileConfig = new FileConfiguration + _fileConfig = new FileConfiguration { DynamicRoutes = new() { @@ -57,14 +60,13 @@ public void Should_return_routes() GivenDynamicRoute("2", true, "2.0", "foo", "baz"), }, }; - GivenThe(fileConfig); GivenTheRloCreatorReturns(); GivenTheVersionCreatorReturns(); GivenTheVersionPolicyCreatorReturns(); GivenTheMetadataCreatorReturns(); // Act - WhenICreate(); + _result = _creator.Create(_fileConfig); // Assert ThenTheRoutesAreReturned(); @@ -73,8 +75,7 @@ public void Should_return_routes() ThenTheMetadataCreatorIsCalledCorrectly(); } - private FileDynamicRoute GivenDynamicRoute(string serviceName, bool enableRateLimiting, - string downstreamHttpVersion, string key, string value) => new() + private static FileDynamicRoute GivenDynamicRoute(string serviceName, bool enableRateLimiting, string downstreamHttpVersion, string key, string value) => new() { ServiceName = serviceName, RateLimitRule = new FileRateLimitRule @@ -160,29 +161,4 @@ private void GivenTheRloCreatorReturns() .Returns(_rlo1) .Returns(_rlo2); } - - private void ThenTheRloCreatorIsNotCalled() - { - _rloCreator.Verify(x => x.Create(It.IsAny(), It.IsAny()), Times.Never); - } - - private void ThenTheMetadataCreatorIsNotCalled() - { - _metadataCreator.Verify(x => x.Create(It.IsAny>(), It.IsAny()), Times.Never); - } - - private void ThenNothingIsReturned() - { - _result.Count.ShouldBe(0); - } - - private void WhenICreate() - { - _result = _creator.Create(_fileConfig); - } - - private void GivenThe(FileConfiguration fileConfig) - { - _fileConfig = fileConfig; - } } diff --git a/test/Ocelot.UnitTests/Configuration/FileConfigurationPollerTests.cs b/test/Ocelot.UnitTests/Configuration/FileConfigurationPollerTests.cs index 150a5088c..5c8fae323 100644 --- a/test/Ocelot.UnitTests/Configuration/FileConfigurationPollerTests.cs +++ b/test/Ocelot.UnitTests/Configuration/FileConfigurationPollerTests.cs @@ -9,7 +9,7 @@ namespace Ocelot.UnitTests.Configuration; -public class FileConfigurationPollerTests : UnitTest, IDisposable +public sealed class FileConfigurationPollerTests : UnitTest, IDisposable { private readonly FileConfigurationPoller _poller; private readonly Mock _factory; @@ -38,16 +38,19 @@ public FileConfigurationPollerTests() } [Fact] - public void should_start() + public void Should_start() { - this.Given(x => GivenPollerHasStarted()) - .Given(x => ThenTheSetterIsCalled(_fileConfig, 1)) - .BDDfy(); + // Arrange, Act + _poller.StartAsync(CancellationToken.None); + + // Assert + ThenTheSetterIsCalled(_fileConfig, 1); } [Fact] - public void should_call_setter_when_gets_new_config() + public void Should_call_setter_when_gets_new_config() { + // Arrange var newConfig = new FileConfiguration { Routes = new List @@ -56,24 +59,24 @@ public void should_call_setter_when_gets_new_config() { DownstreamHostAndPorts = new List { - new() - { - Host = "test", - }, + new("test", 80), }, }, }, }; - this.Given(x => GivenPollerHasStarted()) - .Given(x => WhenTheConfigIsChanged(newConfig, 0)) - .Then(x => ThenTheSetterIsCalledAtLeast(newConfig, 1)) - .BDDfy(); + // Act + _poller.StartAsync(CancellationToken.None); + + // Assert + WhenTheConfigIsChanged(newConfig, 0); + ThenTheSetterIsCalledAtLeast(newConfig, 1); } [Fact] - public void should_not_poll_if_already_polling() + public void Should_not_poll_if_already_polling() { + // Arrange var newConfig = new FileConfiguration { Routes = new List @@ -82,24 +85,24 @@ public void should_not_poll_if_already_polling() { DownstreamHostAndPorts = new List { - new() - { - Host = "test", - }, + new("test", 80), }, }, }, }; - this.Given(x => GivenPollerHasStarted()) - .Given(x => WhenTheConfigIsChanged(newConfig, 10)) - .Then(x => ThenTheSetterIsCalled(newConfig, 1)) - .BDDfy(); + // Act + _poller.StartAsync(CancellationToken.None); + + // Assert + WhenTheConfigIsChanged(newConfig, 10); + ThenTheSetterIsCalled(newConfig, 1); } [Fact] - public void should_do_nothing_if_call_to_provider_fails() + public void Should_do_nothing_if_call_to_provider_fails() { + // Arrange var newConfig = new FileConfiguration { Routes = new List @@ -108,31 +111,25 @@ public void should_do_nothing_if_call_to_provider_fails() { DownstreamHostAndPorts = new List { - new() - { - Host = "test", - }, + new("test", 80), }, }, }, }; - this.Given(x => GivenPollerHasStarted()) - .Given(x => WhenProviderErrors()) - .Then(x => ThenTheSetterIsCalled(newConfig, 0)) - .BDDfy(); - } + // Act + _poller.StartAsync(CancellationToken.None); + WhenProviderErrors(); - [Fact] - public void should_dispose_cleanly_without_starting() - { - this.When(x => WhenPollerIsDisposed()) - .BDDfy(); + // Assert + ThenTheSetterIsCalled(newConfig, 0); } - private void GivenPollerHasStarted() + [Fact] + public void Should_dispose_cleanly_without_starting() { - _poller.StartAsync(CancellationToken.None); + // Arrange, Act, Assert + _poller.Dispose(); // when poller is disposed } private void WhenProviderErrors() @@ -150,11 +147,6 @@ private void WhenTheConfigIsChanged(FileConfiguration newConfig, int delay) .ReturnsAsync(new OkResponse(newConfig)); } - private void WhenPollerIsDisposed() - { - _poller.Dispose(); - } - private void ThenTheSetterIsCalled(FileConfiguration fileConfig, int times) { var result = WaitFor(4000).Until(() => diff --git a/test/Ocelot.UnitTests/Configuration/FileConfigurationSetterTests.cs b/test/Ocelot.UnitTests/Configuration/FileConfigurationSetterTests.cs index 59d3940dc..2cc96f648 100644 --- a/test/Ocelot.UnitTests/Configuration/FileConfigurationSetterTests.cs +++ b/test/Ocelot.UnitTests/Configuration/FileConfigurationSetterTests.cs @@ -28,9 +28,10 @@ public FileConfigurationSetterTests() } [Fact] - public void should_set_configuration() + public async Task Should_set_configuration() { - var fileConfig = new FileConfiguration(); + // Arrange + _fileConfiguration = new FileConfiguration(); var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); var config = new InternalConfiguration( new List(), @@ -43,38 +44,43 @@ public void should_set_configuration() new HttpHandlerOptionsBuilder().Build(), new Version("1.1"), HttpVersionPolicy.RequestVersionOrLower); + GivenTheRepoReturns(new OkResponse()); + GivenTheCreatorReturns(new OkResponse(config)); - this.Given(x => GivenTheFollowingConfiguration(fileConfig)) - .And(x => GivenTheRepoReturns(new OkResponse())) - .And(x => GivenTheCreatorReturns(new OkResponse(config))) - .When(x => WhenISetTheConfiguration()) - .Then(x => ThenTheConfigurationRepositoryIsCalledCorrectly()) - .BDDfy(); + // Act + _result = await _configSetter.Set(_fileConfiguration); + + // Assert + ThenTheConfigurationRepositoryIsCalledCorrectly(); } [Fact] - public void should_return_error_if_unable_to_set_file_configuration() + public async Task Should_return_error_if_unable_to_set_file_configuration() { - var fileConfig = new FileConfiguration(); + // Arrange + _fileConfiguration = new FileConfiguration(); + GivenTheRepoReturns(new ErrorResponse(It.IsAny())); - this.Given(x => GivenTheFollowingConfiguration(fileConfig)) - .And(x => GivenTheRepoReturns(new ErrorResponse(It.IsAny()))) - .When(x => WhenISetTheConfiguration()) - .And(x => ThenAnErrorResponseIsReturned()) - .BDDfy(); + // Act + _result = await _configSetter.Set(_fileConfiguration); + + // Assert + _result.ShouldBeOfType(); } [Fact] - public void should_return_error_if_unable_to_set_ocelot_configuration() + public async Task Should_return_error_if_unable_to_set_ocelot_configuration() { - var fileConfig = new FileConfiguration(); + // Arrange + _fileConfiguration = new FileConfiguration(); + GivenTheRepoReturns(new OkResponse()); + GivenTheCreatorReturns(new ErrorResponse(It.IsAny())); - this.Given(x => GivenTheFollowingConfiguration(fileConfig)) - .And(x => GivenTheRepoReturns(new OkResponse())) - .And(x => GivenTheCreatorReturns(new ErrorResponse(It.IsAny()))) - .When(x => WhenISetTheConfiguration()) - .And(x => ThenAnErrorResponseIsReturned()) - .BDDfy(); + // Act + _result = await _configSetter.Set(_fileConfiguration); + + // Assert + _result.ShouldBeOfType(); } private void GivenTheRepoReturns(Response response) @@ -84,11 +90,6 @@ private void GivenTheRepoReturns(Response response) .ReturnsAsync(response); } - private void ThenAnErrorResponseIsReturned() - { - _result.ShouldBeOfType(); - } - private void GivenTheCreatorReturns(Response configuration) { _configuration = configuration; @@ -97,16 +98,6 @@ private void GivenTheCreatorReturns(Response configurati .ReturnsAsync(_configuration); } - private void GivenTheFollowingConfiguration(FileConfiguration fileConfiguration) - { - _fileConfiguration = fileConfiguration; - } - - private async Task WhenISetTheConfiguration() - { - _result = await _configSetter.Set(_fileConfiguration); - } - private void ThenTheConfigurationRepositoryIsCalledCorrectly() { _configRepo.Verify(x => x.AddOrReplace(_configuration.Data), Times.Once); diff --git a/test/Ocelot.UnitTests/Configuration/FileInternalConfigurationCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/FileInternalConfigurationCreatorTests.cs index eb19be6c0..f132881f5 100644 --- a/test/Ocelot.UnitTests/Configuration/FileInternalConfigurationCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/FileInternalConfigurationCreatorTests.cs @@ -36,28 +36,32 @@ public FileInternalConfigurationCreatorTests() } [Fact] - public void should_return_validation_error() + public async Task Should_return_validation_error() { - var fileConfiguration = new FileConfiguration(); + // Arrange + _fileConfiguration = new FileConfiguration(); + GivenTheValidationFails(); - this.Given(_ => GivenThe(fileConfiguration)) - .And(_ => GivenTheValidationFails()) - .When(_ => WhenICreate()) - .Then(_ => ThenAnErrorIsReturned()) - .BDDfy(); + // Act + _result = await _creator.Create(_fileConfiguration); + + // Assert + _result.IsError.ShouldBeTrue(); } [Fact] - public void should_return_internal_configuration() + public async Task Should_return_internal_configuration() { - var fileConfiguration = new FileConfiguration(); - - this.Given(_ => GivenThe(fileConfiguration)) - .And(_ => GivenTheValidationSucceeds()) - .And(_ => GivenTheDependenciesAreSetUp()) - .When(_ => WhenICreate()) - .Then(_ => ThenTheDependenciesAreCalledCorrectly()) - .BDDfy(); + // Arrange + _fileConfiguration = new FileConfiguration(); + GivenTheValidationSucceeds(); + GivenTheDependenciesAreSetUp(); + + // Act + _result = await _creator.Create(_fileConfiguration); + + // Assert + ThenTheDependenciesAreCalledCorrectly(); } private void ThenTheDependenciesAreCalledCorrectly() @@ -94,25 +98,10 @@ private void GivenTheValidationSucceeds() _validator.Setup(x => x.IsValid(It.IsAny())).ReturnsAsync(response); } - private void ThenAnErrorIsReturned() - { - _result.IsError.ShouldBeTrue(); - } - - private async Task WhenICreate() - { - _result = await _creator.Create(_fileConfiguration); - } - private void GivenTheValidationFails() { var error = new ConfigurationValidationResult(true, new List { new AnyError() }); var response = new OkResponse(error); _validator.Setup(x => x.IsValid(It.IsAny())).ReturnsAsync(response); } - - private void GivenThe(FileConfiguration fileConfiguration) - { - _fileConfiguration = fileConfiguration; - } } diff --git a/test/Ocelot.UnitTests/Configuration/FileModels/FileQoSOptionsTests.cs b/test/Ocelot.UnitTests/Configuration/FileModels/FileQoSOptionsTests.cs index 003e1123f..519334e67 100644 --- a/test/Ocelot.UnitTests/Configuration/FileModels/FileQoSOptionsTests.cs +++ b/test/Ocelot.UnitTests/Configuration/FileModels/FileQoSOptionsTests.cs @@ -4,6 +4,7 @@ namespace Ocelot.UnitTests.Configuration.FileModels; public class FileQoSOptionsTests { + [Trait("Bug", "1833")] [Fact(DisplayName = "1833: Default constructor must assign zero to the TimeoutValue property")] public void Cstor_Default_AssignedZeroToTimeoutValue() { diff --git a/test/Ocelot.UnitTests/Configuration/HashCreationTests.cs b/test/Ocelot.UnitTests/Configuration/HashCreationTests.cs index 2755266b8..3761e3e0e 100644 --- a/test/Ocelot.UnitTests/Configuration/HashCreationTests.cs +++ b/test/Ocelot.UnitTests/Configuration/HashCreationTests.cs @@ -6,19 +6,15 @@ namespace Ocelot.UnitTests.Configuration; public class HashCreationTests { [Fact] - public void should_create_hash_and_salt() + public void Should_create_hash_and_salt() { var password = "secret"; - var salt = new byte[128 / 8]; - using (var rng = RandomNumberGenerator.Create()) - { - rng.GetBytes(salt); - } + using var rng = RandomNumberGenerator.Create(); + rng.GetBytes(salt); var storedSalt = Convert.ToBase64String(salt); - var storedHash = Convert.ToBase64String(KeyDerivation.Pbkdf2( password: password, salt: salt, diff --git a/test/Ocelot.UnitTests/Configuration/HeaderFindAndReplaceCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/HeaderFindAndReplaceCreatorTests.cs index 1aba01298..ec36d37f3 100644 --- a/test/Ocelot.UnitTests/Configuration/HeaderFindAndReplaceCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/HeaderFindAndReplaceCreatorTests.cs @@ -27,9 +27,10 @@ public HeaderFindAndReplaceCreatorTests() } [Fact] - public void should_create() + public void Should_create() { - var route = new FileRoute + // Arrange + _route = new FileRoute { UpstreamHeaderTransform = new Dictionary { @@ -42,75 +43,76 @@ public void should_create() {"Bop", "e, r"}, }, }; - var upstream = new List { new("Test", "Test", "Chicken", 0), new("Moop", "o", "a", 0), }; - var downstream = new List { new("Pop", "West", "East", 0), new("Bop", "e", "r", 0), }; - this.Given(x => GivenTheRoute(route)) - .When(x => WhenICreate()) - .Then(x => ThenTheFollowingUpstreamIsReturned(upstream)) - .Then(x => ThenTheFollowingDownstreamIsReturned(downstream)) - .BDDfy(); + // Act + _result = _creator.Create(_route); + + // Assert + ThenTheFollowingUpstreamIsReturned(upstream); + ThenTheFollowingDownstreamIsReturned(downstream); } [Fact] - public void should_create_with_add_headers_to_request() + public void Should_create_with_add_headers_to_request() { + // Arrange const string key = "X-Forwarded-For"; const string value = "{RemoteIpAddress}"; - - var route = new FileRoute + _route = new FileRoute { UpstreamHeaderTransform = new Dictionary { {key, value}, }, }; - var expected = new AddHeader(key, value); - this.Given(x => GivenTheRoute(route)) - .When(x => WhenICreate()) - .Then(x => ThenTheFollowingAddHeaderToUpstreamIsReturned(expected)) - .BDDfy(); + // Act + _result = _creator.Create(_route); + + // Assert + ThenTheFollowingAddHeaderToUpstreamIsReturned(expected); } [Fact] - public void should_use_base_url_placeholder() + public void Should_use_base_url_placeholder() { - var route = new FileRoute + // Arrange + _route = new FileRoute { DownstreamHeaderTransform = new Dictionary { {"Location", "http://www.bbc.co.uk/, {BaseUrl}"}, }, }; - var downstream = new List { new("Location", "http://www.bbc.co.uk/", "http://ocelot.com/", 0), }; + GivenThePlaceholderIs("http://ocelot.com/"); - this.Given(x => GivenTheRoute(route)) - .And(x => GivenThePlaceholderIs("http://ocelot.com/")) - .When(x => WhenICreate()) - .Then(x => ThenTheFollowingDownstreamIsReturned(downstream)) - .BDDfy(); + // Act + _result = _creator.Create(_route); + + // Assert + ThenTheFollowingDownstreamIsReturned(downstream); } [Fact] - public void should_log_errors_and_not_add_headers() + public void Should_log_errors_and_not_add_headers() { - var route = new FileRoute + // Arrange + _route = new FileRoute { DownstreamHeaderTransform = new Dictionary { @@ -121,17 +123,17 @@ public void should_log_errors_and_not_add_headers() {"Location", "http://www.bbc.co.uk/, {BaseUrl}"}, }, }; - var expected = new List(); + GivenTheBaseUrlErrors(); + + // Act + _result = _creator.Create(_route); - this.Given(x => GivenTheRoute(route)) - .And(x => GivenTheBaseUrlErrors()) - .When(x => WhenICreate()) - .Then(x => ThenTheFollowingDownstreamIsReturned(expected)) - .And(x => ThenTheFollowingUpstreamIsReturned(expected)) - .And(x => ThenTheLoggerIsCalledCorrectly("Unable to add DownstreamHeaderTransform Location: http://www.bbc.co.uk/, {BaseUrl}")) - .And(x => ThenTheLoggerIsCalledCorrectly("Unable to add UpstreamHeaderTransform Location: http://www.bbc.co.uk/, {BaseUrl}")) - .BDDfy(); + // Assert + ThenTheFollowingDownstreamIsReturned(expected); + ThenTheFollowingUpstreamIsReturned(expected); + ThenTheLoggerIsCalledCorrectly("Unable to add DownstreamHeaderTransform Location: http://www.bbc.co.uk/, {BaseUrl}"); + ThenTheLoggerIsCalledCorrectly("Unable to add UpstreamHeaderTransform Location: http://www.bbc.co.uk/, {BaseUrl}"); } private void ThenTheLoggerIsCalledCorrectly(string message) @@ -140,107 +142,112 @@ private void ThenTheLoggerIsCalledCorrectly(string message) } [Fact] - public void should_use_base_url_partial_placeholder() + public void Should_use_base_url_partial_placeholder() { - var route = new FileRoute + // Arrange + _route = new FileRoute { DownstreamHeaderTransform = new Dictionary { {"Location", "http://www.bbc.co.uk/pay, {BaseUrl}pay"}, }, }; - var downstream = new List { new("Location", "http://www.bbc.co.uk/pay", "http://ocelot.com/pay", 0), }; + GivenThePlaceholderIs("http://ocelot.com/"); + + // Act + _result = _creator.Create(_route); - this.Given(x => GivenTheRoute(route)) - .And(x => GivenThePlaceholderIs("http://ocelot.com/")) - .When(x => WhenICreate()) - .Then(x => ThenTheFollowingDownstreamIsReturned(downstream)) - .BDDfy(); + // Assert + ThenTheFollowingDownstreamIsReturned(downstream); } [Fact] - public void should_map_with_partial_placeholder_in_the_middle() + public void Should_map_with_partial_placeholder_in_the_middle() { - var route = new FileRoute + // Arrange + _route = new FileRoute { DownstreamHeaderTransform = new Dictionary { {"Host-Next", "www.bbc.co.uk, subdomain.{Host}/path"}, }, }; - var expected = new List { new("Host-Next", "www.bbc.co.uk", "subdomain.ocelot.next/path", 0), }; + GivenThePlaceholderIs("ocelot.next"); - this.Given(x => GivenTheRoute(route)) - .And(x => GivenThePlaceholderIs("ocelot.next")) - .When(x => WhenICreate()) - .Then(x => ThenTheFollowingDownstreamIsReturned(expected)) - .BDDfy(); + // Act + _result = _creator.Create(_route); + + // Assert + ThenTheFollowingDownstreamIsReturned(expected); } [Fact] - public void should_add_trace_id_header() + public void Should_add_trace_id_header() { - var route = new FileRoute + // Arrange + _route = new FileRoute { DownstreamHeaderTransform = new Dictionary { {"Trace-Id", "{TraceId}"}, }, }; - var expected = new AddHeader("Trace-Id", "{TraceId}"); + GivenThePlaceholderIs("http://ocelot.com/"); + + // Act + _result = _creator.Create(_route); - this.Given(x => GivenTheRoute(route)) - .And(x => GivenThePlaceholderIs("http://ocelot.com/")) - .When(x => WhenICreate()) - .Then(x => ThenTheFollowingAddHeaderToDownstreamIsReturned(expected)) - .BDDfy(); + // Assert + ThenTheFollowingAddHeaderToDownstreamIsReturned(expected); } [Fact] - public void should_add_downstream_header_as_is_when_no_replacement_is_given() + public void Should_add_downstream_header_as_is_when_no_replacement_is_given() { - var route = new FileRoute + // Arrange + _route = new FileRoute { DownstreamHeaderTransform = new Dictionary { {"X-Custom-Header", "Value"}, }, }; - var expected = new AddHeader("X-Custom-Header", "Value"); - this.Given(x => GivenTheRoute(route)) - .And(x => WhenICreate()) - .Then(x => x.ThenTheFollowingAddHeaderToDownstreamIsReturned(expected)) - .BDDfy(); + // Act + _result = _creator.Create(_route); + + // Assert + ThenTheFollowingAddHeaderToDownstreamIsReturned(expected); } [Fact] - public void should_add_upstream_header_as_is_when_no_replacement_is_given() + public void Should_add_upstream_header_as_is_when_no_replacement_is_given() { - var route = new FileRoute + // Arrange + _route = new FileRoute { UpstreamHeaderTransform = new Dictionary { {"X-Custom-Header", "Value"}, }, }; - var expected = new AddHeader("X-Custom-Header", "Value"); - this.Given(x => GivenTheRoute(route)) - .And(x => WhenICreate()) - .Then(x => x.ThenTheFollowingAddHeaderToUpstreamIsReturned(expected)) - .BDDfy(); + // Act + _result = _creator.Create(_route); + + // Assert + ThenTheFollowingAddHeaderToUpstreamIsReturned(expected); } private void GivenThePlaceholderIs(string placeholderValue) @@ -280,16 +287,6 @@ private void ThenTheFollowingDownstreamIsReturned(List dow } } - private void GivenTheRoute(FileRoute route) - { - _route = route; - } - - private void WhenICreate() - { - _result = _creator.Create(_route); - } - private void ThenTheFollowingUpstreamIsReturned(List expecteds) { _result.Upstream.Count.ShouldBe(expecteds.Count); diff --git a/test/Ocelot.UnitTests/Configuration/HttpHandlerOptionsCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/HttpHandlerOptionsCreatorTests.cs index 7460e34da..bb264efb9 100644 --- a/test/Ocelot.UnitTests/Configuration/HttpHandlerOptionsCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/HttpHandlerOptionsCreatorTests.cs @@ -9,7 +9,7 @@ namespace Ocelot.UnitTests.Configuration; public class HttpHandlerOptionsCreatorTests : UnitTest { - private IHttpHandlerOptionsCreator _httpHandlerOptionsCreator; + private HttpHandlerOptionsCreator _creator; private FileRoute _fileRoute; private HttpHandlerOptions _httpHandlerOptions; private IServiceProvider _serviceProvider; @@ -19,64 +19,69 @@ public HttpHandlerOptionsCreatorTests() { _serviceCollection = new ServiceCollection(); _serviceProvider = _serviceCollection.BuildServiceProvider(true); - _httpHandlerOptionsCreator = new HttpHandlerOptionsCreator(_serviceProvider); + _creator = new HttpHandlerOptionsCreator(_serviceProvider); } [Fact] - public void should_not_use_tracing_if_fake_tracer_registered() + public void Should_not_use_tracing_if_fake_tracer_registered() { - var fileRoute = new FileRoute + // Arrange + _fileRoute = new FileRoute { HttpHandlerOptions = new FileHttpHandlerOptions { UseTracing = true, }, }; - var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue, DefaultPooledConnectionLifeTime); - this.Given(x => GivenTheFollowing(fileRoute)) - .When(x => WhenICreateHttpHandlerOptions()) - .Then(x => ThenTheFollowingOptionsReturned(expectedOptions)) - .BDDfy(); + // Act + _httpHandlerOptions = _creator.Create(_fileRoute.HttpHandlerOptions); + + // Assert + ThenTheFollowingOptionsReturned(expectedOptions); } [Fact] - public void should_use_tracing_if_real_tracer_registered() + public void Should_use_tracing_if_real_tracer_registered() { - var fileRoute = new FileRoute + // Arrange + _fileRoute = new FileRoute { HttpHandlerOptions = new FileHttpHandlerOptions { UseTracing = true, }, }; - var expectedOptions = new HttpHandlerOptions(false, false, true, true, int.MaxValue, DefaultPooledConnectionLifeTime); + GivenARealTracer(); - this.Given(x => GivenTheFollowing(fileRoute)) - .And(x => GivenARealTracer()) - .When(x => WhenICreateHttpHandlerOptions()) - .Then(x => ThenTheFollowingOptionsReturned(expectedOptions)) - .BDDfy(); + // Act + _httpHandlerOptions = _creator.Create(_fileRoute.HttpHandlerOptions); + + // Assert + ThenTheFollowingOptionsReturned(expectedOptions); } [Fact] - public void should_create_options_with_useCookie_false_and_allowAutoRedirect_true_as_default() + public void Should_create_options_with_useCookie_false_and_allowAutoRedirect_true_as_default() { - var fileRoute = new FileRoute(); + // Arrange + _fileRoute = new FileRoute(); var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue, DefaultPooledConnectionLifeTime); - this.Given(x => GivenTheFollowing(fileRoute)) - .When(x => WhenICreateHttpHandlerOptions()) - .Then(x => ThenTheFollowingOptionsReturned(expectedOptions)) - .BDDfy(); + // Act + _httpHandlerOptions = _creator.Create(_fileRoute.HttpHandlerOptions); + + // Assert + ThenTheFollowingOptionsReturned(expectedOptions); } [Fact] - public void should_create_options_with_specified_useCookie_and_allowAutoRedirect() + public void Should_create_options_with_specified_useCookie_and_allowAutoRedirect() { - var fileRoute = new FileRoute + // Arrange + _fileRoute = new FileRoute { HttpHandlerOptions = new FileHttpHandlerOptions { @@ -85,54 +90,57 @@ public void should_create_options_with_specified_useCookie_and_allowAutoRedirect UseTracing = false, }, }; - var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue, DefaultPooledConnectionLifeTime); - this.Given(x => GivenTheFollowing(fileRoute)) - .When(x => WhenICreateHttpHandlerOptions()) - .Then(x => ThenTheFollowingOptionsReturned(expectedOptions)) - .BDDfy(); + // Act + _httpHandlerOptions = _creator.Create(_fileRoute.HttpHandlerOptions); + + // Assert + ThenTheFollowingOptionsReturned(expectedOptions); } [Fact] - public void should_create_options_with_useproxy_true_as_default() + public void Should_create_options_with_useproxy_true_as_default() { - var fileRoute = new FileRoute + // Arrange + _fileRoute = new FileRoute { HttpHandlerOptions = new FileHttpHandlerOptions(), }; - var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue, DefaultPooledConnectionLifeTime); - this.Given(x => GivenTheFollowing(fileRoute)) - .When(x => WhenICreateHttpHandlerOptions()) - .Then(x => ThenTheFollowingOptionsReturned(expectedOptions)) - .BDDfy(); + // Act + _httpHandlerOptions = _creator.Create(_fileRoute.HttpHandlerOptions); + + // Assert + ThenTheFollowingOptionsReturned(expectedOptions); } [Fact] - public void should_create_options_with_specified_useproxy() + public void Should_create_options_with_specified_useproxy() { - var fileRoute = new FileRoute + // Arrange + _fileRoute = new FileRoute { HttpHandlerOptions = new FileHttpHandlerOptions { UseProxy = false, }, }; - var expectedOptions = new HttpHandlerOptions(false, false, false, false, int.MaxValue, DefaultPooledConnectionLifeTime); - this.Given(x => GivenTheFollowing(fileRoute)) - .When(x => WhenICreateHttpHandlerOptions()) - .Then(x => ThenTheFollowingOptionsReturned(expectedOptions)) - .BDDfy(); + // Act + _httpHandlerOptions = _creator.Create(_fileRoute.HttpHandlerOptions); + + // Assert + ThenTheFollowingOptionsReturned(expectedOptions); } [Fact] - public void should_create_options_with_specified_MaxConnectionsPerServer() + public void Should_create_options_with_specified_MaxConnectionsPerServer() { - var fileRoute = new FileRoute + // Arrange + _fileRoute = new FileRoute { HttpHandlerOptions = new FileHttpHandlerOptions { @@ -142,16 +150,18 @@ public void should_create_options_with_specified_MaxConnectionsPerServer() var expectedOptions = new HttpHandlerOptions(false, false, false, true, 10, DefaultPooledConnectionLifeTime); - this.Given(x => GivenTheFollowing(fileRoute)) - .When(x => WhenICreateHttpHandlerOptions()) - .Then(x => ThenTheFollowingOptionsReturned(expectedOptions)) - .BDDfy(); + // Act + _httpHandlerOptions = _creator.Create(_fileRoute.HttpHandlerOptions); + + // Assert + ThenTheFollowingOptionsReturned(expectedOptions); } [Fact] - public void should_create_options_fixing_specified_MaxConnectionsPerServer_range() + public void Should_create_options_fixing_specified_MaxConnectionsPerServer_range() { - var fileRoute = new FileRoute + // Arrange + _fileRoute = new FileRoute { HttpHandlerOptions = new FileHttpHandlerOptions { @@ -161,39 +171,31 @@ public void should_create_options_fixing_specified_MaxConnectionsPerServer_range var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue, DefaultPooledConnectionLifeTime); - this.Given(x => GivenTheFollowing(fileRoute)) - .When(x => WhenICreateHttpHandlerOptions()) - .Then(x => ThenTheFollowingOptionsReturned(expectedOptions)) - .BDDfy(); + // Act + _httpHandlerOptions = _creator.Create(_fileRoute.HttpHandlerOptions); + + // Assert + ThenTheFollowingOptionsReturned(expectedOptions); } [Fact] - public void should_create_options_fixing_specified_MaxConnectionsPerServer_range_when_zero() + public void Should_create_options_fixing_specified_MaxConnectionsPerServer_range_when_zero() { - var fileRoute = new FileRoute + // Arrange + _fileRoute = new FileRoute { HttpHandlerOptions = new FileHttpHandlerOptions { MaxConnectionsPerServer = 0, }, }; - var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue, DefaultPooledConnectionLifeTime); - this.Given(x => GivenTheFollowing(fileRoute)) - .When(x => WhenICreateHttpHandlerOptions()) - .Then(x => ThenTheFollowingOptionsReturned(expectedOptions)) - .BDDfy(); - } + // Act + _httpHandlerOptions = _creator.Create(_fileRoute.HttpHandlerOptions); - private void GivenTheFollowing(FileRoute fileRoute) - { - _fileRoute = fileRoute; - } - - private void WhenICreateHttpHandlerOptions() - { - _httpHandlerOptions = _httpHandlerOptionsCreator.Create(_fileRoute.HttpHandlerOptions); + // Assert + ThenTheFollowingOptionsReturned(expectedOptions); } private void ThenTheFollowingOptionsReturned(HttpHandlerOptions expected) @@ -208,10 +210,9 @@ private void ThenTheFollowingOptionsReturned(HttpHandlerOptions expected) private void GivenARealTracer() { - var tracer = new FakeTracer(); _serviceCollection.AddSingleton(); _serviceProvider = _serviceCollection.BuildServiceProvider(true); - _httpHandlerOptionsCreator = new HttpHandlerOptionsCreator(_serviceProvider); + _creator = new HttpHandlerOptionsCreator(_serviceProvider); } /// diff --git a/test/Ocelot.UnitTests/Configuration/HttpVersionPolicyCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/HttpVersionPolicyCreatorTests.cs index 813752d60..964cbb826 100644 --- a/test/Ocelot.UnitTests/Configuration/HttpVersionPolicyCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/HttpVersionPolicyCreatorTests.cs @@ -5,11 +5,10 @@ namespace Ocelot.UnitTests.Configuration; [Trait("Feat", "1672")] public sealed class HttpVersionPolicyCreatorTests : UnitTest { - private readonly HttpVersionPolicyCreator _creator; + private readonly HttpVersionPolicyCreator _creator = new(); public HttpVersionPolicyCreatorTests() { - _creator = new HttpVersionPolicyCreator(); } [Theory] diff --git a/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs b/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs index dc1b45db2..ed85feb71 100644 --- a/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs +++ b/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs @@ -22,58 +22,31 @@ public InMemoryConfigurationRepositoryTests() } [Fact] - public void can_add_config() + public void Can_add_config() { - this.Given(x => x.GivenTheConfigurationIs(new FakeConfig("initial", "adminath"))) - .When(x => x.WhenIAddOrReplaceTheConfig()) - .Then(x => x.ThenNoErrorsAreReturned()) - .And(x => AndTheChangeTokenIsActivated()) - .BDDfy(); - } - - [Fact] - public void can_get_config() - { - this.Given(x => x.GivenThereIsASavedConfiguration()) - .When(x => x.WhenIGetTheConfiguration()) - .Then(x => x.ThenTheConfigurationIsReturned()) - .BDDfy(); - } + // Arrange + _config = new FakeConfig("initial", "adminath"); - private void ThenTheConfigurationIsReturned() - { - _getResult.Data.Routes[0].DownstreamRoute[0].DownstreamPathTemplate.Value.ShouldBe("initial"); - } - - private void WhenIGetTheConfiguration() - { - _getResult = _repo.Get(); - } - - private void GivenThereIsASavedConfiguration() - { - GivenTheConfigurationIs(new FakeConfig("initial", "adminath")); - WhenIAddOrReplaceTheConfig(); - } + // Act + _result = _repo.AddOrReplace(_config); - private void GivenTheConfigurationIs(IInternalConfiguration config) - { - _config = config; + // Assert + _result.IsError.ShouldBeFalse(); + _changeTokenSource.Verify(m => m.Activate(), Times.Once); } - private void WhenIAddOrReplaceTheConfig() + [Fact] + public void Can_get_config() { + // Arrange + _config = new FakeConfig("initial", "adminath"); _result = _repo.AddOrReplace(_config); - } - private void ThenNoErrorsAreReturned() - { - _result.IsError.ShouldBeFalse(); - } + // Act + _getResult = _repo.Get(); - private void AndTheChangeTokenIsActivated() - { - _changeTokenSource.Verify(m => m.Activate(), Times.Once); + // Assert + _getResult.Data.Routes[0].DownstreamRoute[0].DownstreamPathTemplate.Value.ShouldBe("initial"); } private class FakeConfig : IInternalConfiguration @@ -106,9 +79,7 @@ public List Routes } public string AdministrationPath { get; } - public ServiceProviderConfiguration ServiceProviderConfiguration => throw new NotImplementedException(); - public string RequestId { get; } public LoadBalancerOptions LoadBalancerOptions { get; } public string DownstreamScheme { get; } diff --git a/test/Ocelot.UnitTests/Configuration/LoadBalancerOptionsCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/LoadBalancerOptionsCreatorTests.cs index 6302cba73..fe831c278 100644 --- a/test/Ocelot.UnitTests/Configuration/LoadBalancerOptionsCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/LoadBalancerOptionsCreatorTests.cs @@ -1,4 +1,3 @@ -using Ocelot.Configuration; using Ocelot.Configuration.Creator; using Ocelot.Configuration.File; @@ -6,45 +5,25 @@ namespace Ocelot.UnitTests.Configuration; public class LoadBalancerOptionsCreatorTests : UnitTest { - private readonly ILoadBalancerOptionsCreator _creator; - private FileLoadBalancerOptions _fileLoadBalancerOptions; - private LoadBalancerOptions _result; - - public LoadBalancerOptionsCreatorTests() - { - _creator = new LoadBalancerOptionsCreator(); - } + private readonly LoadBalancerOptionsCreator _creator = new(); [Fact] - public void should_create() + public void Should_create() { - var fileLoadBalancerOptions = new FileLoadBalancerOptions + // Arrange + var options = new FileLoadBalancerOptions { Type = "test", Key = "west", Expiry = 1, }; - this.Given(_ => GivenThe(fileLoadBalancerOptions)) - .When(_ => WhenICreate()) - .Then(_ => ThenTheOptionsAreCreated(fileLoadBalancerOptions)) - .BDDfy(); - } + // Act + var result = _creator.Create(options); - private void ThenTheOptionsAreCreated(FileLoadBalancerOptions expected) - { - _result.Type.ShouldBe(expected.Type); - _result.Key.ShouldBe(expected.Key); - _result.ExpiryInMs.ShouldBe(expected.Expiry); - } - - private void WhenICreate() - { - _result = _creator.Create(_fileLoadBalancerOptions); - } - - private void GivenThe(FileLoadBalancerOptions fileLoadBalancerOptions) - { - _fileLoadBalancerOptions = fileLoadBalancerOptions; + // Assert + result.Type.ShouldBe(options.Type); + result.Key.ShouldBe(options.Key); + result.ExpiryInMs.ShouldBe(options.Expiry); } } diff --git a/test/Ocelot.UnitTests/Configuration/QoSOptionsCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/QoSOptionsCreatorTests.cs index 95223ce66..1e2dd7052 100644 --- a/test/Ocelot.UnitTests/Configuration/QoSOptionsCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/QoSOptionsCreatorTests.cs @@ -1,4 +1,3 @@ -using Ocelot.Configuration; using Ocelot.Configuration.Builder; using Ocelot.Configuration.Creator; using Ocelot.Configuration.File; @@ -7,18 +6,12 @@ namespace Ocelot.UnitTests.Configuration; public class QoSOptionsCreatorTests : UnitTest { - private readonly QoSOptionsCreator _creator; - private FileRoute _fileRoute; - private QoSOptions _result; - - public QoSOptionsCreatorTests() - { - _creator = new QoSOptionsCreator(); - } + private readonly QoSOptionsCreator _creator = new(); [Fact] - public void should_create_qos_options() + public void Should_create_qos_options() { + // Arrange var route = new FileRoute { QoSOptions = new FileQoSOptions @@ -34,26 +27,12 @@ public void should_create_qos_options() .WithTimeoutValue(1) .Build(); - this.Given(x => x.GivenTheFollowingRoute(route)) - .When(x => x.WhenICreate()) - .Then(x => x.ThenTheFollowingIsReturned(expected)) - .BDDfy(); - } + // Act + var result = _creator.Create(route.QoSOptions); - private void GivenTheFollowingRoute(FileRoute fileRoute) - { - _fileRoute = fileRoute; - } - - private void WhenICreate() - { - _result = _creator.Create(_fileRoute.QoSOptions); - } - - private void ThenTheFollowingIsReturned(QoSOptions expected) - { - _result.DurationOfBreak.ShouldBe(expected.DurationOfBreak); - _result.ExceptionsAllowedBeforeBreaking.ShouldBe(expected.ExceptionsAllowedBeforeBreaking); - _result.TimeoutValue.ShouldBe(expected.TimeoutValue); + // Assert + result.DurationOfBreak.ShouldBe(expected.DurationOfBreak); + result.ExceptionsAllowedBeforeBreaking.ShouldBe(expected.ExceptionsAllowedBeforeBreaking); + result.TimeoutValue.ShouldBe(expected.TimeoutValue); } } diff --git a/test/Ocelot.UnitTests/Configuration/RateLimitOptionsCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/RateLimitOptionsCreatorTests.cs index 262b3e83a..e6f3112aa 100644 --- a/test/Ocelot.UnitTests/Configuration/RateLimitOptionsCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/RateLimitOptionsCreatorTests.cs @@ -7,20 +7,12 @@ namespace Ocelot.UnitTests.Configuration; public class RateLimitOptionsCreatorTests : UnitTest { - private FileRoute _fileRoute; - private FileGlobalConfiguration _fileGlobalConfig; - private bool _enabled; - private readonly RateLimitOptionsCreator _creator; - private RateLimitOptions _result; - - public RateLimitOptionsCreatorTests() - { - _creator = new RateLimitOptionsCreator(); - } + private readonly RateLimitOptionsCreator _creator = new(); [Fact] - public void should_create_rate_limit_options() + public void Should_create_rate_limit_options() { + // Arrange var fileRoute = new FileRoute { RateLimitOptions = new FileRateLimitRule @@ -55,49 +47,22 @@ public void should_create_rate_limit_options() fileRoute.RateLimitOptions.PeriodTimespan, fileRoute.RateLimitOptions.Limit)) .Build(); - - _enabled = false; - - this.Given(x => x.GivenTheFollowingFileRoute(fileRoute)) - .And(x => x.GivenTheFollowingFileGlobalConfig(fileGlobalConfig)) - .And(x => x.GivenRateLimitingIsEnabled()) - .When(x => x.WhenICreate()) - .Then(x => x.ThenTheFollowingIsReturned(expected)) - .BDDfy(); - } - - private void GivenTheFollowingFileRoute(FileRoute fileRoute) - { - _fileRoute = fileRoute; - } + bool enabled = true; - private void GivenTheFollowingFileGlobalConfig(FileGlobalConfiguration fileGlobalConfig) - { - _fileGlobalConfig = fileGlobalConfig; - } - - private void GivenRateLimitingIsEnabled() - { - _enabled = true; - } - - private void WhenICreate() - { - _result = _creator.Create(_fileRoute.RateLimitOptions, _fileGlobalConfig); - } + // Act + var result = _creator.Create(fileRoute.RateLimitOptions, fileGlobalConfig); - private void ThenTheFollowingIsReturned(RateLimitOptions expected) - { - _enabled.ShouldBeTrue(); - _result.ClientIdHeader.ShouldBe(expected.ClientIdHeader); - _result.ClientWhitelist.ShouldBe(expected.ClientWhitelist); - _result.DisableRateLimitHeaders.ShouldBe(expected.DisableRateLimitHeaders); - _result.EnableRateLimiting.ShouldBe(expected.EnableRateLimiting); - _result.HttpStatusCode.ShouldBe(expected.HttpStatusCode); - _result.QuotaExceededMessage.ShouldBe(expected.QuotaExceededMessage); - _result.RateLimitCounterPrefix.ShouldBe(expected.RateLimitCounterPrefix); - _result.RateLimitRule.Limit.ShouldBe(expected.RateLimitRule.Limit); - _result.RateLimitRule.Period.ShouldBe(expected.RateLimitRule.Period); - TimeSpan.FromSeconds(_result.RateLimitRule.PeriodTimespan).Ticks.ShouldBe(TimeSpan.FromSeconds(expected.RateLimitRule.PeriodTimespan).Ticks); + // Assert + enabled.ShouldBeTrue(); + result.ClientIdHeader.ShouldBe(expected.ClientIdHeader); + result.ClientWhitelist.ShouldBe(expected.ClientWhitelist); + result.DisableRateLimitHeaders.ShouldBe(expected.DisableRateLimitHeaders); + result.EnableRateLimiting.ShouldBe(expected.EnableRateLimiting); + result.HttpStatusCode.ShouldBe(expected.HttpStatusCode); + result.QuotaExceededMessage.ShouldBe(expected.QuotaExceededMessage); + result.RateLimitCounterPrefix.ShouldBe(expected.RateLimitCounterPrefix); + result.RateLimitRule.Limit.ShouldBe(expected.RateLimitRule.Limit); + result.RateLimitRule.Period.ShouldBe(expected.RateLimitRule.Period); + TimeSpan.FromSeconds(result.RateLimitRule.PeriodTimespan).Ticks.ShouldBe(TimeSpan.FromSeconds(expected.RateLimitRule.PeriodTimespan).Ticks); } } diff --git a/test/Ocelot.UnitTests/Configuration/RequestIdKeyCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/RequestIdKeyCreatorTests.cs index 86713da60..f0c00304e 100644 --- a/test/Ocelot.UnitTests/Configuration/RequestIdKeyCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/RequestIdKeyCreatorTests.cs @@ -5,51 +5,46 @@ namespace Ocelot.UnitTests.Configuration; public class RequestIdKeyCreatorTests : UnitTest { - private FileRoute _fileRoute; - private FileGlobalConfiguration _fileGlobalConfig; - private string _result; - private readonly RequestIdKeyCreator _creator; - - public RequestIdKeyCreatorTests() - { - _creator = new RequestIdKeyCreator(); - } + private readonly RequestIdKeyCreator _creator = new(); [Fact] - public void should_use_global_configuration() + public void Should_use_global_configuration() { + // Arrange var route = new FileRoute(); var globalConfig = new FileGlobalConfiguration { RequestIdKey = "cheese", }; - this.Given(x => x.GivenTheFollowingRoute(route)) - .And(x => x.GivenTheFollowingGlobalConfig(globalConfig)) - .When(x => x.WhenICreate()) - .Then(x => x.ThenTheFollowingIsReturned("cheese")) - .BDDfy(); + // Act + var result = _creator.Create(route, globalConfig); + + // Assert + result.ShouldBe("cheese"); } [Fact] - public void should_use_re_route_specific() + public void Should_use_re_route_specific() { + // Arrange var route = new FileRoute { RequestIdKey = "cheese", }; var globalConfig = new FileGlobalConfiguration(); - this.Given(x => x.GivenTheFollowingRoute(route)) - .And(x => x.GivenTheFollowingGlobalConfig(globalConfig)) - .When(x => x.WhenICreate()) - .Then(x => x.ThenTheFollowingIsReturned("cheese")) - .BDDfy(); + // Act + var result = _creator.Create(route, globalConfig); + + // Assert + result.ShouldBe("cheese"); } [Fact] - public void should_use_re_route_over_global_specific() + public void Should_use_re_route_over_global_specific() { + // Arrange var route = new FileRoute { RequestIdKey = "cheese", @@ -59,30 +54,10 @@ public void should_use_re_route_over_global_specific() RequestIdKey = "test", }; - this.Given(x => x.GivenTheFollowingRoute(route)) - .And(x => x.GivenTheFollowingGlobalConfig(globalConfig)) - .When(x => x.WhenICreate()) - .Then(x => x.ThenTheFollowingIsReturned("cheese")) - .BDDfy(); - } - - private void GivenTheFollowingRoute(FileRoute fileRoute) - { - _fileRoute = fileRoute; - } - - private void GivenTheFollowingGlobalConfig(FileGlobalConfiguration globalConfig) - { - _fileGlobalConfig = globalConfig; - } - - private void WhenICreate() - { - _result = _creator.Create(_fileRoute, _fileGlobalConfig); - } + // Act + var result = _creator.Create(route, globalConfig); - private void ThenTheFollowingIsReturned(string expected) - { - _result.ShouldBe(expected); + // Assert + result.ShouldBe("cheese"); } } diff --git a/test/Ocelot.UnitTests/Configuration/RouteKeyCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/RouteKeyCreatorTests.cs index 7afdf37d2..8e7ce4d20 100644 --- a/test/Ocelot.UnitTests/Configuration/RouteKeyCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/RouteKeyCreatorTests.cs @@ -6,18 +6,12 @@ namespace Ocelot.UnitTests.Configuration; public class RouteKeyCreatorTests : UnitTest { - private readonly RouteKeyCreator _creator; - private FileRoute _route; - private string _result; - - public RouteKeyCreatorTests() - { - _creator = new RouteKeyCreator(); - } + private readonly RouteKeyCreator _creator = new(); [Fact] public void Should_return_sticky_session_key() { + // Arrange var route = new FileRoute { LoadBalancerOptions = new FileLoadBalancerOptions @@ -27,15 +21,17 @@ public void Should_return_sticky_session_key() }, }; - this.Given(_ => GivenThe(route)) - .When(_ => WhenICreate()) - .Then(_ => ThenTheResultIs("CookieStickySessions:testy")) - .BDDfy(); + // Act + var result = _creator.Create(route); + + // Assert + result.ShouldBe("CookieStickySessions:testy"); } [Fact] public void Should_return_route_key() { + // Arrange var route = new FileRoute { UpstreamPathTemplate = "/api/product", @@ -47,15 +43,17 @@ public void Should_return_route_key() }, }; - this.Given(_ => GivenThe(route)) - .When(_ => WhenICreate()) - .Then(_ => ThenTheResultIs("GET,POST,PUT|/api/product|no-host|localhost:8080,localhost:4430|no-svc-ns|no-svc-name|no-lb-type|no-lb-key")) - .BDDfy(); + // Act + var result = _creator.Create(route); + + // Assert + result.ShouldBe("GET,POST,PUT|/api/product|no-host|localhost:8080,localhost:4430|no-svc-ns|no-svc-name|no-lb-type|no-lb-key"); } [Fact] public void Should_return_route_key_with_upstream_host() { + // Arrange var route = new FileRoute { UpstreamHost = "my-host", @@ -68,15 +66,17 @@ public void Should_return_route_key_with_upstream_host() }, }; - this.Given(_ => GivenThe(route)) - .When(_ => WhenICreate()) - .Then(_ => ThenTheResultIs("GET,POST,PUT|/api/product|my-host|localhost:8080,localhost:4430|no-svc-ns|no-svc-name|no-lb-type|no-lb-key")) - .BDDfy(); + // Act + var result = _creator.Create(route); + + // Assert + result.ShouldBe("GET,POST,PUT|/api/product|my-host|localhost:8080,localhost:4430|no-svc-ns|no-svc-name|no-lb-type|no-lb-key"); } [Fact] public void Should_return_route_key_with_svc_name() { + // Arrange var route = new FileRoute { UpstreamPathTemplate = "/api/product", @@ -84,15 +84,17 @@ public void Should_return_route_key_with_svc_name() ServiceName = "products-service", }; - this.Given(_ => GivenThe(route)) - .When(_ => WhenICreate()) - .Then(_ => ThenTheResultIs("GET,POST,PUT|/api/product|no-host|no-host-and-port|no-svc-ns|products-service|no-lb-type|no-lb-key")) - .BDDfy(); + // Act + var result = _creator.Create(route); + + // Assert + result.ShouldBe("GET,POST,PUT|/api/product|no-host|no-host-and-port|no-svc-ns|products-service|no-lb-type|no-lb-key"); } [Fact] public void Should_return_route_key_with_load_balancer_options() { + // Arrange var route = new FileRoute { UpstreamPathTemplate = "/api/product", @@ -105,24 +107,10 @@ public void Should_return_route_key_with_load_balancer_options() }, }; - this.Given(_ => GivenThe(route)) - .When(_ => WhenICreate()) - .Then(_ => ThenTheResultIs("GET,POST,PUT|/api/product|no-host|no-host-and-port|no-svc-ns|products-service|LeastConnection|testy")) - .BDDfy(); - } + // Act + var result = _creator.Create(route); - private void GivenThe(FileRoute route) - { - _route = route; - } - - private void WhenICreate() - { - _result = _creator.Create(_route); - } - - private void ThenTheResultIs(string expected) - { - _result.ShouldBe(expected); + // Assert + result.ShouldBe("GET,POST,PUT|/api/product|no-host|no-host-and-port|no-svc-ns|products-service|LeastConnection|testy"); } } diff --git a/test/Ocelot.UnitTests/Configuration/RouteOptionsCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/RouteOptionsCreatorTests.cs index 21f9058ae..d83162789 100644 --- a/test/Ocelot.UnitTests/Configuration/RouteOptionsCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/RouteOptionsCreatorTests.cs @@ -6,12 +6,7 @@ namespace Ocelot.UnitTests.Configuration; public class RouteOptionsCreatorTests : UnitTest { - private readonly RouteOptionsCreator _creator; - - public RouteOptionsCreatorTests() - { - _creator = new RouteOptionsCreator(); - } + private readonly RouteOptionsCreator _creator = new(); [Fact] public void Create_ArgumentIsNull_OptionsObjIsCreated() diff --git a/test/Ocelot.UnitTests/Configuration/RoutesCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/RoutesCreatorTests.cs index 507aca35d..b9e396d71 100644 --- a/test/Ocelot.UnitTests/Configuration/RoutesCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/RoutesCreatorTests.cs @@ -92,18 +92,21 @@ public RoutesCreatorTests() [Fact] public void Should_return_nothing() { - var fileConfig = new FileConfiguration(); + // Arrange + _fileConfig = new FileConfiguration(); - this.Given(_ => GivenThe(fileConfig)) - .When(_ => WhenICreate()) - .Then(_ => ThenNoRoutesAreReturned()) - .BDDfy(); + // Act + _result = _creator.Create(_fileConfig); + + // Assert + _result.ShouldBeEmpty(); } [Fact] public void Should_return_routes() { - var fileConfig = new FileConfiguration + // Arrange + _fileConfig = new FileConfiguration { Routes = new List { @@ -153,13 +156,14 @@ public void Should_return_routes() }, }, }; + GivenTheDependenciesAreSetUpCorrectly(); + + // Act + _result = _creator.Create(_fileConfig); - this.Given(_ => GivenThe(fileConfig)) - .And(_ => GivenTheDependenciesAreSetUpCorrectly()) - .When(_ => WhenICreate()) - .Then(_ => ThenTheDependenciesAreCalledCorrectly()) - .And(_ => ThenTheRoutesAreCreated()) - .BDDfy(); + // Assert + ThenTheDependenciesAreCalledCorrectly(); + ThenTheRoutesAreCreated(); } private void ThenTheDependenciesAreCalledCorrectly() @@ -217,26 +221,10 @@ private void GivenTheDependenciesAreSetUpCorrectly() private void ThenTheRoutesAreCreated() { _result.Count.ShouldBe(2); - ThenTheRouteIsSet(_fileConfig.Routes[0], 0); ThenTheRouteIsSet(_fileConfig.Routes[1], 1); } - private void ThenNoRoutesAreReturned() - { - _result.ShouldBeEmpty(); - } - - private void GivenThe(FileConfiguration fileConfig) - { - _fileConfig = fileConfig; - } - - private void WhenICreate() - { - _result = _creator.Create(_fileConfig); - } - private void ThenTheRouteIsSet(FileRoute expected, int routeIndex) { _result[routeIndex].DownstreamRoute[0].DownstreamHttpVersion.ShouldBe(_expectedVersion); diff --git a/test/Ocelot.UnitTests/Configuration/SecurityOptionsCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/SecurityOptionsCreatorTests.cs index 2a223c78f..4b02440cd 100644 --- a/test/Ocelot.UnitTests/Configuration/SecurityOptionsCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/SecurityOptionsCreatorTests.cs @@ -26,7 +26,7 @@ public void Should_create_route_security_config() var actual = _creator.Create(securityOptions, globalConfig); // Assert - ThenTheResultIs(actual, expected); + actual.ThenTheResultIs(expected); } [Fact] @@ -50,7 +50,7 @@ public void Should_create_global_security_config() var actual = _creator.Create(new(), globalConfig); // Assert - ThenTheResultIs(actual, expected); + actual.ThenTheResultIs(expected); } [Fact] @@ -81,10 +81,13 @@ public void Should_create_global_route_security_config() var actual = _creator.Create(securityOptions, globalConfig); // Assert - ThenTheResultIs(actual, expected); + actual.ThenTheResultIs(expected); } +} - private static void ThenTheResultIs(SecurityOptions actual, SecurityOptions expected) +internal static class SecurityOptionsExtensions +{ + public static void ThenTheResultIs(this SecurityOptions actual, SecurityOptions expected) { for (var i = 0; i < expected.IPAllowedList.Count; i++) { diff --git a/test/Ocelot.UnitTests/Configuration/ServiceProviderConfigurationCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/ServiceProviderConfigurationCreatorTests.cs new file mode 100644 index 000000000..0e158ad39 --- /dev/null +++ b/test/Ocelot.UnitTests/Configuration/ServiceProviderConfigurationCreatorTests.cs @@ -0,0 +1,50 @@ +using Ocelot.Configuration.Builder; +using Ocelot.Configuration.Creator; +using Ocelot.Configuration.File; + +namespace Ocelot.UnitTests.Configuration; + +public class ServiceProviderConfigurationCreatorTests : UnitTest +{ + private readonly ServiceProviderConfigurationCreator _creator = new(); + + [Fact] + public void Should_create_service_provider_config() + { + // Arrange + var globalConfig = new FileGlobalConfiguration + { + ServiceDiscoveryProvider = new FileServiceDiscoveryProvider + { + Scheme = "https", + Host = "127.0.0.1", + Port = 1234, + Type = "ServiceFabric", + Token = "testtoken", + ConfigurationKey = "woo", + Namespace = "default", + }, + }; + var expected = new ServiceProviderConfigurationBuilder() + .WithScheme("https") + .WithHost("127.0.0.1") + .WithPort(1234) + .WithType("ServiceFabric") + .WithToken("testtoken") + .WithConfigurationKey("woo") + .WithNamespace("default") + .Build(); + + // Act + var result = _creator.Create(globalConfig); + + // Assert + result.Scheme.ShouldBe(expected.Scheme); + result.Host.ShouldBe(expected.Host); + result.Port.ShouldBe(expected.Port); + result.Token.ShouldBe(expected.Token); + result.Type.ShouldBe(expected.Type); + result.Namespace.ShouldBe(expected.Namespace); + result.ConfigurationKey.ShouldBe(expected.ConfigurationKey); + } +} diff --git a/test/Ocelot.UnitTests/Configuration/ServiceProviderCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/ServiceProviderCreatorTests.cs deleted file mode 100644 index 9370fc744..000000000 --- a/test/Ocelot.UnitTests/Configuration/ServiceProviderCreatorTests.cs +++ /dev/null @@ -1,72 +0,0 @@ -using Ocelot.Configuration; -using Ocelot.Configuration.Builder; -using Ocelot.Configuration.Creator; -using Ocelot.Configuration.File; - -namespace Ocelot.UnitTests.Configuration; - -public class ServiceProviderCreatorTests : UnitTest -{ - private readonly ServiceProviderConfigurationCreator _creator; - private FileGlobalConfiguration _globalConfig; - private ServiceProviderConfiguration _result; - - public ServiceProviderCreatorTests() - { - _creator = new ServiceProviderConfigurationCreator(); - } - - [Fact] - public void should_create_service_provider_config() - { - var globalConfig = new FileGlobalConfiguration - { - ServiceDiscoveryProvider = new FileServiceDiscoveryProvider - { - Scheme = "https", - Host = "127.0.0.1", - Port = 1234, - Type = "ServiceFabric", - Token = "testtoken", - ConfigurationKey = "woo", - Namespace = "default", - }, - }; - - var expected = new ServiceProviderConfigurationBuilder() - .WithScheme("https") - .WithHost("127.0.0.1") - .WithPort(1234) - .WithType("ServiceFabric") - .WithToken("testtoken") - .WithConfigurationKey("woo") - .WithNamespace("default") - .Build(); - - this.Given(x => x.GivenTheFollowingGlobalConfig(globalConfig)) - .When(x => x.WhenICreate()) - .Then(x => x.ThenTheConfigIs(expected)) - .BDDfy(); - } - - private void GivenTheFollowingGlobalConfig(FileGlobalConfiguration fileGlobalConfig) - { - _globalConfig = fileGlobalConfig; - } - - private void WhenICreate() - { - _result = _creator.Create(_globalConfig); - } - - private void ThenTheConfigIs(ServiceProviderConfiguration expected) - { - _result.Scheme.ShouldBe(expected.Scheme); - _result.Host.ShouldBe(expected.Host); - _result.Port.ShouldBe(expected.Port); - _result.Token.ShouldBe(expected.Token); - _result.Type.ShouldBe(expected.Type); - _result.Namespace.ShouldBe(expected.Namespace); - _result.ConfigurationKey.ShouldBe(expected.ConfigurationKey); - } -} diff --git a/test/Ocelot.UnitTests/Configuration/UpstreamHeaderTemplatePatternCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/UpstreamHeaderTemplatePatternCreatorTests.cs index 49cf841ac..29b451a0e 100644 --- a/test/Ocelot.UnitTests/Configuration/UpstreamHeaderTemplatePatternCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/UpstreamHeaderTemplatePatternCreatorTests.cs @@ -1,17 +1,11 @@ using Ocelot.Configuration.Creator; using Ocelot.Configuration.File; -using Ocelot.Values; namespace Ocelot.UnitTests.Configuration; public class UpstreamHeaderTemplatePatternCreatorTests { - private readonly UpstreamHeaderTemplatePatternCreator _creator; - - public UpstreamHeaderTemplatePatternCreatorTests() - { - _creator = new(); - } + private readonly UpstreamHeaderTemplatePatternCreator _creator = new(); [Trait("PR", "1312")] [Trait("Feat", "360")] diff --git a/test/Ocelot.UnitTests/Configuration/UpstreamTemplatePatternCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/UpstreamTemplatePatternCreatorTests.cs index db783ca7a..a024f190f 100644 --- a/test/Ocelot.UnitTests/Configuration/UpstreamTemplatePatternCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/UpstreamTemplatePatternCreatorTests.cs @@ -7,233 +7,255 @@ namespace Ocelot.UnitTests.Configuration; public class UpstreamTemplatePatternCreatorTests : UnitTest { - private FileRoute _fileRoute; - private readonly UpstreamTemplatePatternCreator _creator; - private UpstreamPathTemplate _result; + private readonly UpstreamTemplatePatternCreator _creator = new(); private const string MatchEverything = UpstreamTemplatePatternCreator.RegExMatchZeroOrMoreOfEverything; - public UpstreamTemplatePatternCreatorTests() - { - _creator = new UpstreamTemplatePatternCreator(); - } - [Fact] - public void should_match_up_to_next_slash() + public void Should_match_up_to_next_slash() { + // Arrange var fileRoute = new FileRoute { UpstreamPathTemplate = "/api/v{apiVersion}/cards", Priority = 0, }; - this.Given(x => x.GivenTheFollowingFileRoute(fileRoute)) - .When(x => x.WhenICreateTheTemplatePattern()) - .Then(x => x.ThenTheFollowingIsReturned("^(?i)/api/v[^/]+/cards$")) - .And(x => ThenThePriorityIs(0)) - .BDDfy(); + // Act + var result = _creator.Create(fileRoute); + + // Assert + result.Template.ShouldBe("^(?i)/api/v[^/]+/cards$"); + result.Priority.ShouldBe(0); } [Fact] - public void should_use_re_route_priority() + public void Should_use_re_route_priority() { + // Arrange var fileRoute = new FileRoute { UpstreamPathTemplate = "/orders/{catchAll}", Priority = 0, }; - this.Given(x => x.GivenTheFollowingFileRoute(fileRoute)) - .When(x => x.WhenICreateTheTemplatePattern()) - .Then(x => x.ThenTheFollowingIsReturned($"^(?i)/orders(?:|/{MatchEverything})$")) - .And(x => ThenThePriorityIs(0)) - .BDDfy(); + // Act + var result = _creator.Create(fileRoute); + + // Assert + result.Template.ShouldBe($"^(?i)/orders(?:|/{MatchEverything})$"); + result.Priority.ShouldBe(0); } [Fact] - public void should_use_zero_priority() + public void Should_use_zero_priority() { + // Arrange var fileRoute = new FileRoute { UpstreamPathTemplate = "/{catchAll}", Priority = 1, }; - this.Given(x => x.GivenTheFollowingFileRoute(fileRoute)) - .When(x => x.WhenICreateTheTemplatePattern()) - .Then(x => x.ThenTheFollowingIsReturned("^/.*")) - .And(x => ThenThePriorityIs(0)) - .BDDfy(); + // Act + var result = _creator.Create(fileRoute); + + // Assert + result.Template.ShouldBe("^/.*"); + result.Priority.ShouldBe(0); } [Fact] - public void should_set_upstream_template_pattern_to_ignore_case_sensitivity() + public void Should_set_upstream_template_pattern_to_ignore_case_sensitivity() { + // Arrange var fileRoute = new FileRoute { UpstreamPathTemplate = "/PRODUCTS/{productId}", RouteIsCaseSensitive = false, }; - this.Given(x => x.GivenTheFollowingFileRoute(fileRoute)) - .When(x => x.WhenICreateTheTemplatePattern()) - .Then(x => x.ThenTheFollowingIsReturned($"^(?i)/PRODUCTS(?:|/{MatchEverything})$")) - .And(x => ThenThePriorityIs(1)) - .BDDfy(); + // Act + var result = _creator.Create(fileRoute); + + // Assert + result.Template.ShouldBe($"^(?i)/PRODUCTS(?:|/{MatchEverything})$"); + result.Priority.ShouldBe(1); } [Fact] - public void should_match_forward_slash_or_no_forward_slash_if_template_end_with_forward_slash() + public void Should_match_forward_slash_or_no_forward_slash_if_template_end_with_forward_slash() { + // Arrange var fileRoute = new FileRoute { UpstreamPathTemplate = "/PRODUCTS/", RouteIsCaseSensitive = false, }; - this.Given(x => x.GivenTheFollowingFileRoute(fileRoute)) - .When(x => x.WhenICreateTheTemplatePattern()) - .Then(x => x.ThenTheFollowingIsReturned("^(?i)/PRODUCTS(/|)$")) - .And(x => ThenThePriorityIs(1)) - .BDDfy(); + // Act + var result = _creator.Create(fileRoute); + + // Assert + result.Template.ShouldBe("^(?i)/PRODUCTS(/|)$"); + result.Priority.ShouldBe(1); } [Fact] - public void should_set_upstream_template_pattern_to_respect_case_sensitivity() + public void Should_set_upstream_template_pattern_to_respect_case_sensitivity() { + // Arrange var fileRoute = new FileRoute { UpstreamPathTemplate = "/PRODUCTS/{productId}", RouteIsCaseSensitive = true, }; - this.Given(x => x.GivenTheFollowingFileRoute(fileRoute)) - .When(x => x.WhenICreateTheTemplatePattern()) - .Then(x => x.ThenTheFollowingIsReturned($"^/PRODUCTS(?:|/{MatchEverything})$")) - .And(x => ThenThePriorityIs(1)) - .BDDfy(); + + // Act + var result = _creator.Create(fileRoute); + + // Assert + result.Template.ShouldBe($"^/PRODUCTS(?:|/{MatchEverything})$"); + result.Priority.ShouldBe(1); } [Fact] - public void should_create_template_pattern_that_matches_anything_to_end_of_string() + public void Should_create_template_pattern_that_matches_anything_to_end_of_string() { + // Arrange var fileRoute = new FileRoute { UpstreamPathTemplate = "/api/products/{productId}", RouteIsCaseSensitive = true, }; - this.Given(x => x.GivenTheFollowingFileRoute(fileRoute)) - .When(x => x.WhenICreateTheTemplatePattern()) - .Then(x => x.ThenTheFollowingIsReturned($"^/api/products(?:|/{MatchEverything})$")) - .And(x => ThenThePriorityIs(1)) - .BDDfy(); + // Act + var result = _creator.Create(fileRoute); + + // Assert + result.Template.ShouldBe($"^/api/products(?:|/{MatchEverything})$"); + result.Priority.ShouldBe(1); } [Fact] - public void should_create_template_pattern_that_matches_more_than_one_placeholder() + public void Should_create_template_pattern_that_matches_more_than_one_placeholder() { + // Arrange var fileRoute = new FileRoute { UpstreamPathTemplate = "/api/products/{productId}/variants/{variantId}", RouteIsCaseSensitive = true, }; - this.Given(x => x.GivenTheFollowingFileRoute(fileRoute)) - .When(x => x.WhenICreateTheTemplatePattern()) - .Then(x => x.ThenTheFollowingIsReturned($"^/api/products/[^/]+/variants(?:|/{MatchEverything})$")) - .And(x => ThenThePriorityIs(1)) - .BDDfy(); + // Act + var result = _creator.Create(fileRoute); + + // Assert + result.Template.ShouldBe($"^/api/products/[^/]+/variants(?:|/{MatchEverything})$"); + result.Priority.ShouldBe(1); } [Fact] - public void should_create_template_pattern_that_matches_more_than_one_placeholder_with_trailing_slash() + public void Should_create_template_pattern_that_matches_more_than_one_placeholder_with_trailing_slash() { + // Arrange var fileRoute = new FileRoute { UpstreamPathTemplate = "/api/products/{productId}/variants/{variantId}/", RouteIsCaseSensitive = true, }; - this.Given(x => x.GivenTheFollowingFileRoute(fileRoute)) - .When(x => x.WhenICreateTheTemplatePattern()) - .Then(x => x.ThenTheFollowingIsReturned("^/api/products/[^/]+/variants/[^/]+(/|)$")) - .And(x => ThenThePriorityIs(1)) - .BDDfy(); + // Act + var result = _creator.Create(fileRoute); + + // Assert + result.Template.ShouldBe("^/api/products/[^/]+/variants/[^/]+(/|)$"); + result.Priority.ShouldBe(1); } [Fact] - public void should_create_template_pattern_that_matches_to_end_of_string() + public void Should_create_template_pattern_that_matches_to_end_of_string() { + // Arrange var fileRoute = new FileRoute { UpstreamPathTemplate = "/", }; - this.Given(x => x.GivenTheFollowingFileRoute(fileRoute)) - .When(x => x.WhenICreateTheTemplatePattern()) - .Then(x => x.ThenTheFollowingIsReturned("^/$")) - .And(x => ThenThePriorityIs(1)) - .BDDfy(); + // Act + var result = _creator.Create(fileRoute); + + // Assert + result.Template.ShouldBe("^/$"); + result.Priority.ShouldBe(1); } [Fact] - public void should_create_template_pattern_that_matches_to_end_of_string_when_slash_and_placeholder() + public void Should_create_template_pattern_that_matches_to_end_of_string_when_slash_and_placeholder() { + // Arrange var fileRoute = new FileRoute { UpstreamPathTemplate = "/{url}", }; - this.Given(x => x.GivenTheFollowingFileRoute(fileRoute)) - .When(x => x.WhenICreateTheTemplatePattern()) - .Then(x => x.ThenTheFollowingIsReturned("^/.*")) - .And(x => ThenThePriorityIs(0)) - .BDDfy(); + // Act + var result = _creator.Create(fileRoute); + + // Assert + result.Template.ShouldBe("^/.*"); + result.Priority.ShouldBe(0); } [Fact] - public void should_create_template_pattern_that_starts_with_placeholder_then_has_another_later() + public void Should_create_template_pattern_that_starts_with_placeholder_then_has_another_later() { + // Arrange var fileRoute = new FileRoute { UpstreamPathTemplate = "/{productId}/products/variants/{variantId}/", RouteIsCaseSensitive = true, }; - this.Given(x => x.GivenTheFollowingFileRoute(fileRoute)) - .When(x => x.WhenICreateTheTemplatePattern()) - .Then(x => x.ThenTheFollowingIsReturned("^/[^/]+/products/variants/[^/]+(/|)$")) - .And(x => ThenThePriorityIs(1)) - .BDDfy(); + // Act + var result = _creator.Create(fileRoute); + + // Assert + result.Template.ShouldBe("^/[^/]+/products/variants/[^/]+(/|)$"); + result.Priority.ShouldBe(1); } [Fact] - public void should_create_template_pattern_that_matches_query_string() + public void Should_create_template_pattern_that_matches_query_string() { + // Arrange var fileRoute = new FileRoute { UpstreamPathTemplate = "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}", }; - this.Given(x => x.GivenTheFollowingFileRoute(fileRoute)) - .When(x => x.WhenICreateTheTemplatePattern()) - .Then(x => x.ThenTheFollowingIsReturned($@"^(?i)/api/subscriptions/[^/]+/updates(/$|/\?|\?|$)unitId={MatchEverything}$")) - .And(x => ThenThePriorityIs(1)) - .BDDfy(); + // Act + var result = _creator.Create(fileRoute); + + // Assert + result.Template.ShouldBe($@"^(?i)/api/subscriptions/[^/]+/updates(/$|/\?|\?|$)unitId={MatchEverything}$"); + result.Priority.ShouldBe(1); } [Fact] - public void should_create_template_pattern_that_matches_query_string_with_multiple_params() + public void Should_create_template_pattern_that_matches_query_string_with_multiple_params() { + // Arrange var fileRoute = new FileRoute { UpstreamPathTemplate = "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}&productId={productId}", }; - this.Given(x => x.GivenTheFollowingFileRoute(fileRoute)) - .When(x => x.WhenICreateTheTemplatePattern()) - .Then(x => x.ThenTheFollowingIsReturned($@"^(?i)/api/subscriptions/[^/]+/updates(/$|/\?|\?|$)unitId={MatchEverything}&productId={MatchEverything}$")) - .And(x => ThenThePriorityIs(1)) - .BDDfy(); + // Act + var result = _creator.Create(fileRoute); + + // Assert + result.Template.ShouldBe($"^(?i)/api/subscriptions/[^/]+/updates(/$|/\\?|\\?|$)unitId={MatchEverything}&productId={MatchEverything}$"); + result.Priority.ShouldBe(1); } [Theory] @@ -243,13 +265,16 @@ public void should_create_template_pattern_that_matches_query_string_with_multip public void Should_not_match_when_placeholder_appears_after_query_start(string urlPathTemplate, string requestPath, bool shouldMatch) { // Arrange - GivenTheFollowingFileRoute(new() { UpstreamPathTemplate = urlPathTemplate }); + var fileRoute = new FileRoute + { + UpstreamPathTemplate = urlPathTemplate, + }; // Act - WhenICreateTheTemplatePattern(); + var result = _creator.Create(fileRoute); // Assert - ShouldMatchWithRegex(requestPath, shouldMatch); + result.ShouldMatchWithRegex(requestPath, shouldMatch); } [Theory] @@ -259,38 +284,24 @@ public void Should_not_match_when_placeholder_appears_after_query_start(string u public void Should_not_match_with_query_param_wildcard(string urlPathTemplate, string requestPath, bool shouldMatch) { // Arrange - GivenTheFollowingFileRoute(new() { UpstreamPathTemplate = urlPathTemplate }); + var fileRoute = new FileRoute + { + UpstreamPathTemplate = urlPathTemplate, + }; // Act - WhenICreateTheTemplatePattern(); + var result = _creator.Create(fileRoute); // Assert - ShouldMatchWithRegex(requestPath, shouldMatch); + result.ShouldMatchWithRegex(requestPath, shouldMatch); } +} - private void ShouldMatchWithRegex(string requestPath, bool shouldMatch) +internal static class UpstreamPathTemplateExtensions +{ + public static void ShouldMatchWithRegex(this UpstreamPathTemplate actual, string requestPath, bool shouldMatch) { - var match = Regex.Match(requestPath, _result.Template); + var match = Regex.Match(requestPath, actual.Template); Assert.Equal(shouldMatch, match.Success); } - - private void GivenTheFollowingFileRoute(FileRoute fileRoute) - { - _fileRoute = fileRoute; - } - - private void WhenICreateTheTemplatePattern() - { - _result = _creator.Create(_fileRoute); - } - - private void ThenTheFollowingIsReturned(string expected) - { - _result.Template.ShouldBe(expected); - } - - private void ThenThePriorityIs(int v) - { - _result.Priority.ShouldBe(v); - } } diff --git a/test/Ocelot.UnitTests/Configuration/Validation/FileConfigurationFluentValidatorTests.cs b/test/Ocelot.UnitTests/Configuration/Validation/FileConfigurationFluentValidatorTests.cs index 84d6bb7ce..0919050fa 100644 --- a/test/Ocelot.UnitTests/Configuration/Validation/FileConfigurationFluentValidatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/Validation/FileConfigurationFluentValidatorTests.cs @@ -20,7 +20,7 @@ namespace Ocelot.UnitTests.Configuration.Validation; public class FileConfigurationFluentValidatorTests : UnitTest { - private IConfigurationValidator _configurationValidator; + private FileConfigurationFluentValidator _configurationValidator; private FileConfiguration _fileConfiguration; private Response _result; private IServiceProvider _provider; @@ -38,92 +38,117 @@ public FileConfigurationFluentValidatorTests() } [Fact] - public void Configuration_is_valid_if_service_discovery_options_specified_and_has_service_fabric_as_option() + public async Task Configuration_is_valid_if_service_discovery_options_specified_and_has_service_fabric_as_option() { + // Arrange var route = GivenServiceDiscoveryRoute(); var configuration = GivenAConfiguration(route); configuration.GlobalConfiguration.ServiceDiscoveryProvider = GivenDefaultServiceDiscoveryProvider(); - this.Given(x => x.GivenAConfiguration(configuration)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsValid()) - .BDDfy(); + GivenAConfiguration(configuration); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsValid(); } [Fact] - public void Configuration_is_valid_if_service_discovery_options_specified_and_has_service_discovery_handler() + public async Task Configuration_is_valid_if_service_discovery_options_specified_and_has_service_discovery_handler() { + // Arrange var route = GivenServiceDiscoveryRoute(); var configuration = GivenAConfiguration(route); configuration.GlobalConfiguration.ServiceDiscoveryProvider = GivenDefaultServiceDiscoveryProvider(); configuration.GlobalConfiguration.ServiceDiscoveryProvider.Type = "FakeServiceDiscoveryProvider"; - this.Given(x => x.GivenAConfiguration(configuration)) - .And(x => x.GivenAServiceDiscoveryHandler()) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsValid()) - .BDDfy(); + GivenAConfiguration(configuration); + GivenAServiceDiscoveryHandler(); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsValid(); } [Fact] - public void Configuration_is_valid_if_service_discovery_options_specified_dynamically_and_has_service_discovery_handler() + public async Task Configuration_is_valid_if_service_discovery_options_specified_dynamically_and_has_service_discovery_handler() { + // Arrange var configuration = new FileConfiguration(); configuration.GlobalConfiguration.ServiceDiscoveryProvider = GivenDefaultServiceDiscoveryProvider(); configuration.GlobalConfiguration.ServiceDiscoveryProvider.Type = "FakeServiceDiscoveryProvider"; - this.Given(x => x.GivenAConfiguration(configuration)) - .And(x => x.GivenAServiceDiscoveryHandler()) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsValid()) - .BDDfy(); + GivenAConfiguration(configuration); + GivenAServiceDiscoveryHandler(); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsValid(); } [Fact] - public void Configuration_is_invalid_if_service_discovery_options_specified_but_no_service_discovery_handler() + public async Task Configuration_is_invalid_if_service_discovery_options_specified_but_no_service_discovery_handler() { + // Arrange var route = GivenServiceDiscoveryRoute(); var configuration = GivenAConfiguration(route); configuration.GlobalConfiguration.ServiceDiscoveryProvider = GivenDefaultServiceDiscoveryProvider(); configuration.GlobalConfiguration.ServiceDiscoveryProvider.Type = "FakeServiceDiscoveryProvider"; - this.Given(x => x.GivenAConfiguration(configuration)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsNotValid()) - .And(x => x.ThenTheErrorIs()) - .And(x => x.ThenTheErrorMessageAtPositionIs(0, "Unable to start Ocelot, errors are: Unable to start Ocelot because either a Route or GlobalConfiguration are using ServiceDiscoveryOptions but no ServiceDiscoveryFinderDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Consul and services.AddConsul() or Ocelot.Provider.Eureka and services.AddEureka()?")) - .BDDfy(); + GivenAConfiguration(configuration); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsNotValid(); + ThenTheErrorIs(); + ThenTheErrorMessageAtPositionIs(0, "Unable to start Ocelot, errors are: Unable to start Ocelot because either a Route or GlobalConfiguration are using ServiceDiscoveryOptions but no ServiceDiscoveryFinderDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Consul and services.AddConsul() or Ocelot.Provider.Eureka and services.AddEureka()?"); } [Fact] - public void Configuration_is_invalid_if_service_discovery_options_specified_dynamically_but_service_discovery_handler() + public async Task Configuration_is_invalid_if_service_discovery_options_specified_dynamically_but_service_discovery_handler() { + // Arrange var configuration = new FileConfiguration(); configuration.GlobalConfiguration.ServiceDiscoveryProvider = GivenDefaultServiceDiscoveryProvider(); configuration.GlobalConfiguration.ServiceDiscoveryProvider.Type = "FakeServiceDiscoveryProvider"; - this.Given(x => x.GivenAConfiguration(configuration)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsNotValid()) - .And(x => x.ThenTheErrorIs()) - .And(x => x.ThenTheErrorMessageAtPositionIs(0, "Unable to start Ocelot, errors are: Unable to start Ocelot because either a Route or GlobalConfiguration are using ServiceDiscoveryOptions but no ServiceDiscoveryFinderDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Consul and services.AddConsul() or Ocelot.Provider.Eureka and services.AddEureka()?")) - .BDDfy(); + GivenAConfiguration(configuration); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsNotValid(); + ThenTheErrorIs(); + ThenTheErrorMessageAtPositionIs(0, "Unable to start Ocelot, errors are: Unable to start Ocelot because either a Route or GlobalConfiguration are using ServiceDiscoveryOptions but no ServiceDiscoveryFinderDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Consul and services.AddConsul() or Ocelot.Provider.Eureka and services.AddEureka()?"); } [Fact] - public void Configuration_is_invalid_if_service_discovery_options_specified_but_no_service_discovery_handler_with_matching_name() + public async Task Configuration_is_invalid_if_service_discovery_options_specified_but_no_service_discovery_handler_with_matching_name() { + // Arrange var route = GivenServiceDiscoveryRoute(); var configuration = GivenAConfiguration(route); configuration.GlobalConfiguration.ServiceDiscoveryProvider = GivenDefaultServiceDiscoveryProvider(); configuration.GlobalConfiguration.ServiceDiscoveryProvider.Type = "consul"; - this.Given(x => x.GivenAConfiguration(configuration)) - .When(x => x.WhenIValidateTheConfiguration()) - .And(x => x.GivenAServiceDiscoveryHandler()) - .Then(x => x.ThenTheResultIsNotValid()) - .And(x => x.ThenTheErrorIs()) - .And(x => x.ThenTheErrorMessageAtPositionIs(0, "Unable to start Ocelot, errors are: Unable to start Ocelot because either a Route or GlobalConfiguration are using ServiceDiscoveryOptions but no ServiceDiscoveryFinderDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Consul and services.AddConsul() or Ocelot.Provider.Eureka and services.AddEureka()?")) - .BDDfy(); + GivenAConfiguration(configuration); + + // Act + await WhenIValidateTheConfiguration(); + GivenAServiceDiscoveryHandler(); + + // Assert + ThenTheResultIsNotValid(); + ThenTheErrorIs(); + ThenTheErrorMessageAtPositionIs(0, "Unable to start Ocelot, errors are: Unable to start Ocelot because either a Route or GlobalConfiguration are using ServiceDiscoveryOptions but no ServiceDiscoveryFinderDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Consul and services.AddConsul() or Ocelot.Provider.Eureka and services.AddEureka()?"); } [Fact] - public void Configuration_is_valid_if_qos_options_specified_and_has_qos_handler() + public async Task Configuration_is_valid_if_qos_options_specified_and_has_qos_handler() { + // Arrange var route = GivenDefaultRoute("/laura", "/"); route.Key = "Laura"; route.QoSOptions = new FileQoSOptions @@ -131,16 +156,20 @@ public void Configuration_is_valid_if_qos_options_specified_and_has_qos_handler( TimeoutValue = 1, ExceptionsAllowedBeforeBreaking = 1, }; - this.Given(x => x.GivenAConfiguration(route)) - .And(x => x.GivenAQoSHandler()) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsValid()) - .BDDfy(); + GivenAConfiguration(route); + GivenAQoSHandler(); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsValid(); } [Fact] - public void Configuration_is_valid_if_qos_options_specified_globally_and_has_qos_handler() + public async Task Configuration_is_valid_if_qos_options_specified_globally_and_has_qos_handler() { + // Arrange var route = GivenDefaultRoute("/laura", "/"); route.Key = "Laura"; var configuration = GivenAConfiguration(route); @@ -149,16 +178,20 @@ public void Configuration_is_valid_if_qos_options_specified_globally_and_has_qos TimeoutValue = 1, ExceptionsAllowedBeforeBreaking = 1, }; - this.Given(x => x.GivenAConfiguration(configuration)) - .And(x => x.GivenAQoSHandler()) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsValid()) - .BDDfy(); + GivenAConfiguration(configuration); + GivenAQoSHandler(); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsValid(); } [Fact] - public void Configuration_is_invalid_if_qos_options_specified_but_no_qos_handler() + public async Task Configuration_is_invalid_if_qos_options_specified_but_no_qos_handler() { + // Arrange var route = GivenDefaultRoute("/laura", "/"); route.Key = "Laura"; route.QoSOptions = new FileQoSOptions @@ -166,17 +199,21 @@ public void Configuration_is_invalid_if_qos_options_specified_but_no_qos_handler TimeoutValue = 1, ExceptionsAllowedBeforeBreaking = 1, }; - this.Given(x => x.GivenAConfiguration(route)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsNotValid()) - .And(x => x.ThenTheErrorIs()) - .And(x => x.ThenTheErrorMessageAtPositionIs(0, "Unable to start Ocelot because either a Route or GlobalConfiguration are using QoSOptions but no QosDelegatingHandlerDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Polly and services.AddPolly()?")) - .BDDfy(); + GivenAConfiguration(route); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsNotValid(); + ThenTheErrorIs(); + ThenTheErrorMessageAtPositionIs(0, "Unable to start Ocelot because either a Route or GlobalConfiguration are using QoSOptions but no QosDelegatingHandlerDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Polly and services.AddPolly()?"); } [Fact] - public void Configuration_is_invalid_if_qos_options_specified_globally_but_no_qos_handler() + public async Task Configuration_is_invalid_if_qos_options_specified_globally_but_no_qos_handler() { + // Arrange var route = GivenDefaultRoute("/laura", "/"); route.Key = "Laura"; var configuration = GivenAConfiguration(route); @@ -185,17 +222,21 @@ public void Configuration_is_invalid_if_qos_options_specified_globally_but_no_qo TimeoutValue = 1, ExceptionsAllowedBeforeBreaking = 1, }; - this.Given(x => x.GivenAConfiguration(configuration)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsNotValid()) - .And(x => x.ThenTheErrorIs()) - .And(x => x.ThenTheErrorMessageAtPositionIs(0, "Unable to start Ocelot because either a Route or GlobalConfiguration are using QoSOptions but no QosDelegatingHandlerDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Polly and services.AddPolly()?")) - .BDDfy(); + GivenAConfiguration(configuration); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsNotValid(); + ThenTheErrorIs(); + ThenTheErrorMessageAtPositionIs(0, "Unable to start Ocelot because either a Route or GlobalConfiguration are using QoSOptions but no QosDelegatingHandlerDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Polly and services.AddPolly()?"); } [Fact] - public void Configuration_is_valid_if_aggregates_are_valid() + public async Task Configuration_is_valid_if_aggregates_are_valid() { + // Arrange var route = GivenDefaultRoute("/laura", "/"); route.Key = "Laura"; var route2 = GivenDefaultRoute("/tom", "/"); @@ -210,15 +251,19 @@ public void Configuration_is_valid_if_aggregates_are_valid() RouteKeys = new() { "Tom", "Laura" }, }, }; - this.Given(x => x.GivenAConfiguration(configuration)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsValid()) - .BDDfy(); + GivenAConfiguration(configuration); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsValid(); } [Fact] - public void Configuration_is_invalid_if_aggregates_are_duplicate_of_routes() + public async Task Configuration_is_invalid_if_aggregates_are_duplicate_of_routes() { + // Arrange var route = GivenDefaultRoute("/laura", "/"); route.Key = "Laura"; var route2 = GivenDefaultRoute("/tom", "/"); @@ -234,16 +279,20 @@ public void Configuration_is_invalid_if_aggregates_are_duplicate_of_routes() RouteKeys = new() { "Tom", "Laura" }, }, }; - this.Given(x => x.GivenAConfiguration(configuration)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsNotValid()) - .And(x => x.ThenTheErrorMessageAtPositionIs(0, "route /tom has duplicate aggregate")) - .BDDfy(); + GivenAConfiguration(configuration); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsNotValid(); + ThenTheErrorMessageAtPositionIs(0, "route /tom has duplicate aggregate"); } [Fact] - public void Configuration_is_valid_if_aggregates_are_not_duplicate_of_routes() + public async Task Configuration_is_valid_if_aggregates_are_not_duplicate_of_routes() { + // Arrange var route = GivenDefaultRoute("/laura", "/"); route.Key = "Laura"; var route2 = GivenDefaultRoute("/tom", "/"); @@ -259,15 +308,19 @@ public void Configuration_is_valid_if_aggregates_are_not_duplicate_of_routes() RouteKeys = new() { "Tom", "Laura" }, }, }; - this.Given(x => x.GivenAConfiguration(configuration)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsValid()) - .BDDfy(); + GivenAConfiguration(configuration); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsValid(); } [Fact] - public void Configuration_is_invalid_if_aggregates_are_duplicate_of_aggregates() + public async Task Configuration_is_invalid_if_aggregates_are_duplicate_of_aggregates() { + // Arrange var route = GivenDefaultRoute("/laura", "/"); route.Key = "Laura"; var route2 = GivenDefaultRoute("/lol", "/"); @@ -288,16 +341,20 @@ public void Configuration_is_invalid_if_aggregates_are_duplicate_of_aggregates() RouteKeys = new() { "Tom", "Laura" }, }, }; - this.Given(x => x.GivenAConfiguration(configuration)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsNotValid()) - .And(x => x.ThenTheErrorMessageAtPositionIs(0, "aggregate /tom has duplicate aggregate")) - .BDDfy(); + GivenAConfiguration(configuration); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsNotValid(); + ThenTheErrorMessageAtPositionIs(0, "aggregate /tom has duplicate aggregate"); } [Fact] - public void Configuration_is_invalid_if_routes_dont_exist_for_aggregate() + public async Task Configuration_is_invalid_if_routes_dont_exist_for_aggregate() { + // Arrange var route = GivenDefaultRoute("/laura", "/"); route.Key = "Laura"; var configuration = GivenAConfiguration(route); @@ -310,16 +367,20 @@ public void Configuration_is_invalid_if_routes_dont_exist_for_aggregate() RouteKeys = new() { "Tom", "Laura" }, }, }; - this.Given(x => x.GivenAConfiguration(configuration)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsNotValid()) - .And(x => x.ThenTheErrorMessageAtPositionIs(0, "Routes for aggregateRoute / either do not exist or do not have correct ServiceName property")) - .BDDfy(); + GivenAConfiguration(configuration); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsNotValid(); + ThenTheErrorMessageAtPositionIs(0, "Routes for aggregateRoute / either do not exist or do not have correct ServiceName property"); } [Fact] - public void Configuration_is_invalid_if_aggregate_has_routes_with_specific_request_id_keys() + public async Task Configuration_is_invalid_if_aggregate_has_routes_with_specific_request_id_keys() { + // Arrange var route = GivenDefaultRoute("/laura", "/"); route.Key = "Laura"; var route2 = GivenDefaultRoute("/tom", "/"); @@ -335,250 +396,322 @@ public void Configuration_is_invalid_if_aggregate_has_routes_with_specific_reque RouteKeys = new() { "Tom", "Laura" }, }, }; - this.Given(x => x.GivenAConfiguration(configuration)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsNotValid()) - .And(x => x.ThenTheErrorMessageAtPositionIs(0, "aggregateRoute / contains Route with specific RequestIdKey, this is not possible with Aggregates")) - .BDDfy(); + GivenAConfiguration(configuration); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsNotValid(); + ThenTheErrorMessageAtPositionIs(0, "aggregateRoute / contains Route with specific RequestIdKey, this is not possible with Aggregates"); } [Fact] - public void Configuration_is_invalid_if_scheme_in_downstream_or_upstream_template() + public async Task Configuration_is_invalid_if_scheme_in_downstream_or_upstream_template() { - this.Given(x => x.GivenAConfiguration(GivenDefaultRoute("http://asdf.com", "http://www.bbc.co.uk/api/products/{productId}"))) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsNotValid()) - .Then(x => x.ThenTheErrorIs()) - .And(x => x.ThenTheErrorMessageAtPositionIs(0, "Downstream Path Template http://www.bbc.co.uk/api/products/{productId} doesnt start with forward slash")) - .And(x => x.ThenTheErrorMessageAtPositionIs(1, "Downstream Path Template http://www.bbc.co.uk/api/products/{productId} contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature.")) - .And(x => x.ThenTheErrorMessageAtPositionIs(2, "Downstream Path Template http://www.bbc.co.uk/api/products/{productId} contains scheme")) + // Arrange + GivenAConfiguration(GivenDefaultRoute("http://asdf.com", "http://www.bbc.co.uk/api/products/{productId}")); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsNotValid(); + ThenTheErrorIs(); + ThenTheErrorMessageAtPositionIs(0, "Downstream Path Template http://www.bbc.co.uk/api/products/{productId} doesnt start with forward slash"); + ThenTheErrorMessageAtPositionIs(1, "Downstream Path Template http://www.bbc.co.uk/api/products/{productId} contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature."); + ThenTheErrorMessageAtPositionIs(2, "Downstream Path Template http://www.bbc.co.uk/api/products/{productId} contains scheme"); - .And(x => x.ThenTheErrorMessageAtPositionIs(3, "Upstream Path Template http://asdf.com contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature.")) - .And(x => x.ThenTheErrorMessageAtPositionIs(4, "Upstream Path Template http://asdf.com doesnt start with forward slash")) - .And(x => x.ThenTheErrorMessageAtPositionIs(5, "Upstream Path Template http://asdf.com contains scheme")) - .BDDfy(); + ThenTheErrorMessageAtPositionIs(3, "Upstream Path Template http://asdf.com contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature."); + ThenTheErrorMessageAtPositionIs(4, "Upstream Path Template http://asdf.com doesnt start with forward slash"); + ThenTheErrorMessageAtPositionIs(5, "Upstream Path Template http://asdf.com contains scheme"); } [Fact] - public void Configuration_is_valid_with_one_route() + public async Task Configuration_is_valid_with_one_route() { - this.Given(x => x.GivenAConfiguration(GivenDefaultRoute())) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsValid()) - .BDDfy(); + // Arrange + GivenAConfiguration(GivenDefaultRoute()); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsValid(); } [Fact] - public void Configuration_is_invalid_without_slash_prefix_downstream_path_template() + public async Task Configuration_is_invalid_without_slash_prefix_downstream_path_template() { - this.Given(x => x.GivenAConfiguration(GivenDefaultRoute("/asdf/", "api/products/"))) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsNotValid()) - .And(x => x.ThenTheErrorMessageAtPositionIs(0, "Downstream Path Template api/products/ doesnt start with forward slash")) - .BDDfy(); + // Arrange + GivenAConfiguration(GivenDefaultRoute("/asdf/", "api/products/")); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsNotValid(); + ThenTheErrorMessageAtPositionIs(0, "Downstream Path Template api/products/ doesnt start with forward slash"); } [Fact] - public void Configuration_is_invalid_without_slash_prefix_upstream_path_template() + public async Task Configuration_is_invalid_without_slash_prefix_upstream_path_template() { - this.Given(x => x.GivenAConfiguration(GivenDefaultRoute("api/prod/", "/api/products/"))) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsNotValid()) - .And(x => x.ThenTheErrorMessageAtPositionIs(0, "Upstream Path Template api/prod/ doesnt start with forward slash")) - .BDDfy(); + // Arrange + GivenAConfiguration(GivenDefaultRoute("api/prod/", "/api/products/")); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsNotValid(); + ThenTheErrorMessageAtPositionIs(0, "Upstream Path Template api/prod/ doesnt start with forward slash"); } [Fact] - public void Configuration_is_invalid_if_upstream_url_contains_forward_slash_then_another_forward_slash() + public async Task Configuration_is_invalid_if_upstream_url_contains_forward_slash_then_another_forward_slash() { - this.Given(x => x.GivenAConfiguration(GivenDefaultRoute("//api/prod/", "/api/products/"))) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsNotValid()) - .And(x => x.ThenTheErrorMessageAtPositionIs(0, "Upstream Path Template //api/prod/ contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature.")) - .BDDfy(); + // Arrange + GivenAConfiguration(GivenDefaultRoute("//api/prod/", "/api/products/")); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsNotValid(); + ThenTheErrorMessageAtPositionIs(0, "Upstream Path Template //api/prod/ contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature."); } [Fact] - public void Configuration_is_invalid_if_downstream_url_contains_forward_slash_then_another_forward_slash() + public async Task Configuration_is_invalid_if_downstream_url_contains_forward_slash_then_another_forward_slash() { - this.Given(x => x.GivenAConfiguration(GivenDefaultRoute("/api/prod/", "//api/products/"))) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsNotValid()) - .And(x => x.ThenTheErrorMessageAtPositionIs(0, "Downstream Path Template //api/products/ contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature.")) - .BDDfy(); + // Arrange + GivenAConfiguration(GivenDefaultRoute("/api/prod/", "//api/products/")); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsNotValid(); + ThenTheErrorMessageAtPositionIs(0, "Downstream Path Template //api/products/ contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature."); } [Fact] - public void Configuration_is_valid_with_valid_authentication_provider() + public async Task Configuration_is_valid_with_valid_authentication_provider() { + // Arrange var route = GivenDefaultRoute(); - route.AuthenticationOptions.AuthenticationProviderKey = "Test"; - this.Given(x => x.GivenAConfiguration(route)) - .And(x => x.GivenTheAuthSchemeExists("Test")) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsValid()) - .BDDfy(); + route.AuthenticationOptions.AuthenticationProviderKey = "Test"; + GivenAConfiguration(route); + GivenTheAuthSchemeExists("Test"); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsValid(); } [Fact] - public void Configuration_is_invalid_with_invalid_authentication_provider() + public async Task Configuration_is_invalid_with_invalid_authentication_provider() { + // Arrange var route = GivenDefaultRoute(); route.AuthenticationOptions = new FileAuthenticationOptions() { AuthenticationProviderKey = "Test", AuthenticationProviderKeys = new string[] { "Test #1", "Test #2" }, }; - this.Given(x => x.GivenAConfiguration(route)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsNotValid()) - .And(x => x.ThenTheErrorMessageAtPositionIs(0, "Authentication Options AuthenticationProviderKey:'Test',AuthenticationProviderKeys:['Test #1','Test #2'],AllowedScopes:[] is unsupported authentication provider")) - .BDDfy(); + GivenAConfiguration(route); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsNotValid(); + ThenTheErrorMessageAtPositionIs(0, "Authentication Options AuthenticationProviderKey:'Test',AuthenticationProviderKeys:['Test #1','Test #2'],AllowedScopes:[] is unsupported authentication provider"); } [Fact] - public void Configuration_is_not_valid_with_duplicate_routes_all_verbs() + public async Task Configuration_is_not_valid_with_duplicate_routes_all_verbs() { + // Arrange var route = GivenDefaultRoute(); var duplicate = GivenDefaultRoute(); duplicate.DownstreamPathTemplate = "/www/test/"; - this.Given(x => x.GivenAConfiguration(route, duplicate)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsNotValid()) - .And(x => x.ThenTheErrorMessageAtPositionIs(0, "route /asdf/ has duplicate")) - .BDDfy(); + GivenAConfiguration(route, duplicate); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsNotValid(); + ThenTheErrorMessageAtPositionIs(0, "route /asdf/ has duplicate"); } [Fact] - public void Configuration_is_valid_with_duplicate_routes_all_verbs_but_different_hosts() + public async Task Configuration_is_valid_with_duplicate_routes_all_verbs_but_different_hosts() { + // Arrange var route = GivenDefaultRoute(); route.UpstreamHost = "host1"; var duplicate = GivenDefaultRoute(null, "/www/test/"); - duplicate.UpstreamHost = "host2"; - this.Given(x => x.GivenAConfiguration(route, duplicate)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsValid()) - .BDDfy(); + duplicate.UpstreamHost = "host2"; + GivenAConfiguration(route, duplicate); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsValid(); } [Fact] - public void Configuration_is_not_valid_with_duplicate_routes_specific_verbs() + public async Task Configuration_is_not_valid_with_duplicate_routes_specific_verbs() { + // Arrange var route = GivenDefaultRoute(); var duplicate = GivenDefaultRoute(null, "/www/test/"); - duplicate.UpstreamHttpMethod = new() { "Get" }; - this.Given(x => x.GivenAConfiguration(route, duplicate)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsNotValid()) - .And(x => x.ThenTheErrorMessageAtPositionIs(0, "route /asdf/ has duplicate")) - .BDDfy(); + duplicate.UpstreamHttpMethod = new() { "Get" }; + GivenAConfiguration(route, duplicate); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsNotValid(); + ThenTheErrorMessageAtPositionIs(0, "route /asdf/ has duplicate"); } [Fact] - public void Configuration_is_valid_with_duplicate_routes_different_verbs() + public async Task Configuration_is_valid_with_duplicate_routes_different_verbs() { + // Arrange var route = GivenDefaultRoute(); // "Get" verb is inside var duplicate = GivenDefaultRoute(null, "/www/test/"); - duplicate.UpstreamHttpMethod = new() { "Post" }; - this.Given(x => x.GivenAConfiguration(route, duplicate)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsValid()) - .BDDfy(); + duplicate.UpstreamHttpMethod = new() { "Post" }; + GivenAConfiguration(route, duplicate); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsValid(); } [Fact] - public void Configuration_is_not_valid_with_duplicate_routes_with_duplicated_upstreamhosts() + public async Task Configuration_is_not_valid_with_duplicate_routes_with_duplicated_upstreamhosts() { + // Arrange var route = GivenDefaultRoute(); route.UpstreamHttpMethod = new(); route.UpstreamHost = "upstreamhost"; var duplicate = GivenDefaultRoute(null, "/www/test/"); duplicate.UpstreamHttpMethod = new(); - duplicate.UpstreamHost = "upstreamhost"; - - this.Given(x => x.GivenAConfiguration(route, duplicate)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsNotValid()) - .And(x => x.ThenTheErrorMessageAtPositionIs(0, "route /asdf/ has duplicate")) - .BDDfy(); + duplicate.UpstreamHost = "upstreamhost"; + GivenAConfiguration(route, duplicate); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsNotValid(); + ThenTheErrorMessageAtPositionIs(0, "route /asdf/ has duplicate"); } [Fact] - public void Configuration_is_valid_with_duplicate_routes_but_different_upstreamhosts() + public async Task Configuration_is_valid_with_duplicate_routes_but_different_upstreamhosts() { + // Arrange var route = GivenDefaultRoute(); route.UpstreamHttpMethod = new(); route.UpstreamHost = "upstreamhost111"; var duplicate = GivenDefaultRoute(null, "/www/test/"); duplicate.UpstreamHttpMethod = new(); - duplicate.UpstreamHost = "upstreamhost222"; - - this.Given(x => x.GivenAConfiguration(route, duplicate)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsValid()) - .BDDfy(); + duplicate.UpstreamHost = "upstreamhost222"; + GivenAConfiguration(route, duplicate); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsValid(); } [Fact] - public void Configuration_is_valid_with_duplicate_routes_but_one_upstreamhost_is_not_set() + public async Task Configuration_is_valid_with_duplicate_routes_but_one_upstreamhost_is_not_set() { + // Arrange var route = GivenDefaultRoute(); route.UpstreamHttpMethod = new(); route.UpstreamHost = "upstreamhost"; var duplicate = GivenDefaultRoute(null, "/www/test/"); - duplicate.UpstreamHttpMethod = new(); - - this.Given(x => x.GivenAConfiguration(route, duplicate)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsValid()) - .BDDfy(); + duplicate.UpstreamHttpMethod = new(); + GivenAConfiguration(route, duplicate); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsValid(); } [Fact] - public void Configuration_is_invalid_with_invalid_rate_limit_configuration() + public async Task Configuration_is_invalid_with_invalid_rate_limit_configuration() { + // Arrange var route = GivenDefaultRoute(); route.RateLimitOptions = new FileRateLimitRule { Period = "1x", EnableRateLimiting = true, - }; - this.Given(x => x.GivenAConfiguration(route)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsNotValid()) - .And(x => x.ThenTheErrorMessageAtPositionIs(0, "RateLimitOptions.Period does not contain integer then s (second), m (minute), h (hour), d (day) e.g. 1m for 1 minute period")) - .BDDfy(); + }; + GivenAConfiguration(route); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsNotValid(); + ThenTheErrorMessageAtPositionIs(0, "RateLimitOptions.Period does not contain integer then s (second), m (minute), h (hour), d (day) e.g. 1m for 1 minute period"); } [Fact] - public void Configuration_is_valid_with_valid_rate_limit_configuration() + public async Task Configuration_is_valid_with_valid_rate_limit_configuration() { + // Arrange var route = GivenDefaultRoute(); route.RateLimitOptions = new FileRateLimitRule { Period = "1d", EnableRateLimiting = true, }; - this.Given(x => x.GivenAConfiguration(route)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsValid()) - .BDDfy(); + GivenAConfiguration(route); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsValid(); } [Fact] - public void Configuration_is_valid_with_using_service_discovery_and_service_name() + public async Task Configuration_is_valid_with_using_service_discovery_and_service_name() { + // Arrange var route = GivenServiceDiscoveryRoute(); var config = GivenAConfiguration(route); - config.GlobalConfiguration.ServiceDiscoveryProvider = GivenDefaultServiceDiscoveryProvider(); - this.Given(x => x.GivenAConfiguration(config)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsValid()) - .BDDfy(); + config.GlobalConfiguration.ServiceDiscoveryProvider = GivenDefaultServiceDiscoveryProvider(); + GivenAConfiguration(config); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsValid(); } private const string Empty = ""; @@ -586,15 +719,19 @@ public void Configuration_is_valid_with_using_service_discovery_and_service_name [Theory] [InlineData(null)] [InlineData(Empty)] - public void Configuration_is_invalid_when_not_using_service_discovery_and_host(string downstreamHost) + public async Task Configuration_is_invalid_when_not_using_service_discovery_and_host(string downstreamHost) { + // Arrange var route = GivenDefaultRoute(); route.DownstreamHostAndPorts[0].Host = downstreamHost; - this.Given(x => x.GivenAConfiguration(route)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsNotValid()) - .And(x => x.ThenTheErrorMessageAtPositionIs(0, "When not using service discovery Host must be set on DownstreamHostAndPorts if you are not using Route.Host or Ocelot cannot find your service!")) - .BDDfy(); + GivenAConfiguration(route); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsNotValid(); + ThenTheErrorMessageAtPositionIs(0, "When not using service discovery Host must be set on DownstreamHostAndPorts if you are not using Route.Host or Ocelot cannot find your service!"); } [Theory] @@ -666,58 +803,74 @@ public async Task HaveServiceDiscoveryProviderRegistered_ServiceDiscoveryFinderD } [Fact] - public void Configuration_is_valid_when_not_using_service_discovery_and_host_is_set() + public async Task Configuration_is_valid_when_not_using_service_discovery_and_host_is_set() { + // Arrange var route = GivenDefaultRoute(); route.DownstreamHostAndPorts = new() { new("bbc.co.uk", 123), }; - this.Given(x => x.GivenAConfiguration(route)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsValid()) - .BDDfy(); + GivenAConfiguration(route); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsValid(); } [Fact] - public void Configuration_is_valid_when_no_downstream_but_has_host_and_port() + public async Task Configuration_is_valid_when_no_downstream_but_has_host_and_port() { + // Arrange var route = GivenDefaultRoute(); route.DownstreamHostAndPorts = new() { new("test", 123), }; - this.Given(x => x.GivenAConfiguration(route)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsValid()) - .BDDfy(); + GivenAConfiguration(route); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsValid(); } [Fact] - public void Configuration_is_not_valid_when_no_host_and_port() + public async Task Configuration_is_not_valid_when_no_host_and_port() { + // Arrange var route = GivenDefaultRoute(); route.DownstreamHostAndPorts = new(); - this.Given(x => x.GivenAConfiguration(route)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsNotValid()) - .And(x => x.ThenTheErrorMessageAtPositionIs(0, "When not using service discovery DownstreamHostAndPorts must be set and not empty or Ocelot cannot find your service!")) - .BDDfy(); + GivenAConfiguration(route); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsNotValid(); + ThenTheErrorMessageAtPositionIs(0, "When not using service discovery DownstreamHostAndPorts must be set and not empty or Ocelot cannot find your service!"); } [Fact] - public void Configuration_is_not_valid_when_host_and_port_is_empty() + public async Task Configuration_is_not_valid_when_host_and_port_is_empty() { + // Arrange var route = GivenDefaultRoute(); route.DownstreamHostAndPorts = new() { new(), }; - this.Given(x => x.GivenAConfiguration(route)) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsNotValid()) - .And(x => x.ThenTheErrorMessageAtPositionIs(0, "When not using service discovery Host must be set on DownstreamHostAndPorts if you are not using Route.Host or Ocelot cannot find your service!")) - .BDDfy(); + GivenAConfiguration(route); + + // Act + await WhenIValidateTheConfiguration(); + + // Assert + ThenTheResultIsNotValid(); + ThenTheErrorMessageAtPositionIs(0, "When not using service discovery Host must be set on DownstreamHostAndPorts if you are not using Route.Host or Ocelot cannot find your service!"); } [Fact] @@ -970,7 +1123,7 @@ private void GivenTheAuthSchemeExists(string name) private void GivenAQoSHandler() { - DelegatingHandler Del(DownstreamRoute a, IHttpContextAccessor b, IOcelotLoggerFactory c) => new FakeDelegatingHandler(); + static DelegatingHandler Del(DownstreamRoute a, IHttpContextAccessor b, IOcelotLoggerFactory c) => new FakeDelegatingHandler(); _services.AddSingleton((QosDelegatingHandlerDelegate)Del); _provider = _services.BuildServiceProvider(true); _configurationValidator = new FileConfigurationFluentValidator(_provider, new RouteFluentValidator(_authProvider.Object, new HostAndPortValidator(), new FileQoSOptionsFluentValidator(_provider)), new FileGlobalConfigurationFluentValidator(new FileQoSOptionsFluentValidator(_provider))); @@ -978,8 +1131,8 @@ private void GivenAQoSHandler() private void GivenAServiceDiscoveryHandler() { - ServiceDiscoveryFinderDelegate del = (a, b, c) => new FakeServiceDiscoveryProvider(); - _services.AddSingleton(del); + static IServiceDiscoveryProvider del(IServiceProvider a, ServiceProviderConfiguration b, DownstreamRoute c) => new FakeServiceDiscoveryProvider(); + _services.AddSingleton((ServiceDiscoveryFinderDelegate)del); _provider = _services.BuildServiceProvider(true); _configurationValidator = new FileConfigurationFluentValidator(_provider, new RouteFluentValidator(_authProvider.Object, new HostAndPortValidator(), new FileQoSOptionsFluentValidator(_provider)), new FileGlobalConfigurationFluentValidator(new FileQoSOptionsFluentValidator(_provider))); } @@ -996,13 +1149,8 @@ private class TestHandler : AuthenticationHandler // https://learn.microsoft.com/en-us/dotnet/core/compatibility/aspnet-core/8.0/isystemclock-obsolete // .NET 8.0: TimeProvider is now a settable property on the Options classes for the authentication and identity components. // It can be set directly or by registering a provider in the dependency injection container. -#if NET8_0_OR_GREATER public TestHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder) : base(options, logger, encoder) { } -#else - public TestHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) - { } -#endif protected override Task HandleAuthenticateAsync() { diff --git a/test/Ocelot.UnitTests/Configuration/Validation/FileQoSOptionsFluentValidatorTests.cs b/test/Ocelot.UnitTests/Configuration/Validation/FileQoSOptionsFluentValidatorTests.cs index 22570787b..f09f728ab 100644 --- a/test/Ocelot.UnitTests/Configuration/Validation/FileQoSOptionsFluentValidatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/Validation/FileQoSOptionsFluentValidatorTests.cs @@ -1,4 +1,3 @@ -using FluentValidation.Results; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Ocelot.Configuration; @@ -13,8 +12,6 @@ public class FileQoSOptionsFluentValidatorTests : UnitTest { private FileQoSOptionsFluentValidator _validator; private readonly ServiceCollection _services; - private ValidationResult _result; - private FileQoSOptions _qosOptions; public FileQoSOptionsFluentValidatorTests() { @@ -24,76 +21,59 @@ public FileQoSOptionsFluentValidatorTests() } [Fact] - public void should_be_valid_as_nothing_set() + public void Should_be_valid_as_nothing_set() { - this.Given(_ => GivenThe(new FileQoSOptions())) - .When(_ => WhenIValidate()) - .Then(_ => ThenTheResultIsValid()) - .BDDfy(); + // Arrange + var qosOptions = new FileQoSOptions(); + + // Act + var result = _validator.Validate(qosOptions); + + // Assert + result.IsValid.ShouldBeTrue(); } [Fact] - public void should_be_valid_as_qos_delegate_set() + public void Should_be_valid_as_qos_delegate_set() { + // Arrange var qosOptions = new FileQoSOptions { TimeoutValue = 1, ExceptionsAllowedBeforeBreaking = 1, }; + GivenAQosDelegate(); + + // Act + var result = _validator.Validate(qosOptions); - this.Given(_ => GivenThe(qosOptions)) - .And(_ => GivenAQosDelegate()) - .When(_ => WhenIValidate()) - .Then(_ => ThenTheResultIsValid()) - .BDDfy(); + // Assert + result.IsValid.ShouldBeTrue(); } [Fact] - public void should_be_invalid_as_no_qos_delegate() + public void Should_be_invalid_as_no_qos_delegate() { + // Arrange var qosOptions = new FileQoSOptions { TimeoutValue = 1, ExceptionsAllowedBeforeBreaking = 1, }; - this.Given(_ => GivenThe(qosOptions)) - .When(_ => WhenIValidate()) - .Then(_ => ThenTheResultIsInValid()) - .And(_ => ThenTheErrorIs()) - .BDDfy(); - } + // Act + var result = _validator.Validate(qosOptions); - private void ThenTheErrorIs() - { - _result.Errors[0].ErrorMessage.ShouldBe("Unable to start Ocelot because either a Route or GlobalConfiguration are using QoSOptions but no QosDelegatingHandlerDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Polly and services.AddPolly()?"); - } - - private void ThenTheResultIsInValid() - { - _result.IsValid.ShouldBeFalse(); + // Assert + result.IsValid.ShouldBeFalse(); + result.Errors[0].ErrorMessage.ShouldBe("Unable to start Ocelot because either a Route or GlobalConfiguration are using QoSOptions but no QosDelegatingHandlerDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Polly and services.AddPolly()?"); } private void GivenAQosDelegate() { - DelegatingHandler Fake(DownstreamRoute a, IHttpContextAccessor b, IOcelotLoggerFactory c) => null; + static DelegatingHandler Fake(DownstreamRoute a, IHttpContextAccessor b, IOcelotLoggerFactory c) => null; _services.AddSingleton((QosDelegatingHandlerDelegate)Fake); var provider = _services.BuildServiceProvider(true); _validator = new FileQoSOptionsFluentValidator(provider); } - - private void GivenThe(FileQoSOptions qosOptions) - { - _qosOptions = qosOptions; - } - - private void WhenIValidate() - { - _result = _validator.Validate(_qosOptions); - } - - private void ThenTheResultIsValid() - { - _result.IsValid.ShouldBeTrue(); - } } diff --git a/test/Ocelot.UnitTests/Configuration/Validation/HostAndPortValidatorTests.cs b/test/Ocelot.UnitTests/Configuration/Validation/HostAndPortValidatorTests.cs index 91d8b8ca8..03ead0937 100644 --- a/test/Ocelot.UnitTests/Configuration/Validation/HostAndPortValidatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/Validation/HostAndPortValidatorTests.cs @@ -1,4 +1,3 @@ -using FluentValidation.Results; using Ocelot.Configuration.File; using Ocelot.Configuration.Validator; @@ -6,9 +5,7 @@ namespace Ocelot.UnitTests.Configuration.Validation; public class HostAndPortValidatorTests : UnitTest { - private HostAndPortValidator _validator; - private ValidationResult _result; - private FileHostAndPort _hostAndPort; + private readonly HostAndPortValidator _validator; public HostAndPortValidatorTests() { @@ -18,56 +15,35 @@ public HostAndPortValidatorTests() [Theory] [InlineData(null)] [InlineData("")] - public void should_be_invalid_because_host_empty(string host) + public void Should_be_invalid_because_host_empty(string host) { - var fileHostAndPort = new FileHostAndPort + // Arrange + var hostAndPort = new FileHostAndPort { Host = host, }; - this.Given(_ => GivenThe(fileHostAndPort)) - .When(_ => WhenIValidate()) - .Then(_ => ThenTheResultIsInValid()) - .And(_ => ThenTheErorrIs()) - .BDDfy(); + // Act + var result = _validator.Validate(hostAndPort); + + // Assert + result.IsValid.ShouldBeFalse(); + result.Errors[0].ErrorMessage.ShouldBe("When not using service discovery Host must be set on DownstreamHostAndPorts if you are not using Route.Host or Ocelot cannot find your service!"); } [Fact] - public void should_be_valid_because_host_set() + public void Should_be_valid_because_host_set() { - var fileHostAndPort = new FileHostAndPort + // Arrange + var hostAndPort = new FileHostAndPort { Host = "test", }; - this.Given(_ => GivenThe(fileHostAndPort)) - .When(_ => WhenIValidate()) - .Then(_ => ThenTheResultIsValid()) - .BDDfy(); - } - - private void GivenThe(FileHostAndPort hostAndPort) - { - _hostAndPort = hostAndPort; - } - - private void WhenIValidate() - { - _result = _validator.Validate(_hostAndPort); - } + // Act + var result = _validator.Validate(hostAndPort); - private void ThenTheResultIsValid() - { - _result.IsValid.ShouldBeTrue(); - } - - private void ThenTheErorrIs() - { - _result.Errors[0].ErrorMessage.ShouldBe("When not using service discovery Host must be set on DownstreamHostAndPorts if you are not using Route.Host or Ocelot cannot find your service!"); - } - - private void ThenTheResultIsInValid() - { - _result.IsValid.ShouldBeFalse(); + // Assert + result.IsValid.ShouldBeTrue(); } } diff --git a/test/Ocelot.UnitTests/Configuration/Validation/RouteFluentValidatorTests.cs b/test/Ocelot.UnitTests/Configuration/Validation/RouteFluentValidatorTests.cs index ecf14d620..ba9b37ef4 100644 --- a/test/Ocelot.UnitTests/Configuration/Validation/RouteFluentValidatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/Validation/RouteFluentValidatorTests.cs @@ -11,9 +11,7 @@ public class RouteFluentValidatorTests : UnitTest { private readonly RouteFluentValidator _validator; private readonly Mock _authProvider; - private Mock _serviceProvider; - private FileRoute _route; - private ValidationResult _result; + private readonly Mock _serviceProvider; public RouteFluentValidatorTests() { @@ -25,60 +23,68 @@ public RouteFluentValidatorTests() } [Fact] - public void downstream_path_template_should_not_be_empty() + public async Task Downstream_path_template_should_not_be_empty() { - var fileRoute = new FileRoute(); + // Arrange + var route = new FileRoute(); - this.Given(_ => GivenThe(fileRoute)) - .When(_ => WhenIValidate()) - .Then(_ => ThenTheResultIsInvalid()) - .And(_ => ThenTheErrorsContains("Downstream Path Template cannot be empty")) - .BDDfy(); + // Act + var result = await _validator.ValidateAsync(route); + + // Assert + result.IsValid.ShouldBeFalse(); + result.ThenTheErrorsContains("Downstream Path Template cannot be empty"); } [Fact] - public void upstream_path_template_should_not_be_empty() + public async Task Upstream_path_template_should_not_be_empty() { - var fileRoute = new FileRoute + // Arrange + var route = new FileRoute { DownstreamPathTemplate = "test", }; - this.Given(_ => GivenThe(fileRoute)) - .When(_ => WhenIValidate()) - .Then(_ => ThenTheResultIsInvalid()) - .And(_ => ThenTheErrorsContains("Upstream Path Template cannot be empty")) - .BDDfy(); + // Act + var result = await _validator.ValidateAsync(route); + + // Assert + result.IsValid.ShouldBeFalse(); + result.ThenTheErrorsContains("Upstream Path Template cannot be empty"); } [Fact] - public void downstream_path_template_should_start_with_forward_slash() + public async Task Downstream_path_template_should_start_with_forward_slash() { - var fileRoute = new FileRoute + // Arrange + var route = new FileRoute { DownstreamPathTemplate = "test", }; - this.Given(_ => GivenThe(fileRoute)) - .When(_ => WhenIValidate()) - .Then(_ => ThenTheResultIsInvalid()) - .And(_ => ThenTheErrorsContains("Downstream Path Template test doesnt start with forward slash")) - .BDDfy(); + // Act + var result = await _validator.ValidateAsync(route); + + // Assert + result.IsValid.ShouldBeFalse(); + result.ThenTheErrorsContains("Downstream Path Template test doesnt start with forward slash"); } [Fact] - public void downstream_path_template_should_not_contain_double_forward_slash() + public async Task Downstream_path_template_should_not_contain_double_forward_slash() { - var fileRoute = new FileRoute + // Arrange + var route = new FileRoute { DownstreamPathTemplate = "//test", }; - this.Given(_ => GivenThe(fileRoute)) - .When(_ => WhenIValidate()) - .Then(_ => ThenTheResultIsInvalid()) - .And(_ => ThenTheErrorsContains("Downstream Path Template //test contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature.")) - .BDDfy(); + // Act + var result = await _validator.ValidateAsync(route); + + // Assert + result.IsValid.ShouldBeFalse(); + result.ThenTheErrorsContains("Downstream Path Template //test contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature."); } [Theory] @@ -86,50 +92,56 @@ public void downstream_path_template_should_not_contain_double_forward_slash() [InlineData("http://test")] [InlineData("/test/http://")] [InlineData("/test/https://")] - public void downstream_path_template_should_not_contain_scheme(string downstreamPathTemplate) + public async Task Downstream_path_template_should_not_contain_scheme(string downstreamPathTemplate) { - var fileRoute = new FileRoute + // Arrange + var route = new FileRoute { DownstreamPathTemplate = downstreamPathTemplate, }; - this.Given(_ => GivenThe(fileRoute)) - .When(_ => WhenIValidate()) - .Then(_ => ThenTheResultIsInvalid()) - .And(_ => ThenTheErrorsContains($"Downstream Path Template {downstreamPathTemplate} contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature.")) - .BDDfy(); + // Act + var result = await _validator.ValidateAsync(route); + + // Assert + result.IsValid.ShouldBeFalse(); + result.ThenTheErrorsContains($"Downstream Path Template {downstreamPathTemplate} contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature."); } [Fact] - public void upstream_path_template_should_start_with_forward_slash() + public async Task Upstream_path_template_should_start_with_forward_slash() { - var fileRoute = new FileRoute + // Arrange + var route = new FileRoute { DownstreamPathTemplate = "/test", UpstreamPathTemplate = "test", }; - this.Given(_ => GivenThe(fileRoute)) - .When(_ => WhenIValidate()) - .Then(_ => ThenTheResultIsInvalid()) - .And(_ => ThenTheErrorsContains("Upstream Path Template test doesnt start with forward slash")) - .BDDfy(); + // Act + var result = await _validator.ValidateAsync(route); + + // Assert + result.IsValid.ShouldBeFalse(); + result.ThenTheErrorsContains("Upstream Path Template test doesnt start with forward slash"); } [Fact] - public void upstream_path_template_should_not_contain_double_forward_slash() + public async Task Upstream_path_template_should_not_contain_double_forward_slash() { - var fileRoute = new FileRoute + // Arrange + var route = new FileRoute { DownstreamPathTemplate = "/test", UpstreamPathTemplate = "//test", }; - this.Given(_ => GivenThe(fileRoute)) - .When(_ => WhenIValidate()) - .Then(_ => ThenTheResultIsInvalid()) - .And(_ => ThenTheErrorsContains("Upstream Path Template //test contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature.")) - .BDDfy(); + // Act + var result = await _validator.ValidateAsync(route); + + // Assert + result.IsValid.ShouldBeFalse(); + result.ThenTheErrorsContains("Upstream Path Template //test contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature."); } [Theory] @@ -137,25 +149,28 @@ public void upstream_path_template_should_not_contain_double_forward_slash() [InlineData("http://test")] [InlineData("/test/http://")] [InlineData("/test/https://")] - public void upstream_path_template_should_not_contain_scheme(string upstreamPathTemplate) + public async Task Upstream_path_template_should_not_contain_scheme(string upstreamPathTemplate) { - var fileRoute = new FileRoute + // Arrange + var route = new FileRoute { DownstreamPathTemplate = "/test", UpstreamPathTemplate = upstreamPathTemplate, }; - this.Given(_ => GivenThe(fileRoute)) - .When(_ => WhenIValidate()) - .Then(_ => ThenTheResultIsInvalid()) - .And(_ => ThenTheErrorsContains($"Upstream Path Template {upstreamPathTemplate} contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature.")) - .BDDfy(); + // Act + var result = await _validator.ValidateAsync(route); + + // Assert + result.IsValid.ShouldBeFalse(); + result.ThenTheErrorsContains($"Upstream Path Template {upstreamPathTemplate} contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature."); } [Fact] - public void should_not_be_valid_if_enable_rate_limiting_true_and_period_is_empty() + public async Task Should_not_be_valid_if_enable_rate_limiting_true_and_period_is_empty() { - var fileRoute = new FileRoute + // Arrange + var route = new FileRoute { DownstreamPathTemplate = "/test", UpstreamPathTemplate = "/test", @@ -165,17 +180,19 @@ public void should_not_be_valid_if_enable_rate_limiting_true_and_period_is_empty }, }; - this.Given(_ => GivenThe(fileRoute)) - .When(_ => WhenIValidate()) - .Then(_ => ThenTheResultIsInvalid()) - .And(_ => ThenTheErrorsContains("RateLimitOptions.Period is empty")) - .BDDfy(); + // Act + var result = await _validator.ValidateAsync(route); + + // Assert + result.IsValid.ShouldBeFalse(); + result.ThenTheErrorsContains("RateLimitOptions.Period is empty"); } [Fact] - public void should_not_be_valid_if_enable_rate_limiting_true_and_period_has_value() + public async Task Should_not_be_valid_if_enable_rate_limiting_true_and_period_has_value() { - var fileRoute = new FileRoute + // Arrange + var route = new FileRoute { DownstreamPathTemplate = "/test", UpstreamPathTemplate = "/test", @@ -186,11 +203,12 @@ public void should_not_be_valid_if_enable_rate_limiting_true_and_period_has_valu }, }; - this.Given(_ => GivenThe(fileRoute)) - .When(_ => WhenIValidate()) - .Then(_ => ThenTheResultIsInvalid()) - .And(_ => ThenTheErrorsContains("RateLimitOptions.Period does not contain integer then s (second), m (minute), h (hour), d (day) e.g. 1m for 1 minute period")) - .BDDfy(); + // Act + var result = await _validator.ValidateAsync(route); + + // Assert + result.IsValid.ShouldBeFalse(); + result.ThenTheErrorsContains("RateLimitOptions.Period does not contain integer then s (second), m (minute), h (hour), d (day) e.g. 1m for 1 minute period"); } [Theory] @@ -219,9 +237,10 @@ public void IsValidPeriod_ReflectionLifeHack_BranchesAreCovered(string period, b } [Fact] - public void should_not_be_valid_if_specified_authentication_provider_isnt_registered() + public async Task Should_not_be_valid_if_specified_authentication_provider_isnt_registered() { - var fileRoute = new FileRoute + // Arrange + var route = new FileRoute { DownstreamPathTemplate = "/test", UpstreamPathTemplate = "/test", @@ -231,49 +250,55 @@ public void should_not_be_valid_if_specified_authentication_provider_isnt_regist }, }; - this.Given(_ => GivenThe(fileRoute)) - .When(_ => WhenIValidate()) - .Then(_ => ThenTheResultIsInvalid()) - .And(_ => ThenTheErrorsContains($"Authentication Options AuthenticationProviderKey:'JwtLads',AuthenticationProviderKeys:[],AllowedScopes:[] is unsupported authentication provider")) - .BDDfy(); + // Act + var result = await _validator.ValidateAsync(route); + + // Assert + result.IsValid.ShouldBeFalse(); + result.ThenTheErrorsContains($"Authentication Options AuthenticationProviderKey:'JwtLads',AuthenticationProviderKeys:[],AllowedScopes:[] is unsupported authentication provider"); } [Fact] - public void should_not_be_valid_if_not_using_service_discovery_and_no_host_and_ports() + public async Task Should_not_be_valid_if_not_using_service_discovery_and_no_host_and_ports() { - var fileRoute = new FileRoute + // Arrange + var route = new FileRoute { DownstreamPathTemplate = "/test", UpstreamPathTemplate = "/test", }; - this.Given(_ => GivenThe(fileRoute)) - .When(_ => WhenIValidate()) - .Then(_ => ThenTheResultIsInvalid()) - .And(_ => ThenTheErrorsContains("When not using service discovery DownstreamHostAndPorts must be set and not empty or Ocelot cannot find your service!")) - .BDDfy(); + // Act + var result = await _validator.ValidateAsync(route); + + // Assert + result.IsValid.ShouldBeFalse(); + result.ThenTheErrorsContains("When not using service discovery DownstreamHostAndPorts must be set and not empty or Ocelot cannot find your service!"); } [Fact] - public void should_be_valid_if_using_service_discovery_and_no_host_and_ports() + public async Task Should_be_valid_if_using_service_discovery_and_no_host_and_ports() { - var fileRoute = new FileRoute + // Arrange + var route = new FileRoute { DownstreamPathTemplate = "/test", UpstreamPathTemplate = "/test", ServiceName = "Lads", }; - this.Given(_ => GivenThe(fileRoute)) - .When(_ => WhenIValidate()) - .Then(_ => ThenTheResultIsValid()) - .BDDfy(); + // Act + var result = await _validator.ValidateAsync(route); + + // Assert + result.IsValid.ShouldBeTrue(); } [Fact] - public void should_be_valid_re_route_using_host_and_port_and_paths() + public async Task Should_be_valid_re_route_using_host_and_port_and_paths() { - var fileRoute = new FileRoute + // Arrange + var route = new FileRoute { DownstreamPathTemplate = "/test", UpstreamPathTemplate = "/test", @@ -287,18 +312,19 @@ public void should_be_valid_re_route_using_host_and_port_and_paths() }, }; - this.Given(_ => GivenThe(fileRoute)) - .When(_ => WhenIValidate()) - .Then(_ => ThenTheResultIsValid()) - .BDDfy(); + // Act + var result = await _validator.ValidateAsync(route); + + // Assert + result.IsValid.ShouldBeTrue(); } [Fact] - public void should_be_valid_if_specified_authentication_provider_is_registered() + public async Task Should_be_valid_if_specified_authentication_provider_is_registered() { + // Arrange const string key = "JwtLads"; - - var fileRoute = new FileRoute + var route = new FileRoute { DownstreamPathTemplate = "/test", UpstreamPathTemplate = "/test", @@ -315,12 +341,13 @@ public void should_be_valid_if_specified_authentication_provider_is_registered() }, }, }; + GivenAnAuthProvider(key); - this.Given(_ => GivenThe(fileRoute)) - .And(_ => GivenAnAuthProvider(key)) - .When(_ => WhenIValidate()) - .Then(_ => ThenTheResultIsValid()) - .BDDfy(); + // Act + var result = await _validator.ValidateAsync(route); + + // Assert + result.IsValid.ShouldBeTrue(); } [Theory] @@ -334,9 +361,10 @@ public void should_be_valid_if_specified_authentication_provider_is_registered() [InlineData("2")] [InlineData("")] [InlineData(null)] - public void should_be_valid_re_route_using_downstream_http_version(string version) + public async Task Should_be_valid_re_route_using_downstream_http_version(string version) { - var fileRoute = new FileRoute + // Arrange + var route = new FileRoute { DownstreamPathTemplate = "/test", UpstreamPathTemplate = "/test", @@ -351,10 +379,11 @@ public void should_be_valid_re_route_using_downstream_http_version(string versio DownstreamHttpVersion = version, }; - this.Given(_ => GivenThe(fileRoute)) - .When(_ => WhenIValidate()) - .Then(_ => ThenTheResultIsValid()) - .BDDfy(); + // Act + var result = await _validator.ValidateAsync(route); + + // Assert + result.IsValid.ShouldBeTrue(); } [Theory] @@ -364,9 +393,10 @@ public void should_be_valid_re_route_using_downstream_http_version(string versio [InlineData("a1,1")] [InlineData("12,0")] [InlineData("asdf")] - public void should_be_invalid_re_route_using_downstream_http_version(string version) + public async Task Should_be_invalid_re_route_using_downstream_http_version(string version) { - var fileRoute = new FileRoute + // Arrange + var route = new FileRoute { DownstreamPathTemplate = "/test", UpstreamPathTemplate = "/test", @@ -381,11 +411,12 @@ public void should_be_invalid_re_route_using_downstream_http_version(string vers DownstreamHttpVersion = version, }; - this.Given(_ => GivenThe(fileRoute)) - .When(_ => WhenIValidate()) - .Then(_ => ThenTheResultIsInvalid()) - .And(_ => ThenTheErrorsContains("'Downstream Http Version'")) // this error message changes depending on the OS language - .BDDfy(); + // Act + var result = await _validator.ValidateAsync(route); + + // Assert + result.IsValid.ShouldBeFalse(); + result.ThenTheErrorsContains("'Downstream Http Version'"); // this error message changes depending on the OS language } private void GivenAnAuthProvider(string key) @@ -400,31 +431,6 @@ private void GivenAnAuthProvider(string key) .ReturnsAsync(schemes); } - private void ThenTheResultIsValid() - { - _result.IsValid.ShouldBeTrue(); - } - - private void GivenThe(FileRoute route) - { - _route = route; - } - - private async Task WhenIValidate() - { - _result = await _validator.ValidateAsync(_route); - } - - private void ThenTheResultIsInvalid() - { - _result.IsValid.ShouldBeFalse(); - } - - private void ThenTheErrorsContains(string expected) - { - _result.Errors.ShouldContain(x => x.ErrorMessage.Contains(expected)); - } - private class FakeAutheHandler : IAuthenticationHandler { public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context) @@ -448,3 +454,9 @@ public Task ForbidAsync(AuthenticationProperties properties) } } } + +static class ValidationResultExtensions +{ + public static void ThenTheErrorsContains(this ValidationResult result, string expected) + => result.Errors.ShouldContain(x => x.ErrorMessage.Contains(expected)); +} diff --git a/test/Ocelot.UnitTests/Configuration/VersionCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/VersionCreatorTests.cs index b2bf6a8a4..0f33a0d1d 100644 --- a/test/Ocelot.UnitTests/Configuration/VersionCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/VersionCreatorTests.cs @@ -4,46 +4,27 @@ namespace Ocelot.UnitTests.Configuration; public class VersionCreatorTests : UnitTest { - private readonly HttpVersionCreator _creator; - private string _input; - private Version _result; - - public VersionCreatorTests() - { - _creator = new HttpVersionCreator(); - } - - [Fact] - public void should_create_version_based_on_input() - { - this.Given(_ => GivenTheInput("2.0")) - .When(_ => WhenICreate()) - .Then(_ => ThenTheResultIs(2, 0)) - .BDDfy(); - } + private readonly HttpVersionCreator _creator = new(); [Fact] - public void should_default_to_version_one_point_one() + public void Should_create_version_based_on_input() { - this.Given(_ => GivenTheInput(string.Empty)) - .When(_ => WhenICreate()) - .Then(_ => ThenTheResultIs(1, 1)) - .BDDfy(); - } + // Arrange, Act + var result = _creator.Create("2.0"); - private void GivenTheInput(string input) - { - _input = input; + // Assert + result.Major.ShouldBe(2); + result.Minor.ShouldBe(0); } - private void WhenICreate() + [Fact] + public void Should_default_to_version_one_point_one() { - _result = _creator.Create(_input); - } + // Arrange, Act + var result = _creator.Create(string.Empty); - private void ThenTheResultIs(int major, int minor) - { - _result.Major.ShouldBe(major); - _result.Minor.ShouldBe(minor); + // Assert + result.Major.ShouldBe(1); + result.Minor.ShouldBe(1); } } diff --git a/test/Ocelot.UnitTests/Consul/ConsulFileConfigurationRepositoryTests.cs b/test/Ocelot.UnitTests/Consul/ConsulFileConfigurationRepositoryTests.cs index bf82f3bb2..474c5c1ac 100644 --- a/test/Ocelot.UnitTests/Consul/ConsulFileConfigurationRepositoryTests.cs +++ b/test/Ocelot.UnitTests/Consul/ConsulFileConfigurationRepositoryTests.cs @@ -21,7 +21,6 @@ public class ConsulFileConfigurationRepositoryTests : UnitTest private readonly Mock _client; private readonly Mock _kvEndpoint; private FileConfiguration _fileConfiguration; - private Response _setResult; private Response _getResult; public ConsulFileConfigurationRepositoryTests() @@ -33,97 +32,105 @@ public ConsulFileConfigurationRepositoryTests() _factory = new Mock(); _client = new Mock(); _kvEndpoint = new Mock(); - _client .Setup(x => x.KV) .Returns(_kvEndpoint.Object); - _factory .Setup(x => x.Get(It.IsAny())) .Returns(_client.Object); - _options .SetupGet(x => x.Value) .Returns(() => _fileConfiguration); } [Fact] - public void should_set_config() + public async Task Should_set_config() { - var config = FakeFileConfiguration(); + // Arrange + var config = GivenFakeFileConfiguration(); + GivenWritingToConsulSucceeds(); - this.Given(_ => GivenIHaveAConfiguration(config)) - .And(_ => GivenWritingToConsulSucceeds()) - .When(_ => WhenISetTheConfiguration()) - .Then(_ => ThenTheConfigurationIsStoredAs(config)) - .BDDfy(); + // Act + _ = await _repo.Set(config); + + // Assert + ThenTheConfigurationIsStoredAs(config); } [Fact] - public void should_get_config() + public async Task Should_get_config() { - var config = FakeFileConfiguration(); + // Arrange + var config = _fileConfiguration = GivenFakeFileConfiguration(); + GivenFetchFromConsulSucceeds(); + + // Act + _getResult = await _repo.Get(); - this.Given(_ => GivenIHaveAConfiguration(config)) - .And(_ => GivenFetchFromConsulSucceeds()) - .When(_ => WhenIGetTheConfiguration()) - .Then(_ => ThenTheConfigurationIs(config)) - .BDDfy(); + // Assert + ThenTheConfigurationIs(config); } [Fact] - public void should_get_null_config() + public async Task Should_get_null_config() { - var config = FakeFileConfiguration(); + // Arrange + _fileConfiguration = GivenFakeFileConfiguration(); + GivenFetchFromConsulReturnsNull(); - this.Given(_ => GivenIHaveAConfiguration(config)) - .Given(_ => GivenFetchFromConsulReturnsNull()) - .When(_ => WhenIGetTheConfiguration()) - .Then(_ => ThenTheConfigurationIsNull()) - .BDDfy(); + // Act + _getResult = await _repo.Get(); + + // Assert + _getResult.Data.ShouldBeNull(); } [Fact] - public void should_get_config_from_cache() + public async Task Should_get_config_from_cache() { - var config = FakeFileConfiguration(); + // Arrange + var config = _fileConfiguration = GivenFakeFileConfiguration(); + GivenFetchFromCacheSucceeds(); + + // Act + _getResult = await _repo.Get(); - this.Given(_ => GivenIHaveAConfiguration(config)) - .And(_ => GivenFetchFromCacheSucceeds()) - .When(_ => WhenIGetTheConfiguration()) - .Then(_ => ThenTheConfigurationIs(config)) - .BDDfy(); + // Assert + ThenTheConfigurationIs(config); } [Fact] - public void should_set_config_key() + public async Task Should_set_config_key() { - var config = FakeFileConfiguration(); + // Arrange + _fileConfiguration = GivenFakeFileConfiguration(); + GivenTheConfigKeyComesFromFileConfig("Tom"); + GivenFetchFromConsulSucceeds(); - this.Given(_ => GivenIHaveAConfiguration(config)) - .And(_ => GivenTheConfigKeyComesFromFileConfig("Tom")) - .And(_ => GivenFetchFromConsulSucceeds()) - .When(_ => WhenIGetTheConfiguration()) - .And(_ => ThenTheConfigKeyIs("Tom")) - .BDDfy(); + // Act + _getResult = await _repo.Get(); + + // Assert + ThenTheConfigKeyIs("Tom"); } [Fact] - public void should_set_default_config_key() + public async Task Should_set_default_config_key() { - var config = FakeFileConfiguration(); + // Arrange + _fileConfiguration = GivenFakeFileConfiguration(); + GivenFetchFromConsulSucceeds(); - this.Given(_ => GivenIHaveAConfiguration(config)) - .And(_ => GivenFetchFromConsulSucceeds()) - .When(_ => WhenIGetTheConfiguration()) - .And(_ => ThenTheConfigKeyIs("InternalConfiguration")) - .BDDfy(); + // Act + _getResult = await _repo.Get(); + + // Assert + ThenTheConfigKeyIs("InternalConfiguration"); } private void ThenTheConfigKeyIs(string expected) { - _kvEndpoint - .Verify(x => x.Get(expected, It.IsAny()), Times.Once); + _kvEndpoint.Verify(x => x.Get(expected, It.IsAny()), Times.Once); } private void GivenTheConfigKeyComesFromFileConfig(string key) @@ -132,11 +139,6 @@ private void GivenTheConfigKeyComesFromFileConfig(string key) _repo = new ConsulFileConfigurationRepository(_options.Object, _cache.Object, _factory.Object, _loggerFactory.Object); } - private void ThenTheConfigurationIsNull() - { - _getResult.Data.ShouldBeNull(); - } - private void ThenTheConfigurationIs(FileConfiguration config) { var expected = JsonConvert.SerializeObject(config, Formatting.Indented); @@ -144,20 +146,13 @@ private void ThenTheConfigurationIs(FileConfiguration config) result.ShouldBe(expected); } - private async Task WhenIGetTheConfiguration() - { - _getResult = await _repo.Get(); - } - private void GivenWritingToConsulSucceeds() { var response = new WriteResult { Response = true, }; - - _kvEndpoint - .Setup(x => x.Put(It.IsAny(), It.IsAny())).ReturnsAsync(response); + _kvEndpoint.Setup(x => x.Put(It.IsAny(), It.IsAny())).ReturnsAsync(response); } private void GivenFetchFromCacheSucceeds() @@ -168,56 +163,34 @@ private void GivenFetchFromCacheSucceeds() private void GivenFetchFromConsulReturnsNull() { var result = new QueryResult(); - - _kvEndpoint - .Setup(x => x.Get(It.IsAny(), It.IsAny())) + _kvEndpoint.Setup(x => x.Get(It.IsAny(), It.IsAny())) .ReturnsAsync(result); } private void GivenFetchFromConsulSucceeds() { var json = JsonConvert.SerializeObject(_fileConfiguration, Formatting.Indented); - var bytes = Encoding.UTF8.GetBytes(json); - var kvp = new KVPair("OcelotConfiguration") { Value = bytes, }; - var query = new QueryResult { Response = kvp, }; - - _kvEndpoint - .Setup(x => x.Get(It.IsAny(), It.IsAny())) + _kvEndpoint.Setup(x => x.Get(It.IsAny(), It.IsAny())) .ReturnsAsync(query); } private void ThenTheConfigurationIsStoredAs(FileConfiguration config) { var json = JsonConvert.SerializeObject(config, Formatting.Indented); - var bytes = Encoding.UTF8.GetBytes(json); - - _kvEndpoint - .Verify(x => x.Put(It.Is(k => k.Value.SequenceEqual(bytes)), It.IsAny()), Times.Once); + _kvEndpoint.Verify(x => x.Put(It.Is(k => k.Value.SequenceEqual(bytes)), It.IsAny()), Times.Once); } - private async Task WhenISetTheConfiguration() - { - _setResult = await _repo.Set(_fileConfiguration); - } - - private void GivenIHaveAConfiguration(FileConfiguration config) - { - _fileConfiguration = config; - - _repo = new ConsulFileConfigurationRepository(_options.Object, _cache.Object, _factory.Object, _loggerFactory.Object); - } - - private static FileConfiguration FakeFileConfiguration() + private FileConfiguration GivenFakeFileConfiguration() { var routes = new List { @@ -225,31 +198,27 @@ private static FileConfiguration FakeFileConfiguration() { DownstreamHostAndPorts = new List { - new() - { - Host = "123.12.12.12", - Port = 80, - }, + new("123.12.12.12", 80), }, - DownstreamScheme = "https", + DownstreamScheme = Uri.UriSchemeHttps, DownstreamPathTemplate = "/asdfs/test/{test}", }, }; - var globalConfiguration = new FileGlobalConfiguration { ServiceDiscoveryProvider = new FileServiceDiscoveryProvider { - Scheme = "https", + Scheme = Uri.UriSchemeHttps, Port = 198, Host = "blah", }, }; - - return new FileConfiguration + _fileConfiguration = new FileConfiguration { GlobalConfiguration = globalConfiguration, Routes = routes, }; + _repo = new ConsulFileConfigurationRepository(_options.Object, _cache.Object, _factory.Object, _loggerFactory.Object); + return _fileConfiguration; } } diff --git a/test/Ocelot.UnitTests/Consul/ConsulProviderFactoryTests.cs b/test/Ocelot.UnitTests/Consul/ConsulProviderFactoryTests.cs index 6496ff3ce..923275961 100644 --- a/test/Ocelot.UnitTests/Consul/ConsulProviderFactoryTests.cs +++ b/test/Ocelot.UnitTests/Consul/ConsulProviderFactoryTests.cs @@ -13,7 +13,7 @@ public sealed class ConsulProviderFactoryTests : UnitTest, IDisposable { private readonly ServiceProvider _provider; private readonly IServiceScope _scope; - private readonly HttpContext _context = new DefaultHttpContext(); + private readonly DefaultHttpContext _context = new(); public ConsulProviderFactoryTests() { diff --git a/test/Ocelot.UnitTests/Consul/ConsulTests.cs b/test/Ocelot.UnitTests/Consul/ConsulTests.cs index b6a38fc6d..13f39129a 100644 --- a/test/Ocelot.UnitTests/Consul/ConsulTests.cs +++ b/test/Ocelot.UnitTests/Consul/ConsulTests.cs @@ -11,12 +11,14 @@ namespace Ocelot.UnitTests.Consul; +/// +/// TODO Move to integration tests. +/// public sealed class ConsulTests : UnitTest, IDisposable { private readonly int _port; private readonly string _consulHost; private readonly string _consulScheme; - private readonly string _fakeConsulServiceDiscoveryUrl; private readonly List _consulServiceEntries; private readonly Mock _factory; private readonly Mock _logger; @@ -30,10 +32,9 @@ public sealed class ConsulTests : UnitTest, IDisposable public ConsulTests() { - _port = 8500; + _port = PortFinder.GetRandomPort(); _consulHost = "localhost"; - _consulScheme = "http"; - _fakeConsulServiceDiscoveryUrl = $"{_consulScheme}://{_consulHost}:{_port}"; + _consulScheme = Uri.UriSchemeHttp; _consulServiceEntries = new List(); _factory = new Mock(); _logger = new Mock(); @@ -63,7 +64,7 @@ private void Arrange([CallerMemberName] string serviceName = null) public async Task Should_return_service_from_consul() { Arrange(); - var service1 = GivenService(50881); + var service1 = GivenService(PortFinder.GetRandomPort()); _consulServiceEntries.Add(service1.ToServiceEntry()); GivenThereIsAFakeConsulServiceDiscoveryProvider(); @@ -79,7 +80,7 @@ public async Task Should_use_token() { Arrange(); const string token = "test token"; - var service1 = GivenService(50881); + var service1 = GivenService(PortFinder.GetRandomPort()); _consulServiceEntries.Add(service1.ToServiceEntry()); GivenThereIsAFakeConsulServiceDiscoveryProvider(); var config = new ConsulRegistryConfiguration(_consulScheme, _consulHost, _port, nameof(Should_use_token), token); @@ -97,8 +98,8 @@ public async Task Should_use_token() public async Task Should_not_return_services_with_invalid_address() { Arrange(); - var service1 = GivenService(50881, "http://localhost"); - var service2 = GivenService(50888, "http://localhost"); + var service1 = GivenService(PortFinder.GetRandomPort(), "http://localhost"); + var service2 = GivenService(PortFinder.GetRandomPort(), "http://localhost"); _consulServiceEntries.Add(service1.ToServiceEntry()); _consulServiceEntries.Add(service2.ToServiceEntry()); GivenThereIsAFakeConsulServiceDiscoveryProvider(); @@ -115,8 +116,8 @@ public async Task Should_not_return_services_with_invalid_address() public async Task Should_not_return_services_with_empty_address() { Arrange(); - var service1 = GivenService(50881).WithAddress(string.Empty); - var service2 = GivenService(50888).WithAddress(null); + var service1 = GivenService(PortFinder.GetRandomPort()).WithAddress(string.Empty); + var service2 = GivenService(PortFinder.GetRandomPort()).WithAddress(null); _consulServiceEntries.Add(service1.ToServiceEntry()); _consulServiceEntries.Add(service2.ToServiceEntry()); GivenThereIsAFakeConsulServiceDiscoveryProvider(); @@ -185,12 +186,13 @@ private void ThenTheLoggerHasBeenCalledCorrectlyWithValidationWarning() private void GivenThereIsAFakeConsulServiceDiscoveryProvider([CallerMemberName] string serviceName = "test") { + string url = $"{_consulScheme}://{_consulHost}:{_port}"; _fakeConsulBuilder = TestHostBuilder.Create() - .UseUrls(_fakeConsulServiceDiscoveryUrl) + .UseUrls(url) .UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) .UseIISIntegration() - .UseUrls(_fakeConsulServiceDiscoveryUrl) + .UseUrls(url) .Configure(app => { app.Run(async context => diff --git a/test/Ocelot.UnitTests/Consul/DefaultConsulServiceBuilderTests.cs b/test/Ocelot.UnitTests/Consul/DefaultConsulServiceBuilderTests.cs index 5858efb60..2d49c9f3a 100644 --- a/test/Ocelot.UnitTests/Consul/DefaultConsulServiceBuilderTests.cs +++ b/test/Ocelot.UnitTests/Consul/DefaultConsulServiceBuilderTests.cs @@ -47,7 +47,6 @@ public void Ctor_PrivateMembers_PropertiesAreInitialized() var propConfiguration = sut.GetType().GetProperty("Configuration", BindingFlags.NonPublic | BindingFlags.Instance); // Act - //var actualConfiguration = sut.Configuration; var actualConfiguration = propConfiguration.GetValue(sut); var actualClient = propClient.GetValue(sut); var actualLogger = propLogger.GetValue(sut); diff --git a/test/Ocelot.UnitTests/Consul/OcelotBuilderExtensionsTests.cs b/test/Ocelot.UnitTests/Consul/OcelotBuilderExtensionsTests.cs index c1a2ed096..fd7b4d04c 100644 --- a/test/Ocelot.UnitTests/Consul/OcelotBuilderExtensionsTests.cs +++ b/test/Ocelot.UnitTests/Consul/OcelotBuilderExtensionsTests.cs @@ -34,63 +34,35 @@ private static IWebHostEnvironment GetHostingEnvironment() [Fact] public void AddConsul_ShouldSetUpConsul() { - // Arrange - Exception ex = null; - try - { - // Act - var builder = _services.AddOcelot(_configRoot); - builder.AddConsul(); - } - catch (Exception e) - { - ex = e; - } + // Arrange, Act + var builder = _services.AddOcelot(_configRoot) + .AddConsul(); // Assert - ex.ShouldBeNull(); + builder.ShouldNotBeNull(); } [Fact] public void AddConfigStoredInConsul_ShouldSetUpConsul() { - // Arrange - Exception ex = null; - try - { - // Act - var builder = _services.AddOcelot(_configRoot); - builder.AddConsul().AddConfigStoredInConsul(); - } - catch (Exception e) - { - ex = e; - } + // Arrange, Act + var builder = _services.AddOcelot(_configRoot) + .AddConsul() + .AddConfigStoredInConsul(); // Assert - ex.ShouldBeNull(); + builder.ShouldNotBeNull(); } [Fact] public void AddConsulGeneric_TServiceBuilder_ShouldSetUpConsul() { - // Arrange - Exception ex = null; - IOcelotBuilder builder = null; - try - { - // Act - builder = _services - .AddOcelot(_configRoot) - .AddConsul(); - } - catch (Exception e) - { - ex = e; - } + // Arrange, Act + var builder = _services + .AddOcelot(_configRoot) + .AddConsul(); // Assert - ex.ShouldBeNull(); builder.ShouldNotBeNull(); builder.Services.SingleOrDefault(s => s.ServiceType == typeof(IConsulServiceBuilder)).ShouldNotBeNull(); } diff --git a/test/Ocelot.UnitTests/Consul/PollingConsulServiceDiscoveryProviderTests.cs b/test/Ocelot.UnitTests/Consul/PollingConsulServiceDiscoveryProviderTests.cs index 4b50feaff..212ce224e 100644 --- a/test/Ocelot.UnitTests/Consul/PollingConsulServiceDiscoveryProviderTests.cs +++ b/test/Ocelot.UnitTests/Consul/PollingConsulServiceDiscoveryProviderTests.cs @@ -26,25 +26,31 @@ public PollingConsulServiceDiscoveryProviderTests() } [Fact] - public void should_return_service_from_consul() + public void Should_return_service_from_consul() { + // Arrange var service = new Service(string.Empty, new ServiceHostAndPort(string.Empty, 0), string.Empty, string.Empty, new List()); + GivenConsulReturns(service); - this.Given(x => GivenConsulReturns(service)) - .When(x => WhenIGetTheServices(1)) - .Then(x => ThenTheCountIs(1)) - .BDDfy(); + // Act + WhenIGetTheServices(1); + + // Assert + _result.Count.ShouldBe(1); } [Fact] - public void should_return_service_from_consul_without_delay() + public async Task Should_return_service_from_consul_without_delay() { + // Arrange var service = new Service(string.Empty, new ServiceHostAndPort(string.Empty, 0), string.Empty, string.Empty, new List()); + GivenConsulReturns(service); + + // Act + await WhenIGetTheServicesWithoutDelay(1); - this.Given(x => GivenConsulReturns(service)) - .When(x => WhenIGetTheServicesWithoutDelay(1)) - .Then(x => ThenTheCountIs(1)) - .BDDfy(); + // Assert + _result.Count.ShouldBe(1); } private void GivenConsulReturns(Service service) @@ -53,11 +59,6 @@ private void GivenConsulReturns(Service service) _consulServiceDiscoveryProvider.Setup(x => x.GetAsync()).ReturnsAsync(_services); } - private void ThenTheCountIs(int count) - { - _result.Count.ShouldBe(count); - } - private void WhenIGetTheServices(int expected) { var provider = new PollConsul(_delay, "test", _factory.Object, _consulServiceDiscoveryProvider.Object); diff --git a/test/Ocelot.UnitTests/Controllers/FileConfigurationControllerTests.cs b/test/Ocelot.UnitTests/Controllers/FileConfigurationControllerTests.cs index 51abac911..68a1c9f0b 100644 --- a/test/Ocelot.UnitTests/Controllers/FileConfigurationControllerTests.cs +++ b/test/Ocelot.UnitTests/Controllers/FileConfigurationControllerTests.cs @@ -13,8 +13,6 @@ public class FileConfigurationControllerTests : UnitTest private readonly FileConfigurationController _controller; private readonly Mock _repo; private readonly Mock _setter; - private IActionResult _result; - private FileConfiguration _fileConfiguration; public FileConfigurationControllerTests() { @@ -24,97 +22,61 @@ public FileConfigurationControllerTests() } [Fact] - public void Should_get_file_configuration() + public async Task Should_get_file_configuration() { + // Arrange var expected = new OkResponse(new FileConfiguration()); + _repo.Setup(x => x.Get()).ReturnsAsync(expected); - this.Given(x => x.GivenTheGetConfigurationReturns(expected)) - .When(x => x.WhenIGetTheFileConfiguration()) - .Then(x => x.TheTheGetFileConfigurationIsCalledCorrectly()) - .BDDfy(); + // Act + var result = await _controller.Get(); + + // Assert + _repo.Verify(x => x.Get(), Times.Once); } [Fact] - public void Should_return_error_when_cannot_get_config() + public async Task Should_return_error_when_cannot_get_config() { + // Arrange var expected = new ErrorResponse(It.IsAny()); + _repo.Setup(x => x.Get()).ReturnsAsync(expected); - this.Given(x => x.GivenTheGetConfigurationReturns(expected)) - .When(x => x.WhenIGetTheFileConfiguration()) - .Then(x => x.TheTheGetFileConfigurationIsCalledCorrectly()) - .And(x => x.ThenTheResponseIs()) - .BDDfy(); - } + // Act + var result = await _controller.Get(); - [Fact] - public void Should_post_file_configuration() - { - var expected = new FileConfiguration(); - - this.Given(x => GivenTheFileConfiguration(expected)) - .And(x => GivenTheConfigSetterReturns(new OkResponse())) - .When(x => WhenIPostTheFileConfiguration()) - .Then(x => x.ThenTheConfigrationSetterIsCalledCorrectly()) - .BDDfy(); + // Assert + _repo.Verify(x => x.Get(), Times.Once); + result.ShouldBeOfType(); } [Fact] - public void Should_return_error_when_cannot_set_config() + public async Task Should_post_file_configuration() { + // Arrange var expected = new FileConfiguration(); + _setter.Setup(x => x.Set(It.IsAny())).ReturnsAsync(new OkResponse()); - this.Given(x => GivenTheFileConfiguration(expected)) - .And(x => GivenTheConfigSetterReturns(new ErrorResponse(new FakeError()))) - .When(x => WhenIPostTheFileConfiguration()) - .Then(x => x.ThenTheConfigrationSetterIsCalledCorrectly()) - .And(x => ThenTheResponseIs()) - .BDDfy(); - } - - private void GivenTheConfigSetterReturns(Response response) - { - _setter - .Setup(x => x.Set(It.IsAny())) - .ReturnsAsync(response); - } - - private void ThenTheConfigrationSetterIsCalledCorrectly() - { - _setter - .Verify(x => x.Set(_fileConfiguration), Times.Once); - } - - private async Task WhenIPostTheFileConfiguration() - { - _result = await _controller.Post(_fileConfiguration); - } + // Act + var result = await _controller.Post(expected); - private void GivenTheFileConfiguration(FileConfiguration fileConfiguration) - { - _fileConfiguration = fileConfiguration; - } - - private void ThenTheResponseIs() - { - _result.ShouldBeOfType(); + // Assert + _setter.Verify(x => x.Set(expected), Times.Once); } - private void GivenTheGetConfigurationReturns(Response fileConfiguration) + [Fact] + public async Task Should_return_error_when_cannot_set_config() { - _repo - .Setup(x => x.Get()) - .ReturnsAsync(fileConfiguration); - } + // Arrange + var expected = new FileConfiguration(); + _setter.Setup(x => x.Set(It.IsAny())).ReturnsAsync(new ErrorResponse(new FakeError())); - private async Task WhenIGetTheFileConfiguration() - { - _result = await _controller.Get(); - } + // Act + var result = await _controller.Post(expected); - private void TheTheGetFileConfigurationIsCalledCorrectly() - { - _repo - .Verify(x => x.Get(), Times.Once); + // Assert + _setter.Verify(x => x.Set(expected), Times.Once); + result.ShouldBeOfType(); } private class FakeError : Error diff --git a/test/Ocelot.UnitTests/Controllers/OutputCacheControllerTests.cs b/test/Ocelot.UnitTests/Controllers/OutputCacheControllerTests.cs index e1e124fd0..41848ccb2 100644 --- a/test/Ocelot.UnitTests/Controllers/OutputCacheControllerTests.cs +++ b/test/Ocelot.UnitTests/Controllers/OutputCacheControllerTests.cs @@ -7,31 +7,21 @@ public class OutputCacheControllerTests : UnitTest { private readonly OutputCacheController _controller; private readonly Mock> _cache; - private IActionResult _result; public OutputCacheControllerTests() { - _cache = new Mock>(); - _controller = new OutputCacheController(_cache.Object); + _cache = new(); + _controller = new(_cache.Object); } [Fact] - public void should_delete_key() + public void Delete_ByKey_ClearedRegion() { - this.When(_ => WhenIDeleteTheKey("a")) - .Then(_ => ThenTheKeyIsDeleted("a")) - .BDDfy(); - } + // Arrange, Act + var result = _controller.Delete("a"); - private void ThenTheKeyIsDeleted(string key) - { - _result.ShouldBeOfType(); - _cache - .Verify(x => x.ClearRegion(key), Times.Once); - } - - private void WhenIDeleteTheKey(string key) - { - _result = _controller.Delete(key); + // Assert + result.ShouldBeOfType(); + _cache.Verify(x => x.ClearRegion("a"), Times.Once); } } diff --git a/test/Ocelot.UnitTests/DependencyInjection/ConfigurationBuilderExtensionsTests.cs b/test/Ocelot.UnitTests/DependencyInjection/ConfigurationBuilderExtensionsTests.cs index 8bda08422..3002048e7 100644 --- a/test/Ocelot.UnitTests/DependencyInjection/ConfigurationBuilderExtensionsTests.cs +++ b/test/Ocelot.UnitTests/DependencyInjection/ConfigurationBuilderExtensionsTests.cs @@ -270,7 +270,7 @@ private void WhenIAddOcelotConfigurationWithDefaultFilePaths(string folder, Merg private FileConfiguration ThenTheConfigsAreMergedAndAddedInApplicationConfiguration(bool useCombinedConfig) { - var fc = (FileConfiguration)_configRoot.Get(typeof(FileConfiguration)); + var fc = _configRoot.Get(); fc.GlobalConfiguration.BaseUrl.ShouldBe(useCombinedConfig ? _combinedFileConfiguration.GlobalConfiguration.BaseUrl : _globalConfig.GlobalConfiguration.BaseUrl); fc.GlobalConfiguration.RateLimitOptions.ClientIdHeader.ShouldBe(useCombinedConfig ? _combinedFileConfiguration.GlobalConfiguration.RateLimitOptions.ClientIdHeader : _globalConfig.GlobalConfiguration.RateLimitOptions.ClientIdHeader); @@ -308,7 +308,7 @@ private FileConfiguration ThenTheConfigsAreMergedAndAddedInApplicationConfigurat private void NotContainsEnvSpecificConfig() { - var fc = (FileConfiguration)_configRoot.Get(typeof(FileConfiguration)); + var fc = _configRoot.Get(); fc.Routes.ShouldNotContain(x => x.DownstreamScheme == _envSpecific.Routes[0].DownstreamScheme); fc.Routes.ShouldNotContain(x => x.DownstreamPathTemplate == _envSpecific.Routes[0].DownstreamPathTemplate); fc.Routes.ShouldNotContain(x => x.Key == _envSpecific.Routes[0].Key); diff --git a/test/Ocelot.UnitTests/DependencyInjection/OcelotBuilderTests.cs b/test/Ocelot.UnitTests/DependencyInjection/OcelotBuilderTests.cs index 0a414528b..736282208 100644 --- a/test/Ocelot.UnitTests/DependencyInjection/OcelotBuilderTests.cs +++ b/test/Ocelot.UnitTests/DependencyInjection/OcelotBuilderTests.cs @@ -33,7 +33,6 @@ public class OcelotBuilderTests : UnitTest private readonly IServiceCollection _services; private IServiceProvider _serviceProvider; private IOcelotBuilder _ocelotBuilder; - private Exception _ex; public OcelotBuilderTests() { @@ -46,172 +45,238 @@ public OcelotBuilderTests() private static IWebHostEnvironment GetHostingEnvironment() { var environment = new Mock(); - environment - .Setup(e => e.ApplicationName) + environment.Setup(e => e.ApplicationName) .Returns(typeof(OcelotBuilderTests).GetTypeInfo().Assembly.GetName().Name); - return environment.Object; } [Fact] public void Should_add_specific_delegating_handlers_transient() { - this.Given(x => WhenISetUpOcelotServices()) - .When(x => AddSpecificTransientDelegatingHandler()) - .And(x => AddSpecificTransientDelegatingHandler()) - .Then(x => ThenTheProviderIsRegisteredAndReturnsSpecificHandlers()) - .And(x => ThenTheSpecificHandlersAreTransient()) - .BDDfy(); + // Arrange + _ocelotBuilder = _services.AddOcelot(_configRoot); + + // Act + _ocelotBuilder.AddDelegatingHandler(); + _ocelotBuilder.AddDelegatingHandler(); + + // Assert + ThenTheProviderIsRegisteredAndReturnsSpecificHandlers(); + ThenTheSpecificHandlersAreTransient(); } [Fact] public void Should_add_type_specific_delegating_handlers_transient() { - this.Given(x => WhenISetUpOcelotServices()) - .When(x => AddTypeSpecificTransientDelegatingHandler(typeof(FakeDelegatingHandler))) - .And(x => AddTypeSpecificTransientDelegatingHandler(typeof(FakeDelegatingHandlerTwo))) - .Then(x => ThenTheProviderIsRegisteredAndReturnsSpecificHandlers()) - .And(x => ThenTheSpecificHandlersAreTransient()) - .BDDfy(); + // Arrange + _ocelotBuilder = _services.AddOcelot(_configRoot); + + // Act + _ocelotBuilder.AddDelegatingHandler(typeof(FakeDelegatingHandler)); + _ocelotBuilder.AddDelegatingHandler(typeof(FakeDelegatingHandlerTwo)); + + // Assert + ThenTheProviderIsRegisteredAndReturnsSpecificHandlers(); + ThenTheSpecificHandlersAreTransient(); } [Fact] public void Should_add_global_delegating_handlers_transient() { - this.Given(x => WhenISetUpOcelotServices()) - .When(x => AddTransientGlobalDelegatingHandler()) - .And(x => AddTransientGlobalDelegatingHandler()) - .Then(x => ThenTheProviderIsRegisteredAndReturnsHandlers()) - .And(x => ThenTheGlobalHandlersAreTransient()) - .BDDfy(); + // Arrange + _ocelotBuilder = _services.AddOcelot(_configRoot); + + // Act + _ocelotBuilder.AddDelegatingHandler(true); + _ocelotBuilder.AddDelegatingHandler(true); + + // Assert + ThenTheProviderIsRegisteredAndReturnsHandlers(); + ThenTheGlobalHandlersAreTransient(); } [Fact] public void Should_add_global_type_delegating_handlers_transient() { - this.Given(x => WhenISetUpOcelotServices()) - .When(x => AddTransientGlobalDelegatingHandler()) - .And(x => AddTransientGlobalDelegatingHandler()) - .Then(x => ThenTheProviderIsRegisteredAndReturnsHandlers()) - .And(x => ThenTheGlobalHandlersAreTransient()) - .BDDfy(); + // Arrange + _ocelotBuilder = _services.AddOcelot(_configRoot); + + // Act + _ocelotBuilder.AddDelegatingHandler(true); + _ocelotBuilder.AddDelegatingHandler(true); + + // Assert + ThenTheProviderIsRegisteredAndReturnsHandlers(); + ThenTheGlobalHandlersAreTransient(); } [Fact] public void Should_set_up_services() { - this.When(x => WhenISetUpOcelotServices()) - .Then(x => ThenAnExceptionIsntThrown()) - .BDDfy(); + // Arrange, Act, Assert + _ocelotBuilder = _services.AddOcelot(_configRoot); } [Fact] public void Should_return_ocelot_builder() { - this.When(x => WhenISetUpOcelotServices()) - .Then(x => ThenAnOcelotBuilderIsReturned()) - .BDDfy(); + // Arrange, Act + _ocelotBuilder = _services.AddOcelot(_configRoot); + + // Assert + _ocelotBuilder.ShouldBeOfType(); } [Fact] public void Should_use_logger_factory() { - this.Given(x => WhenISetUpOcelotServices()) - .When(x => WhenIValidateScopes()) - .When(x => WhenIAccessLoggerFactory()) - .Then(x => ThenAnExceptionIsntThrown()) - .BDDfy(); + // Arrange + _ocelotBuilder = _services.AddOcelot(_configRoot); + _serviceProvider = _services.BuildServiceProvider(true); + + // Act + var logger = _serviceProvider.GetService(); + + // Assert + logger.ShouldNotBeNull(); } [Fact] public void Should_set_up_without_passing_in_config() { - this.When(x => WhenISetUpOcelotServicesWithoutConfig()) - .Then(x => ThenAnExceptionIsntThrown()) - .BDDfy(); + // Arrange, Act, Assert + _ocelotBuilder = _services.AddOcelot(); } [Fact] public void Should_add_singleton_defined_aggregators() { - this.Given(x => WhenISetUpOcelotServices()) - .When(x => AddSingletonDefinedAggregator()) - .When(x => AddSingletonDefinedAggregator()) - .Then(x => ThenTheProviderIsRegisteredAndReturnsSpecificAggregators()) - .And(x => ThenTheAggregatorsAreSingleton()) - .BDDfy(); + // Arrange + _ocelotBuilder = _services.AddOcelot(_configRoot); + + // Act + _ocelotBuilder.AddSingletonDefinedAggregator(); + _ocelotBuilder.AddSingletonDefinedAggregator(); + + // Assert + ThenTheProviderIsRegisteredAndReturnsSpecificAggregators(); + + // Then The Aggregators Are Singleton + var aggregators = _serviceProvider.GetServices().ToList(); + var first = aggregators[0]; + aggregators = _serviceProvider.GetServices().ToList(); + var second = aggregators[0]; + first.ShouldBe(second); } [Fact] public void Should_add_transient_defined_aggregators() { - this.Given(x => WhenISetUpOcelotServices()) - .When(x => AddTransientDefinedAggregator()) - .When(x => AddTransientDefinedAggregator()) - .Then(x => ThenTheProviderIsRegisteredAndReturnsSpecificAggregators()) - .And(x => ThenTheAggregatorsAreTransient()) - .BDDfy(); + // Arrange + _ocelotBuilder = _services.AddOcelot(_configRoot); + + // Act + _ocelotBuilder.AddTransientDefinedAggregator(); + _ocelotBuilder.AddTransientDefinedAggregator(); + + // Assert + ThenTheProviderIsRegisteredAndReturnsSpecificAggregators(); + + // Then The Aggregators Are Transient + var aggregators = _serviceProvider.GetServices().ToList(); + var first = aggregators[0]; + aggregators = _serviceProvider.GetServices().ToList(); + var second = aggregators[0]; + first.ShouldNotBe(second); } [Fact] public void Should_add_custom_load_balancer_creators_by_default_ctor() { - this.Given(x => WhenISetUpOcelotServices()) - .When(x => _ocelotBuilder.AddCustomLoadBalancer()) - .Then(x => ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators()) - .BDDfy(); + // Arrange + _ocelotBuilder = _services.AddOcelot(_configRoot); + + // Act + _ocelotBuilder.AddCustomLoadBalancer(); + + // Assert + ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators(); } [Fact] public void Should_add_custom_load_balancer_creators_by_factory_method() { - this.Given(x => WhenISetUpOcelotServices()) - .When(x => _ocelotBuilder.AddCustomLoadBalancer(() => new FakeCustomLoadBalancer())) - .Then(x => ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators()) - .BDDfy(); + // Arrange + _ocelotBuilder = _services.AddOcelot(_configRoot); + + // Act + _ocelotBuilder.AddCustomLoadBalancer(() => new FakeCustomLoadBalancer()); + + // Assert + ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators(); } [Fact] public void Should_add_custom_load_balancer_creators_by_di_factory_method() { - this.Given(x => WhenISetUpOcelotServices()) - .When(x => _ocelotBuilder.AddCustomLoadBalancer(provider => new FakeCustomLoadBalancer())) - .Then(x => ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators()) - .BDDfy(); + // Arrange + _ocelotBuilder = _services.AddOcelot(_configRoot); + + // Act + _ocelotBuilder.AddCustomLoadBalancer(provider => new FakeCustomLoadBalancer()); + + // Assert + ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators(); } [Fact] public void Should_add_custom_load_balancer_creators_by_factory_method_with_arguments() { - this.Given(x => WhenISetUpOcelotServices()) - .When(x => _ocelotBuilder.AddCustomLoadBalancer((route, discoveryProvider) => new FakeCustomLoadBalancer())) - .Then(x => ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators()) - .BDDfy(); + // Arrange + _ocelotBuilder = _services.AddOcelot(_configRoot); + + // Act + _ocelotBuilder.AddCustomLoadBalancer((route, discoveryProvider) => new FakeCustomLoadBalancer()); + + // Assert + ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators(); } [Fact] public void Should_replace_iplaceholder() { - this.Given(x => x.WhenISetUpOcelotServices()) - .When(x => AddConfigPlaceholders()) - .Then(x => ThenAnExceptionIsntThrown()) - .And(x => ThenTheIPlaceholderInstanceIsReplaced()) - .BDDfy(); + // Arrange + _ocelotBuilder = _services.AddOcelot(_configRoot); + + // Act + _ocelotBuilder.AddConfigPlaceholders(); + + // Assert + _serviceProvider = _services.BuildServiceProvider(true); + var placeholders = _serviceProvider.GetService(); + placeholders.ShouldBeOfType(); } [Fact] public void Should_add_custom_load_balancer_creators() { - this.Given(x => WhenISetUpOcelotServices()) - .When(x => _ocelotBuilder.AddCustomLoadBalancer((provider, route, discoveryProvider) => new FakeCustomLoadBalancer())) - .Then(x => ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators()) - .BDDfy(); + // Arrange + _ocelotBuilder = _services.AddOcelot(_configRoot); + + // Act + _ocelotBuilder.AddCustomLoadBalancer((provider, route, discoveryProvider) => new FakeCustomLoadBalancer()); + + // Assert + ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators(); } [Fact] public void Should_use_default_mvc_builder() { - WhenISetUpOcelotServicesWithoutConfig(); + // Arrange, Act + _ocelotBuilder = _services.AddOcelot(); + + // Assert CstorShouldUseDefaultBuilderToInitMvcCoreBuilder(); } @@ -304,9 +369,7 @@ public void Should_use_custom_mvc_builder_with_configuration(bool hasConfig) private IMvcCoreBuilder FakeCustomBuilder(IMvcCoreBuilder builder, Assembly assembly) { _fakeCustomBuilderCalled = true; - - return builder - .AddJsonOptions(options => + return builder.AddJsonOptions(options => { options.JsonSerializerOptions.WriteIndented = true; }); @@ -315,16 +378,9 @@ private IMvcCoreBuilder FakeCustomBuilder(IMvcCoreBuilder builder, Assembly asse private void WhenISetupOcelotServicesWithCustomMvcBuider(IConfiguration configuration = null, bool useConfigParam = false) { _fakeCustomBuilderCalled = false; - try - { - _ocelotBuilder = !useConfigParam - ? _services.AddOcelotUsingBuilder(FakeCustomBuilder) - : _services.AddOcelotUsingBuilder(configuration, FakeCustomBuilder); - } - catch (Exception e) - { - _ex = e; - } + _ocelotBuilder = !useConfigParam + ? _services.AddOcelotUsingBuilder(FakeCustomBuilder) + : _services.AddOcelotUsingBuilder(configuration, FakeCustomBuilder); } private void CstorShouldUseCustomBuilderToInitMvcCoreBuilder() @@ -355,23 +411,6 @@ private void ShouldFindConfiguration() actual.ShouldBe(_configRoot); } - private void AddSingletonDefinedAggregator() - where T : class, IDefinedAggregator - { - _ocelotBuilder.AddSingletonDefinedAggregator(); - } - - private void AddTransientDefinedAggregator() - where T : class, IDefinedAggregator - { - _ocelotBuilder.AddTransientDefinedAggregator(); - } - - private void AddConfigPlaceholders() - { - _ocelotBuilder.AddConfigPlaceholders(); - } - private void ThenTheSpecificHandlersAreTransient() { var handlers = _serviceProvider.GetServices().ToList(); @@ -390,28 +429,6 @@ private void ThenTheGlobalHandlersAreTransient() first.ShouldNotBe(second); } - private void AddTransientGlobalDelegatingHandler() - where T : DelegatingHandler - { - _ocelotBuilder.AddDelegatingHandler(true); - } - - private void AddSpecificTransientDelegatingHandler() - where T : DelegatingHandler - { - _ocelotBuilder.AddDelegatingHandler(); - } - - private void AddTypeTransientGlobalDelegatingHandler(Type type) - { - _ocelotBuilder.AddDelegatingHandler(type, true); - } - - private void AddTypeSpecificTransientDelegatingHandler(Type type) - { - _ocelotBuilder.AddDelegatingHandler(type); - } - private void ThenTheProviderIsRegisteredAndReturnsHandlers() { _serviceProvider = _services.BuildServiceProvider(true); @@ -447,99 +464,10 @@ private void ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalanc creators.Count(c => c.GetType() == typeof(DelegateInvokingLoadBalancerCreator)).ShouldBe(1); } - private void ThenTheAggregatorsAreTransient() - { - var aggregators = _serviceProvider.GetServices().ToList(); - var first = aggregators[0]; - aggregators = _serviceProvider.GetServices().ToList(); - var second = aggregators[0]; - first.ShouldNotBe(second); - } - - private void ThenTheAggregatorsAreSingleton() - { - var aggregators = _serviceProvider.GetServices().ToList(); - var first = aggregators[0]; - aggregators = _serviceProvider.GetServices().ToList(); - var second = aggregators[0]; - first.ShouldBe(second); - } - - private void ThenAnOcelotBuilderIsReturned() - { - _ocelotBuilder.ShouldBeOfType(); - } - - private void ThenTheIPlaceholderInstanceIsReplaced() - { - _serviceProvider = _services.BuildServiceProvider(true); - var placeholders = _serviceProvider.GetService(); - placeholders.ShouldBeOfType(); - } - - private void WhenISetUpOcelotServices() - { - try - { - _ocelotBuilder = _services.AddOcelot(_configRoot); - } - catch (Exception e) - { - _ex = e; - } - } - - private void WhenISetUpOcelotServicesWithoutConfig() - { - try - { - _ocelotBuilder = _services.AddOcelot(); - } - catch (Exception e) - { - _ex = e; - } - } - - private void WhenIAccessLoggerFactory() - { - try - { - _serviceProvider = _services.BuildServiceProvider(true); - var logger = _serviceProvider.GetService(); - logger.ShouldNotBeNull(); - } - catch (Exception e) - { - _ex = e; - } - } - - private void WhenIValidateScopes() - { - try - { - _serviceProvider = _services.BuildServiceProvider(true); - } - catch (Exception e) - { - _ex = e; - } - } - - private void ThenAnExceptionIsntThrown() - { - _ex.ShouldBeNull(); - } - private class FakeCustomLoadBalancer : ILoadBalancer { public string Type => nameof(FakeCustomLoadBalancer); - - // Not relevant for these tests public Task> LeaseAsync(HttpContext httpContext) => throw new NotImplementedException(); - - // Not relevant for these tests public void Release(ServiceHostAndPort hostAndPort) => throw new NotImplementedException(); } } diff --git a/test/Ocelot.UnitTests/DownstreamPathManipulation/ChangeDownstreamPathTemplateTests.cs b/test/Ocelot.UnitTests/DownstreamPathManipulation/ChangeDownstreamPathTemplateTests.cs index b5852609f..f8d9b9cff 100644 --- a/test/Ocelot.UnitTests/DownstreamPathManipulation/ChangeDownstreamPathTemplateTests.cs +++ b/test/Ocelot.UnitTests/DownstreamPathManipulation/ChangeDownstreamPathTemplateTests.cs @@ -29,156 +29,116 @@ public ChangeDownstreamPathTemplateTests() } [Fact] - public void should_change_downstream_path_request() + public void Should_change_downstream_path_request() { - var claims = new List + // Arrange + _claims = new List { new("test", "data"), }; - var placeHolderValues = new List(); - this.Given( - x => x.GivenAClaimToThing(new List - { - new("path-key", string.Empty, string.Empty, 0), - })) - .And(x => x.GivenClaims(claims)) - .And(x => x.GivenDownstreamPathTemplate("/api/test/{path-key}")) - .And(x => x.GivenPlaceholderNameAndValues(placeHolderValues)) - .And(x => x.GivenTheClaimParserReturns(new OkResponse("value"))) - .When(x => x.WhenIChangeDownstreamPath()) - .Then(x => x.ThenTheResultIsSuccess()) - .And(x => x.ThenClaimDataIsContainedInPlaceHolder("{path-key}", "value")) - .BDDfy(); + _placeholderValues = new List(); + _configuration = new List + { + new("path-key", string.Empty, string.Empty, 0), + }; + _downstreamPathTemplate = new DownstreamPathTemplate("/api/test/{path-key}"); + GivenTheClaimParserReturns(new OkResponse("value")); + + // Act + WhenIChangeDownstreamPath(); + + // Assert + _result.IsError.ShouldBeFalse(); + ThenClaimDataIsContainedInPlaceHolder("{path-key}", "value"); } [Fact] - public void should_replace_existing_placeholder_value() + public void Should_replace_existing_placeholder_value() { - var claims = new List + // Arrange + _claims = new List { new("test", "data"), }; - var placeHolderValues = new List + _placeholderValues = new List { new("{path-key}", "old_value"), }; - this.Given( - x => x.GivenAClaimToThing(new List - { - new("path-key", string.Empty, string.Empty, 0), - })) - .And(x => x.GivenClaims(claims)) - .And(x => x.GivenDownstreamPathTemplate("/api/test/{path-key}")) - .And(x => x.GivenPlaceholderNameAndValues(placeHolderValues)) - .And(x => x.GivenTheClaimParserReturns(new OkResponse("value"))) - .When(x => x.WhenIChangeDownstreamPath()) - .Then(x => x.ThenTheResultIsSuccess()) - .And(x => x.ThenClaimDataIsContainedInPlaceHolder("{path-key}", "value")) - .BDDfy(); + _configuration = new List + { + new("path-key", string.Empty, string.Empty, 0), + }; + _downstreamPathTemplate = new DownstreamPathTemplate("/api/test/{path-key}"); + GivenTheClaimParserReturns(new OkResponse("value")); + + // Act + WhenIChangeDownstreamPath(); + + // Assert + _result.IsError.ShouldBeFalse(); + ThenClaimDataIsContainedInPlaceHolder("{path-key}", "value"); } [Fact] - public void should_return_error_when_no_placeholder_in_downstream_path() + public void Should_return_error_when_no_placeholder_in_downstream_path() { - var claims = new List + // Arrange + _claims = new List { new("test", "data"), }; - var placeHolderValues = new List(); - this.Given( - x => x.GivenAClaimToThing(new List - { - new("path-key", string.Empty, string.Empty, 0), - })) - .And(x => x.GivenClaims(claims)) - .And(x => x.GivenDownstreamPathTemplate("/api/test")) - .And(x => x.GivenPlaceholderNameAndValues(placeHolderValues)) - .And(x => x.GivenTheClaimParserReturns(new OkResponse("value"))) - .When(x => x.WhenIChangeDownstreamPath()) - .Then(x => x.ThenTheResultIsCouldNotFindPlaceholderError()) - .BDDfy(); + _placeholderValues = new List(); + _configuration = new List + { + new("path-key", string.Empty, string.Empty, 0), + }; + _downstreamPathTemplate = new DownstreamPathTemplate("/api/test"); + GivenTheClaimParserReturns(new OkResponse("value")); + + // Act + WhenIChangeDownstreamPath(); + + // Assert + _result.IsError.ShouldBe(true); + _result.Errors.Count.ShouldBe(1); + _result.Errors.First().ShouldBeOfType(); } [Fact] - private void should_return_error_when_claim_parser_returns_error() + public void Should_return_error_when_claim_parser_returns_error() { - var claims = new List + // Arrange + _claims = new List { new("test", "data"), }; - var placeHolderValues = new List(); - this.Given( - x => x.GivenAClaimToThing(new List - { - new("path-key", string.Empty, string.Empty, 0), - })) - .And(x => x.GivenClaims(claims)) - .And(x => x.GivenDownstreamPathTemplate("/api/test/{path-key}")) - .And(x => x.GivenPlaceholderNameAndValues(placeHolderValues)) - .And(x => x.GivenTheClaimParserReturns(new ErrorResponse(new List + _placeholderValues = new List(); + _configuration = new List + { + new("path-key", string.Empty, string.Empty, 0), + }; + _downstreamPathTemplate = new DownstreamPathTemplate("/api/test/{path-key}"); + GivenTheClaimParserReturns(new ErrorResponse(new List { new AnyError(), - }))) - .When(x => x.WhenIChangeDownstreamPath()) - .Then(x => x.ThenTheResultIsError()) - .BDDfy(); - } + })); - private void GivenAClaimToThing(List configuration) - { - _configuration = configuration; - } + // Act + WhenIChangeDownstreamPath(); - private void GivenClaims(List claims) - { - _claims = claims; - } - - private void GivenDownstreamPathTemplate(string template) - { - _downstreamPathTemplate = new DownstreamPathTemplate(template); - } - - private void GivenPlaceholderNameAndValues(List placeholders) - { - _placeholderValues = placeholders; + // Assert + _result.IsError.ShouldBe(true); } private void GivenTheClaimParserReturns(Response claimValue) { _claimValue = claimValue; - _parser - .Setup( - x => - x.GetValue(It.IsAny>(), - It.IsAny(), - It.IsAny(), - It.IsAny())) + _parser.Setup(x => x.GetValue(It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(_claimValue); } private void WhenIChangeDownstreamPath() - { - _result = _changeDownstreamPath.ChangeDownstreamPath(_configuration, _claims, - _downstreamPathTemplate, _placeholderValues); - } - - private void ThenTheResultIsSuccess() - { - _result.IsError.ShouldBe(false); - } - - private void ThenTheResultIsCouldNotFindPlaceholderError() - { - _result.IsError.ShouldBe(true); - _result.Errors.Count.ShouldBe(1); - _result.Errors.First().ShouldBeOfType(); - } - - private void ThenTheResultIsError() - { - _result.IsError.ShouldBe(true); - } + => _result = _changeDownstreamPath.ChangeDownstreamPath(_configuration, _claims, _downstreamPathTemplate, _placeholderValues); private void ThenClaimDataIsContainedInPlaceHolder(string name, string value) { diff --git a/test/Ocelot.UnitTests/DownstreamPathManipulation/ClaimsToDownstreamPathMiddlewareTests.cs b/test/Ocelot.UnitTests/DownstreamPathManipulation/ClaimsToDownstreamPathMiddlewareTests.cs index aa485d0a2..9a116a333 100644 --- a/test/Ocelot.UnitTests/DownstreamPathManipulation/ClaimsToDownstreamPathMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/DownstreamPathManipulation/ClaimsToDownstreamPathMiddlewareTests.cs @@ -20,7 +20,7 @@ public class ClaimsToDownstreamPathMiddlewareTests : UnitTest private readonly Mock _logger; private readonly ClaimsToDownstreamPathMiddleware _middleware; private readonly RequestDelegate _next; - private readonly HttpContext _httpContext; + private readonly DefaultHttpContext _httpContext; public ClaimsToDownstreamPathMiddlewareTests() { @@ -35,8 +35,9 @@ public ClaimsToDownstreamPathMiddlewareTests() } [Fact] - public void should_call_add_queries_correctly() + public async Task Should_call_add_queries_correctly() { + // Arrange var downstreamRoute = new Ocelot.DownstreamRouteFinder.DownstreamRouteHolder(new List(), new RouteBuilder() .WithDownstreamRoute(new DownstreamRouteBuilder() @@ -50,43 +51,26 @@ public void should_call_add_queries_correctly() .WithUpstreamHttpMethod(new List { "Get" }) .Build()); - this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) - .And(x => x.GivenTheChangeDownstreamPathReturnsOk()) - .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.ThenChangeDownstreamPathIsCalledCorrectly()) - .BDDfy(); - } - - private async Task WhenICallTheMiddleware() - { - await _middleware.Invoke(_httpContext); - } + // Arrange: Given The Down Stream Route Is + _httpContext.Items.UpsertTemplatePlaceholderNameAndValues(downstreamRoute.TemplatePlaceholderNameAndValues); + _httpContext.Items.UpsertDownstreamRoute(downstreamRoute.Route.DownstreamRoute[0]); - private void GivenTheChangeDownstreamPathReturnsOk() - { - _changePath - .Setup(x => x.ChangeDownstreamPath( + // Arrange: Given The Change Downstream Path Returns Ok + _changePath.Setup(x => x.ChangeDownstreamPath( It.IsAny>(), It.IsAny>(), It.IsAny(), It.IsAny>())) .Returns(new OkResponse()); - } - private void ThenChangeDownstreamPathIsCalledCorrectly() - { - _changePath - .Verify(x => x.ChangeDownstreamPath( + // Act + await _middleware.Invoke(_httpContext); + + // Assert + _changePath.Verify(x => x.ChangeDownstreamPath( It.IsAny>(), It.IsAny>(), _httpContext.Items.DownstreamRoute().DownstreamPathTemplate, _httpContext.Items.TemplatePlaceholderNameAndValues()), Times.Once); } - - private void GivenTheDownStreamRouteIs(Ocelot.DownstreamRouteFinder.DownstreamRouteHolder downstreamRoute) - { - _httpContext.Items.UpsertTemplatePlaceholderNameAndValues(downstreamRoute.TemplatePlaceholderNameAndValues); - - _httpContext.Items.UpsertDownstreamRoute(downstreamRoute.Route.DownstreamRoute[0]); - } } diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteCreatorTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteCreatorTests.cs index f8a65440f..a82f9f64d 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteCreatorTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteCreatorTests.cs @@ -37,8 +37,9 @@ public DownstreamRouteCreatorTests() } [Fact] - public void should_create_downstream_route() + public void Should_create_downstream_route() { + // Arrange var configuration = new InternalConfiguration( null, "doesnt matter", @@ -50,32 +51,31 @@ public void should_create_downstream_route() _handlerOptions, new Version("1.1"), HttpVersionPolicy.RequestVersionOrLower); + GivenTheConfiguration(configuration); - this.Given(_ => GivenTheConfiguration(configuration)) - .When(_ => WhenICreate()) - .Then(_ => ThenTheDownstreamRouteIsCreated()) - .BDDfy(); + // Act + WhenICreate(); + + // Assert + ThenTheDownstreamRouteIsCreated(); } [Fact] - public void should_create_downstream_route_with_rate_limit_options() + public void Should_create_downstream_route_with_rate_limit_options() { + // Arrange var rateLimitOptions = new RateLimitOptionsBuilder() .WithEnableRateLimiting(true) .WithClientIdHeader("test") .Build(); - var downstreamRoute = new DownstreamRouteBuilder() .WithServiceName("auth") .WithRateLimitOptions(rateLimitOptions) .Build(); - var route = new RouteBuilder() .WithDownstreamRoute(downstreamRoute) .Build(); - var routes = new List { route }; - var configuration = new InternalConfiguration( routes, "doesnt matter", @@ -87,17 +87,20 @@ public void should_create_downstream_route_with_rate_limit_options() _handlerOptions, new Version("1.1"), HttpVersionPolicy.RequestVersionOrLower); + GivenTheConfiguration(configuration); - this.Given(_ => GivenTheConfiguration(configuration)) - .When(_ => WhenICreate()) - .Then(_ => ThenTheDownstreamRouteIsCreated()) - .And(_ => WithRateLimitOptions(rateLimitOptions)) - .BDDfy(); + // Act + WhenICreate(); + + // Assert + ThenTheDownstreamRouteIsCreated(); + WithRateLimitOptions(rateLimitOptions); } [Fact] - public void should_cache_downstream_route() + public void Should_cache_downstream_route() { + // Arrange var configuration = new InternalConfiguration( null, "doesnt matter", @@ -109,18 +112,21 @@ public void should_cache_downstream_route() _handlerOptions, new Version("1.1"), HttpVersionPolicy.RequestVersionOrLower); + GivenTheConfiguration(configuration, "/geoffisthebest/"); + + // Act + WhenICreate(); + GivenTheConfiguration(configuration, "/geoffisthebest/"); + WhenICreateAgain(); - this.Given(_ => GivenTheConfiguration(configuration, "/geoffisthebest/")) - .When(_ => WhenICreate()) - .And(_ => GivenTheConfiguration(configuration, "/geoffisthebest/")) - .When(_ => WhenICreateAgain()) - .Then(_ => ThenTheDownstreamRoutesAreTheSameReference()) - .BDDfy(); + // Assert + _result.ShouldBe(_resultTwo); } [Fact] - public void should_not_cache_downstream_route() + public void Should_not_cache_downstream_route() { + // Arrange var configuration = new InternalConfiguration( null, "doesnt matter", @@ -132,18 +138,21 @@ public void should_not_cache_downstream_route() _handlerOptions, new Version("1.1"), HttpVersionPolicy.RequestVersionOrLower); + GivenTheConfiguration(configuration, "/geoffistheworst/"); + + // Act + WhenICreate(); + GivenTheConfiguration(configuration, "/geoffisthebest/"); + WhenICreateAgain(); - this.Given(_ => GivenTheConfiguration(configuration, "/geoffistheworst/")) - .When(_ => WhenICreate()) - .And(_ => GivenTheConfiguration(configuration, "/geoffisthebest/")) - .When(_ => WhenICreateAgain()) - .Then(_ => ThenTheDownstreamRoutesAreTheNotSameReference()) - .BDDfy(); + // Assert + _result.ShouldNotBe(_resultTwo); } [Fact] - public void should_create_downstream_route_with_no_path() + public void Should_create_downstream_route_with_no_path() { + // Arrange var upstreamUrlPath = "/auth/"; var configuration = new InternalConfiguration( null, @@ -156,16 +165,19 @@ public void should_create_downstream_route_with_no_path() _handlerOptions, new Version("1.1"), HttpVersionPolicy.RequestVersionOrLower); + GivenTheConfiguration(configuration, upstreamUrlPath); + + // Act + WhenICreate(); - this.Given(_ => GivenTheConfiguration(configuration, upstreamUrlPath)) - .When(_ => WhenICreate()) - .Then(_ => ThenTheDownstreamPathIsForwardSlash()) - .BDDfy(); + // Assert + ThenTheDownstreamPathIsForwardSlash(); } [Fact] - public void should_create_downstream_route_with_only_first_segment_no_traling_slash() + public void Should_create_downstream_route_with_only_first_segment_no_traling_slash() { + // Arrange var upstreamUrlPath = "/auth"; var configuration = new InternalConfiguration( null, @@ -178,16 +190,19 @@ public void should_create_downstream_route_with_only_first_segment_no_traling_sl _handlerOptions, new Version("1.1"), HttpVersionPolicy.RequestVersionOrLower); + GivenTheConfiguration(configuration, upstreamUrlPath); - this.Given(_ => GivenTheConfiguration(configuration, upstreamUrlPath)) - .When(_ => WhenICreate()) - .Then(_ => ThenTheDownstreamPathIsForwardSlash()) - .BDDfy(); + // Act + WhenICreate(); + + // Assert + ThenTheDownstreamPathIsForwardSlash(); } [Fact] - public void should_create_downstream_route_with_segments_no_traling_slash() + public void Should_create_downstream_route_with_segments_no_traling_slash() { + // Arrange var upstreamUrlPath = "/auth/test"; var configuration = new InternalConfiguration( null, @@ -200,16 +215,19 @@ public void should_create_downstream_route_with_segments_no_traling_slash() _handlerOptions, new Version("1.1"), HttpVersionPolicy.RequestVersionOrHigher); + GivenTheConfiguration(configuration, upstreamUrlPath); + + // Act + WhenICreate(); - this.Given(_ => GivenTheConfiguration(configuration, upstreamUrlPath)) - .When(_ => WhenICreate()) - .Then(_ => ThenThePathDoesNotHaveTrailingSlash()) - .BDDfy(); + // Assert + ThenThePathDoesNotHaveTrailingSlash(); } [Fact] - public void should_create_downstream_route_and_remove_query_string() + public void Should_create_downstream_route_and_remove_query_string() { + // Arrange var upstreamUrlPath = "/auth/test?test=1&best=2"; var configuration = new InternalConfiguration( null, @@ -222,16 +240,19 @@ public void should_create_downstream_route_and_remove_query_string() _handlerOptions, new Version("1.1"), HttpVersionPolicy.RequestVersionOrLower); + GivenTheConfiguration(configuration, upstreamUrlPath); - this.Given(_ => GivenTheConfiguration(configuration, upstreamUrlPath)) - .When(_ => WhenICreate()) - .Then(_ => ThenTheQueryStringIsRemoved()) - .BDDfy(); + // Act + WhenICreate(); + + // Assert + ThenTheQueryStringIsRemoved(); } [Fact] - public void should_create_downstream_route_for_sticky_sessions() + public void Should_create_downstream_route_for_sticky_sessions() { + // Arrange var loadBalancerOptions = new LoadBalancerOptionsBuilder().WithType(nameof(CookieStickySessions)).WithKey("boom").WithExpiryInMs(1).Build(); var configuration = new InternalConfiguration( null, @@ -244,21 +265,23 @@ public void should_create_downstream_route_for_sticky_sessions() _handlerOptions, new Version("1.1"), HttpVersionPolicy.RequestVersionOrLower); + GivenTheConfiguration(configuration); + + // Act + WhenICreate(); - this.Given(_ => GivenTheConfiguration(configuration)) - .When(_ => WhenICreate()) - .Then(_ => ThenTheStickySessionLoadBalancerIsUsed(loadBalancerOptions)) - .BDDfy(); + // Assert + ThenTheStickySessionLoadBalancerIsUsed(loadBalancerOptions); } [Fact] - public void should_create_downstream_route_with_qos() + public void Should_create_downstream_route_with_qos() { + // Arrange var qoSOptions = new QoSOptionsBuilder() .WithExceptionsAllowedBeforeBreaking(1) .WithTimeoutValue(1) .Build(); - var configuration = new InternalConfiguration( null, "doesnt matter", @@ -270,17 +293,20 @@ public void should_create_downstream_route_with_qos() _handlerOptions, new Version("1.1"), HttpVersionPolicy.RequestVersionOrLower); + GivenTheConfiguration(configuration); + GivenTheQosCreatorReturns(qoSOptions); + + // Act + WhenICreate(); - this.Given(_ => GivenTheConfiguration(configuration)) - .And(_ => GivenTheQosCreatorReturns(qoSOptions)) - .When(_ => WhenICreate()) - .Then(_ => ThenTheQosOptionsAreSet(qoSOptions)) - .BDDfy(); + // Assert + ThenTheQosOptionsAreSet(qoSOptions); } [Fact] - public void should_create_downstream_route_with_handler_options() + public void Should_create_downstream_route_with_handler_options() { + // Arrange var configuration = new InternalConfiguration( null, "doesnt matter", @@ -292,17 +318,18 @@ public void should_create_downstream_route_with_handler_options() _handlerOptions, new Version("1.1"), HttpVersionPolicy.RequestVersionOrLower); + GivenTheConfiguration(configuration); - this.Given(_ => GivenTheConfiguration(configuration)) - .When(_ => WhenICreate()) - .Then(_ => ThenTheHandlerOptionsAreSet()) - .BDDfy(); + // Act + WhenICreate(); + + // Assert: Then The Handler Options Are Set + _result.Data.Route.DownstreamRoute[0].HttpHandlerOptions.ShouldBe(_handlerOptions); } private void GivenTheQosCreatorReturns(QoSOptions options) { - _qosOptionsCreator - .Setup(x => x.Create(It.IsAny(), It.IsAny(), It.IsAny>())) + _qosOptionsCreator.Setup(x => x.Create(It.IsAny(), It.IsAny(), It.IsAny>())) .Returns(options); } @@ -383,11 +410,6 @@ private void GivenTheConfiguration(IInternalConfiguration config, string upstrea _configuration = config; } - private void ThenTheHandlerOptionsAreSet() - { - _result.Data.Route.DownstreamRoute[0].HttpHandlerOptions.ShouldBe(_handlerOptions); - } - private void WhenICreate() { _result = _creator.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _configuration, _upstreamHost, _upstreamHeaders); @@ -397,14 +419,4 @@ private void WhenICreateAgain() { _resultTwo = _creator.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _configuration, _upstreamHost, _upstreamHeaders); } - - private void ThenTheDownstreamRoutesAreTheSameReference() - { - _result.ShouldBe(_resultTwo); - } - - private void ThenTheDownstreamRoutesAreTheNotSameReference() - { - _result.ShouldNotBe(_resultTwo); - } } diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs index d3fbf477d..44417aa4b 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs @@ -21,7 +21,7 @@ public class DownstreamRouteFinderMiddlewareTests : UnitTest private readonly Mock _logger; private readonly DownstreamRouteFinderMiddleware _middleware; private readonly RequestDelegate _next; - private readonly HttpContext _httpContext; + private readonly DefaultHttpContext _httpContext; public DownstreamRouteFinderMiddlewareTests() { @@ -37,8 +37,9 @@ public DownstreamRouteFinderMiddlewareTests() } [Fact] - public void should_call_scoped_data_repository_correctly() + public async Task Should_call_scoped_data_repository_correctly() { + // Arrange var config = new InternalConfiguration( null, null, @@ -50,28 +51,23 @@ public void should_call_scoped_data_repository_correctly() new HttpHandlerOptionsBuilder().Build(), new Version("1.1"), HttpVersionPolicy.RequestVersionOrLower); - var downstreamRoute = new DownstreamRouteBuilder() .WithDownstreamPathTemplate("any old string") .WithUpstreamHttpMethod(new List { "Get" }) .Build(); + GivenTheDownStreamRouteFinderReturns(new( + new List(), + new RouteBuilder() + .WithDownstreamRoute(downstreamRoute) + .WithUpstreamHttpMethod(new List { "Get" }) + .Build())); + GivenTheFollowingConfig(config); - this.Given(x => x.GivenTheDownStreamRouteFinderReturns( - new DownstreamRouteHolder( - new List(), - new RouteBuilder() - .WithDownstreamRoute(downstreamRoute) - .WithUpstreamHttpMethod(new List { "Get" }) - .Build()))) - .And(x => GivenTheFollowingConfig(config)) - .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) - .BDDfy(); - } + // Act + await _middleware.Invoke(_httpContext); - private void WhenICallTheMiddleware() - { - _middleware.Invoke(_httpContext).GetAwaiter().GetType(); + // Assert + ThenTheScopedDataRepositoryIsCalledCorrectly(); } private void GivenTheFollowingConfig(IInternalConfiguration config) diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs index 5c7e3079e..0fccfc1d6 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs @@ -1,17 +1,18 @@ -using Ocelot.Configuration; +using Consul; +using Ocelot.Configuration; using Ocelot.Configuration.Builder; using Ocelot.DownstreamRouteFinder; -using Ocelot.DownstreamRouteFinder.Finder; using Ocelot.DownstreamRouteFinder.HeaderMatcher; using Ocelot.DownstreamRouteFinder.UrlMatcher; using Ocelot.Responses; -using Ocelot.Values; +using Ocelot.Values; +using _DownstreamRouteFinder_ = Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteFinder; namespace Ocelot.UnitTests.DownstreamRouteFinder; public class DownstreamRouteFinderTests : UnitTest { - private readonly IDownstreamRouteProvider _downstreamRouteFinder; + private readonly _DownstreamRouteFinder_ _routeFinder; private readonly Mock _mockUrlMatcher; private readonly Mock _mockHeadersMatcher; private readonly Mock _urlPlaceholderFinder; @@ -32,687 +33,724 @@ public DownstreamRouteFinderTests() _mockHeadersMatcher = new Mock(); _urlPlaceholderFinder = new Mock(); _headerPlaceholderFinder = new Mock(); - _downstreamRouteFinder = new Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteFinder(_mockUrlMatcher.Object, _urlPlaceholderFinder.Object, _mockHeadersMatcher.Object, _headerPlaceholderFinder.Object); + _routeFinder = new _DownstreamRouteFinder_(_mockUrlMatcher.Object, _urlPlaceholderFinder.Object, _mockHeadersMatcher.Object, _headerPlaceholderFinder.Object); } [Fact] - public void should_return_highest_priority_when_first() + public void Should_return_highest_priority_when_first() { + // Arrange var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); - - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) - .And(x => x.GivenTheTemplateVariableAndNameFinderReturns( - new OkResponse>(new List()))) - .And(x => x.GivenTheHeaderPlaceholderAndNameFinderReturns(new List())) - .And(x => x.GivenTheConfigurationIs(new List - { - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new List { "Post" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("test", 1, false, "someUpstreamPath")) - .Build()) + _upstreamUrlPath = "someUpstreamPath"; + _upstreamQuery = string.Empty; + GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new())); + GivenTheHeaderPlaceholderAndNameFinderReturns(new List()); + _routesConfig = new() + { + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamHttpMethod(new List { "Post" }) .WithUpstreamPathTemplate(new UpstreamPathTemplate("test", 1, false, "someUpstreamPath")) - .Build(), - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new List { "Post" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("test", 0, false, "someUpstreamPath")) - .Build()) + .Build()) + .WithUpstreamHttpMethod(new List { "Post" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("test", 1, false, "someUpstreamPath")) + .Build(), + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamHttpMethod(new List { "Post" }) .WithUpstreamPathTemplate(new UpstreamPathTemplate("test", 0, false, "someUpstreamPath")) - .Build(), - }, string.Empty, serviceProviderConfig)) - .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) - .And(x => x.GivenTheHeadersMatcherReturns(true)) - .And(x => x.GivenTheUpstreamHttpMethodIs("Post")) - .When(x => x.WhenICallTheFinder()) - .Then(x => x.ThenTheFollowingIsReturned(new DownstreamRouteHolder(new List(), - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamPathTemplate(new UpstreamPathTemplate("test", 1, false, "someUpstreamPath")) - .WithUpstreamHttpMethod(new List { "Post" }) - .Build()) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("test", 1, false, "someUpstreamPath")) - .WithUpstreamHttpMethod(new List { "Post" }) - .Build() - ))) - .BDDfy(); + .Build()) + .WithUpstreamHttpMethod(new List { "Post" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("test", 0, false, "someUpstreamPath")) + .Build(), + }; + GivenTheConfigurationIs(string.Empty, serviceProviderConfig); + GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true))); + GivenTheHeadersMatcherReturns(true); + _upstreamHttpMethod = "Post"; + + // Act + _result = _routeFinder.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _config, _upstreamHost, _upstreamHeaders); + + // Assert + ThenTheFollowingIsReturned(new( + new List(), + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamPathTemplate(new UpstreamPathTemplate("test", 1, false, "someUpstreamPath")) + .WithUpstreamHttpMethod(new List { "Post" }) + .Build()) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("test", 1, false, "someUpstreamPath")) + .WithUpstreamHttpMethod(new List { "Post" }) + .Build() + )); } [Fact] - public void should_return_highest_priority_when_lowest() + public void Should_return_highest_priority_when_lowest() { + // Arrange var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); - - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) - .And(x => x.GivenTheTemplateVariableAndNameFinderReturns( - new OkResponse>(new List()))) - .And(x => x.GivenTheHeaderPlaceholderAndNameFinderReturns(new List())) - .And(x => x.GivenTheConfigurationIs(new List - { - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new List { "Post" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("test", 0, false, "someUpstreamPath")) - .Build()) + _upstreamUrlPath = "someUpstreamPath"; + _upstreamQuery = string.Empty; + GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new())); + GivenTheHeaderPlaceholderAndNameFinderReturns(new List()); + _routesConfig = new() + { + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamHttpMethod(new List { "Post" }) .WithUpstreamPathTemplate(new UpstreamPathTemplate("test", 0, false, "someUpstreamPath")) - .Build(), - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new List { "Post" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("test", 1, false, "someUpstreamPath")) - .Build()) + .Build()) + .WithUpstreamHttpMethod(new List { "Post" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("test", 0, false, "someUpstreamPath")) + .Build(), + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamHttpMethod(new List { "Post" }) .WithUpstreamPathTemplate(new UpstreamPathTemplate("test", 1, false, "someUpstreamPath")) - .Build(), - }, string.Empty, serviceProviderConfig)) - .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) - .And(x => x.GivenTheHeadersMatcherReturns(true)) - .And(x => x.GivenTheUpstreamHttpMethodIs("Post")) - .When(x => x.WhenICallTheFinder()) - .Then(x => x.ThenTheFollowingIsReturned(new DownstreamRouteHolder(new List(), - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamPathTemplate(new UpstreamPathTemplate("test", 1, false, "someUpstreamPath")) - .WithUpstreamHttpMethod(new List { "Post" }) - .Build()) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("test", 1, false, "someUpstreamPath")) - .WithUpstreamHttpMethod(new List { "Post" }) - .Build() - ))) - .BDDfy(); + .Build()) + .WithUpstreamHttpMethod(new List { "Post" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("test", 1, false, "someUpstreamPath")) + .Build(), + }; + GivenTheConfigurationIs(string.Empty, serviceProviderConfig); + GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true))); + GivenTheHeadersMatcherReturns(true); + _upstreamHttpMethod = "Post"; + + // Act + _result = _routeFinder.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _config, _upstreamHost, _upstreamHeaders); + + // Assert + ThenTheFollowingIsReturned(new( + new List(), + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamPathTemplate(new UpstreamPathTemplate("test", 1, false, "someUpstreamPath")) + .WithUpstreamHttpMethod(new List { "Post" }) + .Build()) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("test", 1, false, "someUpstreamPath")) + .WithUpstreamHttpMethod(new List { "Post" }) + .Build() + )); } [Fact] - public void should_return_route() + public void Should_return_route() { + // Arrange var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); - - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher/")) - .And(x => x.GivenTheTemplateVariableAndNameFinderReturns( - new OkResponse>( - new List()))) - .And(x => x.GivenTheHeaderPlaceholderAndNameFinderReturns(new List())) - .And(x => x.GivenTheConfigurationIs(new List - { - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build()) + _upstreamUrlPath = "matchInUrlMatcher/"; + _upstreamQuery = string.Empty; + GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new())); + GivenTheHeaderPlaceholderAndNameFinderReturns(new List()); + _routesConfig = new() + { + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .Build()) + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .Build(), + }; + GivenTheConfigurationIs(string.Empty, serviceProviderConfig); + GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true))); + GivenTheHeadersMatcherReturns(true); + _upstreamHttpMethod = "Get"; + + // Act + _result = _routeFinder.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _config, _upstreamHost, _upstreamHeaders); + + // Assert + ThenTheFollowingIsReturned(new( + new List(), + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamHttpMethod(new List { "Get" }) .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build(), - }, string.Empty, serviceProviderConfig - )) - .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) - .And(x => x.GivenTheHeadersMatcherReturns(true)) - .And(x => x.GivenTheUpstreamHttpMethodIs("Get")) - .When(x => x.WhenICallTheFinder()) - .Then( - x => x.ThenTheFollowingIsReturned(new DownstreamRouteHolder( - new List(), - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build()) - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build() - ))) - .And(x => x.ThenTheUrlMatcherIsCalledCorrectly()) - .BDDfy(); + .Build()) + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .Build() + )); + ThenTheUrlMatcherIsCalledCorrectly(); } [Fact] - public void should_not_append_slash_to_upstream_url_path() + public void Should_not_append_slash_to_upstream_url_path() { + // Arrange var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); - - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher")) - .And(x => x.GivenTheTemplateVariableAndNameFinderReturns( - new OkResponse>( - new List()))) - .And(x => x.GivenTheHeaderPlaceholderAndNameFinderReturns(new List())) - .And(x => x.GivenTheHeaderPlaceholderAndNameFinderReturns(new List())) - .And(x => x.GivenTheConfigurationIs(new List - { - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build()) + _upstreamUrlPath = "matchInUrlMatcher"; + _upstreamQuery = string.Empty; + GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new())); + GivenTheHeaderPlaceholderAndNameFinderReturns(new List()); + GivenTheHeaderPlaceholderAndNameFinderReturns(new List()); + _routesConfig = new() + { + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamHttpMethod(new List { "Get" }) .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build(), - }, string.Empty, serviceProviderConfig - )) - .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) - .And(x => x.GivenTheHeadersMatcherReturns(true)) - .And(x => x.GivenTheUpstreamHttpMethodIs("Get")) - .When(x => x.WhenICallTheFinder()) - .Then( - x => x.ThenTheFollowingIsReturned(new DownstreamRouteHolder( - new List(), - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build()) - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build() - ))) - .And(x => x.ThenTheUrlMatcherIsCalledCorrectly("matchInUrlMatcher")) - .BDDfy(); + .Build()) + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .Build(), + }; + GivenTheConfigurationIs(string.Empty, serviceProviderConfig); + GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true))); + GivenTheHeadersMatcherReturns(true); + _upstreamHttpMethod = "Get"; + + // Act + _result = _routeFinder.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _config, _upstreamHost, _upstreamHeaders); + + // Assert + ThenTheFollowingIsReturned(new( + new List(), + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .Build()) + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .Build() + )); + + // Assert: Then The Url Matcher Is Called Correctly + _mockUrlMatcher.Verify(x => x.Match("matchInUrlMatcher", _upstreamQuery, _routesConfig[0].UpstreamTemplatePattern), Times.Once); } [Fact] - public void should_return_route_if_upstream_path_and_upstream_template_are_the_same() + public void Should_return_route_if_upstream_path_and_upstream_template_are_the_same() { + // Arrange var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); - - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) - .And( - x => - x.GivenTheTemplateVariableAndNameFinderReturns( - new OkResponse>(new List()))) - .And(x => x.GivenTheHeaderPlaceholderAndNameFinderReturns(new List())) - .And(x => x.GivenTheConfigurationIs(new List - { - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build()) + _upstreamUrlPath = "someUpstreamPath"; + _upstreamQuery = string.Empty; + GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new())); + GivenTheHeaderPlaceholderAndNameFinderReturns(new List()); + _routesConfig = new() + { + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .Build()) + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .Build(), + }; + GivenTheConfigurationIs(string.Empty, serviceProviderConfig); + GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true))); + GivenTheHeadersMatcherReturns(true); + _upstreamHttpMethod = "Get"; + + // Act + _result = _routeFinder.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _config, _upstreamHost, _upstreamHeaders); + + // Assert + ThenTheFollowingIsReturned(new( + new List(), + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamHttpMethod(new List { "Get" }) .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build(), - }, string.Empty, serviceProviderConfig - )) - .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) - .And(x => x.GivenTheHeadersMatcherReturns(true)) - .And(x => x.GivenTheUpstreamHttpMethodIs("Get")) - .When(x => x.WhenICallTheFinder()) - .Then( - x => x.ThenTheFollowingIsReturned(new DownstreamRouteHolder(new List(), - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build()) - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build() - ))) - .BDDfy(); + .Build()) + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .Build() + )); } [Fact] - public void should_return_correct_route_for_http_verb() + public void Should_return_correct_route_for_http_verb() { + // Arrange var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); - - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) - .And( - x => - x.GivenTheTemplateVariableAndNameFinderReturns( - new OkResponse>(new List()))) - .And(x => x.GivenTheHeaderPlaceholderAndNameFinderReturns(new List())) - .And(x => x.GivenTheConfigurationIs(new List - { - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) - .Build()) + _upstreamUrlPath = "someUpstreamPath"; + _upstreamQuery = string.Empty; + GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new())); + GivenTheHeaderPlaceholderAndNameFinderReturns(new List()); + _routesConfig = new() + { + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamHttpMethod(new List { "Get" }) .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) - .Build(), - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPathForAPost") - .WithUpstreamHttpMethod(new List { "Post" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) - .Build()) + .Build()) + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) + .Build(), + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPathForAPost") .WithUpstreamHttpMethod(new List { "Post" }) .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) - .Build(), - }, string.Empty, serviceProviderConfig - )) - .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) - .And(x => x.GivenTheHeadersMatcherReturns(true)) - .And(x => x.GivenTheUpstreamHttpMethodIs("Post")) - .When(x => x.WhenICallTheFinder()) - .Then( - x => x.ThenTheFollowingIsReturned(new DownstreamRouteHolder(new List(), - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPathForAPost") - .WithUpstreamHttpMethod(new List { "Post" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) - .Build()) - .WithUpstreamHttpMethod(new List { "Post" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) - .Build() - ))) - .BDDfy(); + .Build()) + .WithUpstreamHttpMethod(new List { "Post" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) + .Build(), + }; + GivenTheConfigurationIs(string.Empty, serviceProviderConfig); + GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true))); + GivenTheHeadersMatcherReturns(true); + _upstreamHttpMethod = "Post"; + + // Act + _result = _routeFinder.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _config, _upstreamHost, _upstreamHeaders); + + // Assert + ThenTheFollowingIsReturned(new( + new List(), + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPathForAPost") + .WithUpstreamHttpMethod(new List { "Post" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) + .Build()) + .WithUpstreamHttpMethod(new List { "Post" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) + .Build() + )); } [Fact] - public void should_not_return_route() + public void Should_not_return_route() { + // Arrange var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); - - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("dontMatchPath/")) - .And(x => x.GivenTheConfigurationIs(new List - { - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("somPath") - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("somePath", 1, false, "someUpstreamPath")) - .Build()) + _upstreamUrlPath = "dontMatchPath/"; + _upstreamQuery = string.Empty; + _routesConfig = new List + { + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("somPath") .WithUpstreamHttpMethod(new List { "Get" }) .WithUpstreamPathTemplate(new UpstreamPathTemplate("somePath", 1, false, "someUpstreamPath")) - .Build(), - }, string.Empty, serviceProviderConfig - )) - .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(false)))) - .And(x => x.GivenTheHeadersMatcherReturns(true)) - .And(x => x.GivenTheUpstreamHttpMethodIs("Get")) - .When(x => x.WhenICallTheFinder()) - .Then( - x => x.ThenAnErrorResponseIsReturned()) - .And(x => x.ThenTheUrlMatcherIsCalledCorrectly()) - .BDDfy(); + .Build()) + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("somePath", 1, false, "someUpstreamPath")) + .Build(), + }; + GivenTheConfigurationIs(string.Empty, serviceProviderConfig); + GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(false))); + GivenTheHeadersMatcherReturns(true); + _upstreamHttpMethod = "Get"; + + // Act + _result = _routeFinder.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _config, _upstreamHost, _upstreamHeaders); + + // Assert + _result.IsError.ShouldBeTrue(); + ThenTheUrlMatcherIsCalledCorrectly(); } [Fact] - public void should_return_correct_route_for_http_verb_setting_multiple_upstream_http_method() + public void Should_return_correct_route_for_http_verb_setting_multiple_upstream_http_method() { + // Arrange var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); - - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) - .And( - x => - x.GivenTheTemplateVariableAndNameFinderReturns( - new OkResponse>(new List()))) - .And(x => x.GivenTheHeaderPlaceholderAndNameFinderReturns(new List())) - .And(x => x.GivenTheConfigurationIs(new List - { - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new List { "Get", "Post" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) - .Build()) + _upstreamUrlPath = "someUpstreamPath"; + _upstreamQuery = string.Empty; + GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new())); + GivenTheHeaderPlaceholderAndNameFinderReturns(new List()); + _routesConfig = new() + { + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamHttpMethod(new List { "Get", "Post" }) .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) - .Build(), - }, string.Empty, serviceProviderConfig - )) - .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) - .And(x => x.GivenTheHeadersMatcherReturns(true)) - .And(x => x.GivenTheUpstreamHttpMethodIs("Post")) - .When(x => x.WhenICallTheFinder()) - .Then( - x => x.ThenTheFollowingIsReturned(new DownstreamRouteHolder(new List(), - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new List { "Post" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) - .Build()) - .WithUpstreamHttpMethod(new List { "Post" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) - .Build() - ))) - .BDDfy(); + .Build()) + .WithUpstreamHttpMethod(new List { "Get", "Post" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) + .Build(), + }; + GivenTheConfigurationIs(string.Empty, serviceProviderConfig); + GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true))); + GivenTheHeadersMatcherReturns(true); + _upstreamHttpMethod = "Post"; + + // Act + _result = _routeFinder.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _config, _upstreamHost, _upstreamHeaders); + + // Assert + ThenTheFollowingIsReturned(new( + new List(), + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamHttpMethod(new List { "Post" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) + .Build()) + .WithUpstreamHttpMethod(new List { "Post" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) + .Build() + )); } [Fact] - public void should_return_correct_route_for_http_verb_setting_all_upstream_http_method() + public void Should_return_correct_route_for_http_verb_setting_all_upstream_http_method() { + // Arrange var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); - - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) - .And( - x => - x.GivenTheTemplateVariableAndNameFinderReturns( - new OkResponse>(new List()))) - .And(x => x.GivenTheHeaderPlaceholderAndNameFinderReturns(new List())) - .And(x => x.GivenTheConfigurationIs(new List - { - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new List()) - .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) - .Build()) + _upstreamUrlPath = "someUpstreamPath"; + _upstreamQuery = string.Empty; + GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new())); + GivenTheHeaderPlaceholderAndNameFinderReturns(new List()); + _routesConfig = new() + { + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamHttpMethod(new List()) .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) - .Build(), - }, string.Empty, serviceProviderConfig - )) - .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) - .And(x => x.GivenTheHeadersMatcherReturns(true)) - .And(x => x.GivenTheUpstreamHttpMethodIs("Post")) - .When(x => x.WhenICallTheFinder()) - .Then( - x => x.ThenTheFollowingIsReturned(new DownstreamRouteHolder(new List(), - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new List { "Post" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) - .Build()) - .WithUpstreamHttpMethod(new List { "Post" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) - .Build() - ))) - .BDDfy(); + .Build()) + .WithUpstreamHttpMethod(new List()) + .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) + .Build(), + }; + GivenTheConfigurationIs(string.Empty, serviceProviderConfig); + GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true))); + GivenTheHeadersMatcherReturns(true); + _upstreamHttpMethod = "Post"; + + // Act + _result = _routeFinder.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _config, _upstreamHost, _upstreamHeaders); + + // Assert + ThenTheFollowingIsReturned(new( + new List(), + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamHttpMethod(new List { "Post" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) + .Build()) + .WithUpstreamHttpMethod(new List { "Post" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) + .Build() + )); } [Fact] - public void should_not_return_route_for_http_verb_not_setting_in_upstream_http_method() + public void Should_not_return_route_for_http_verb_not_setting_in_upstream_http_method() { + // Arrange var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); - - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) - .And( - x => - x.GivenTheTemplateVariableAndNameFinderReturns( - new OkResponse>(new List()))) - .And(x => x.GivenTheHeaderPlaceholderAndNameFinderReturns(new List())) - .And(x => x.GivenTheConfigurationIs(new List - { - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new List { "Get", "Patch", "Delete" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) - .Build()) + _upstreamUrlPath = "someUpstreamPath"; + _upstreamQuery = string.Empty; + GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new())); + GivenTheHeaderPlaceholderAndNameFinderReturns(new List()); + _routesConfig = new() + { + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamHttpMethod(new List { "Get", "Patch", "Delete" }) .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) - .Build(), - }, string.Empty, serviceProviderConfig - )) - .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) - .And(x => x.GivenTheHeadersMatcherReturns(true)) - .And(x => x.GivenTheUpstreamHttpMethodIs("Post")) - .When(x => x.WhenICallTheFinder()) - .Then(x => x.ThenAnErrorResponseIsReturned()) - .And(x => x.ThenTheUrlMatcherIsNotCalled()) - .BDDfy(); + .Build()) + .WithUpstreamHttpMethod(new List { "Get", "Patch", "Delete" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate(string.Empty, 1, false, "someUpstreamPath")) + .Build(), + }; + GivenTheConfigurationIs(string.Empty, serviceProviderConfig); + GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true))); + GivenTheHeadersMatcherReturns(true); + _upstreamHttpMethod = "Post"; + + // Act + _result = _routeFinder.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _config, _upstreamHost, _upstreamHeaders); + + // Assert + _result.IsError.ShouldBeTrue(); + ThenTheUrlMatcherIsNotCalled(); } [Fact] - public void should_return_route_when_host_matches() + public void Should_return_route_when_host_matches() { + // Arrange var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); - - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher/")) - .And(x => GivenTheUpstreamHostIs("MATCH")) - .And(x => x.GivenTheTemplateVariableAndNameFinderReturns( - new OkResponse>( - new List()))) - .And(x => x.GivenTheHeaderPlaceholderAndNameFinderReturns(new List())) - .And(x => x.GivenTheConfigurationIs(new List - { - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build()) - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .WithUpstreamHost("MATCH") - .Build(), - }, string.Empty, serviceProviderConfig - )) - .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) - .And(x => x.GivenTheHeadersMatcherReturns(true)) - .And(x => x.GivenTheUpstreamHttpMethodIs("Get")) - .When(x => x.WhenICallTheFinder()) - .Then( - x => x.ThenTheFollowingIsReturned(new DownstreamRouteHolder( - new List(), - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build()) - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build() - ))) - .And(x => x.ThenTheUrlMatcherIsCalledCorrectly()) - .BDDfy(); + _upstreamUrlPath = "matchInUrlMatcher/"; + _upstreamQuery = string.Empty; + _upstreamHost = "MATCH"; + GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new())); + GivenTheHeaderPlaceholderAndNameFinderReturns(new List()); + _routesConfig = new() + { + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .Build()) + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .WithUpstreamHost("MATCH") + .Build(), + }; + GivenTheConfigurationIs(string.Empty, serviceProviderConfig); + GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true))); + GivenTheHeadersMatcherReturns(true); + _upstreamHttpMethod = "Get"; + + // Act + _result = _routeFinder.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _config, _upstreamHost, _upstreamHeaders); + + // Assert + ThenTheFollowingIsReturned(new( + new List(), + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .Build()) + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .Build() + )); + ThenTheUrlMatcherIsCalledCorrectly(); } [Fact] - public void should_return_route_when_upstreamhost_is_null() + public void Should_return_route_when_upstreamhost_is_null() { + // Arrange var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); - - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher/")) - .And(x => GivenTheUpstreamHostIs("MATCH")) - .And(x => x.GivenTheTemplateVariableAndNameFinderReturns( - new OkResponse>( - new List()))) - .And(x => x.GivenTheHeaderPlaceholderAndNameFinderReturns(new List())) - .And(x => x.GivenTheConfigurationIs(new List - { - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build()) - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build(), - }, string.Empty, serviceProviderConfig - )) - .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) - .And(x => x.GivenTheHeadersMatcherReturns(true)) - .And(x => x.GivenTheUpstreamHttpMethodIs("Get")) - .When(x => x.WhenICallTheFinder()) - .Then( - x => x.ThenTheFollowingIsReturned(new DownstreamRouteHolder( - new List(), - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build()) - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build() - ))) - .And(x => x.ThenTheUrlMatcherIsCalledCorrectly()) - .BDDfy(); + _upstreamUrlPath = "matchInUrlMatcher/"; + _upstreamQuery = string.Empty; + _upstreamHost = "MATCH"; + GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new())); + GivenTheHeaderPlaceholderAndNameFinderReturns(new List()); + _routesConfig = new() + { + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .Build()) + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .Build(), + }; + GivenTheConfigurationIs(string.Empty, serviceProviderConfig); + GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true))); + GivenTheHeadersMatcherReturns(true); + _upstreamHttpMethod = "Get"; + + // Act + _result = _routeFinder.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _config, _upstreamHost, _upstreamHeaders); + + // Assert + ThenTheFollowingIsReturned(new( + new List(), + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .Build()) + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .Build() + )); + ThenTheUrlMatcherIsCalledCorrectly(); } [Fact] - public void should_not_return_route_when_host_doesnt_match() + public void Should_not_return_route_when_host_doesnt_match() { + // Arrange var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); + _upstreamUrlPath = "matchInUrlMatcher/"; + _upstreamQuery = string.Empty; + _upstreamHost = "DONTMATCH"; + GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new())); + GivenTheHeaderPlaceholderAndNameFinderReturns(new List()); + _routesConfig = new() + { + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .Build()) + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .WithUpstreamHost("MATCH") + .Build(), + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamHttpMethod(new List()) // empty list of methods + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .Build()) + .WithUpstreamHttpMethod(new List()) // empty list of methods + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .WithUpstreamHost("MATCH") + .Build(), + }; + GivenTheConfigurationIs(string.Empty, serviceProviderConfig); + GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true))); + GivenTheHeadersMatcherReturns(true); + _upstreamHttpMethod = "Get"; + + // Act + _result = _routeFinder.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _config, _upstreamHost, _upstreamHeaders); - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher/")) - .And(x => GivenTheUpstreamHostIs("DONTMATCH")) - .And(x => x.GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new List()))) - .And(x => x.GivenTheHeaderPlaceholderAndNameFinderReturns(new List())) - .And(x => x.GivenTheConfigurationIs(new List - { - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build()) - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .WithUpstreamHost("MATCH") - .Build(), - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new List()) // empty list of methods - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build()) - .WithUpstreamHttpMethod(new List()) // empty list of methods - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .WithUpstreamHost("MATCH") - .Build(), - }, string.Empty, serviceProviderConfig - )) - .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) - .And(x => x.GivenTheHeadersMatcherReturns(true)) - .And(x => x.GivenTheUpstreamHttpMethodIs("Get")) - .When(x => x.WhenICallTheFinder()) - .Then(x => x.ThenAnErrorResponseIsReturned()) - .And(x => x.ThenTheUrlMatcherIsNotCalled()) - .BDDfy(); + // Assert + _result.IsError.ShouldBeTrue(); + ThenTheUrlMatcherIsNotCalled(); } [Fact] - public void should_not_return_route_when_host_doesnt_match_with_empty_upstream_http_method() + public void Should_not_return_route_when_host_doesnt_match_with_empty_upstream_http_method() { + // Arrange var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); + _upstreamUrlPath = "matchInUrlMatcher/"; + _upstreamQuery = string.Empty; + _upstreamHost = "DONTMATCH"; + GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new())); + GivenTheHeaderPlaceholderAndNameFinderReturns(new List()); + _routesConfig = new() + { + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamHttpMethod(new List()) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .Build()) + .WithUpstreamHttpMethod(new List()) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .WithUpstreamHost("MATCH") + .Build(), + }; + GivenTheConfigurationIs(string.Empty, serviceProviderConfig); + GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true))); + GivenTheHeadersMatcherReturns(true); + _upstreamHttpMethod = "Get"; - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher/")) - .And(x => GivenTheUpstreamHostIs("DONTMATCH")) - .And(x => x.GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new List()))) - .And(x => x.GivenTheHeaderPlaceholderAndNameFinderReturns(new List())) - .And(x => x.GivenTheConfigurationIs(new List - { - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new List()) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build()) - .WithUpstreamHttpMethod(new List()) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .WithUpstreamHost("MATCH") - .Build(), - }, string.Empty, serviceProviderConfig - )) - .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) - .And(x => x.GivenTheHeadersMatcherReturns(true)) - .And(x => x.GivenTheUpstreamHttpMethodIs("Get")) - .When(x => x.WhenICallTheFinder()) - .Then(x => x.ThenAnErrorResponseIsReturned()) - .And(x => x.ThenTheUrlMatcherIsNotCalled()) - .BDDfy(); + // Act + _result = _routeFinder.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _config, _upstreamHost, _upstreamHeaders); + + // Assert + _result.IsError.ShouldBeTrue(); + ThenTheUrlMatcherIsNotCalled(); } [Fact] - public void should_return_route_when_host_does_match_with_empty_upstream_http_method() + public void Should_return_route_when_host_does_match_with_empty_upstream_http_method() { + // Arrange var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); + _upstreamUrlPath = "matchInUrlMatcher/"; + _upstreamQuery = string.Empty; + _upstreamHost = "MATCH"; + GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new())); + GivenTheHeaderPlaceholderAndNameFinderReturns(new List()); + _routesConfig = new() + { + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamHttpMethod(new List()) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .Build()) + .WithUpstreamHttpMethod(new List()) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .WithUpstreamHost("MATCH") + .Build(), + }; + GivenTheConfigurationIs(string.Empty, serviceProviderConfig); + GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true))); + GivenTheHeadersMatcherReturns(true); + _upstreamHttpMethod = "Get"; + + // Act + _result = _routeFinder.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _config, _upstreamHost, _upstreamHeaders); - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher/")) - .And(x => GivenTheUpstreamHostIs("MATCH")) - .And(x => x.GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new List()))) - .And(x => x.GivenTheHeaderPlaceholderAndNameFinderReturns(new List())) - .And(x => x.GivenTheConfigurationIs(new List - { - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new List()) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build()) - .WithUpstreamHttpMethod(new List()) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .WithUpstreamHost("MATCH") - .Build(), - }, string.Empty, serviceProviderConfig - )) - .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) - .And(x => x.GivenTheHeadersMatcherReturns(true)) - .And(x => x.GivenTheUpstreamHttpMethodIs("Get")) - .When(x => x.WhenICallTheFinder()) - .And(x => x.ThenTheUrlMatcherIsCalledCorrectly(1, 0)) - .BDDfy(); + // Assert + ThenTheUrlMatcherIsCalledCorrectly(1, 0); } [Fact] - public void should_return_route_when_host_matches_but_null_host_on_same_path_first() + public void Should_return_route_when_host_matches_but_null_host_on_same_path_first() { + // Arrange var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); - - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher/")) - .And(x => GivenTheUpstreamHostIs("MATCH")) - .And(x => x.GivenTheTemplateVariableAndNameFinderReturns( - new OkResponse>( - new List()))) - .And(x => x.GivenTheHeaderPlaceholderAndNameFinderReturns(new List())) - .And(x => x.GivenTheConfigurationIs(new List - { - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("THENULLPATH") - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build()) - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build(), - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build()) - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .WithUpstreamHost("MATCH") - .Build(), - }, string.Empty, serviceProviderConfig - )) - .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) - .And(x => x.GivenTheHeadersMatcherReturns(true)) - .And(x => x.GivenTheUpstreamHttpMethodIs("Get")) - .When(x => x.WhenICallTheFinder()) - .Then( - x => x.ThenTheFollowingIsReturned(new DownstreamRouteHolder( - new List(), - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "test")) - .Build()) - .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "test")) - .Build() - ))) - .And(x => x.ThenTheUrlMatcherIsCalledCorrectly(1, 0)) - .And(x => x.ThenTheUrlMatcherIsCalledCorrectly(1, 1)) - .BDDfy(); + _upstreamUrlPath = "matchInUrlMatcher/"; + _upstreamQuery = string.Empty; + _upstreamHost = "MATCH"; + GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new())); + GivenTheHeaderPlaceholderAndNameFinderReturns(new List()); + _routesConfig = new() + { + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("THENULLPATH") + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .Build()) + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .Build(), + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .Build()) + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .WithUpstreamHost("MATCH") + .Build(), + }; + GivenTheConfigurationIs(string.Empty, serviceProviderConfig); + GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true))); + GivenTheHeadersMatcherReturns(true); + _upstreamHttpMethod = "Get"; + + // Act + _result = _routeFinder.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _config, _upstreamHost, _upstreamHeaders); + + // Assert + ThenTheFollowingIsReturned(new( + new List(), + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "test")) + .Build()) + .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "test")) + .Build() + )); + ThenTheUrlMatcherIsCalledCorrectly(1, 0); + ThenTheUrlMatcherIsCalledCorrectly(1, 1); } [Fact] @@ -733,48 +771,46 @@ public void Should_return_route_when_upstream_headers_match() ["header1"] = new UpstreamHeaderTemplate("headerValue1", "headerValue1"), ["header2"] = new UpstreamHeaderTemplate("headerValue2", "headerValue2"), }; - var urlPlaceholders = new List { new PlaceholderNameAndValue("url", "urlValue") }; - var headerPlaceholders = new List { new PlaceholderNameAndValue("header", "headerValue") }; - - GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher/"); - GivenTheUpstreamHeadersIs(upstreamHeaders); + var urlPlaceholders = new List { new("url", "urlValue") }; + var headerPlaceholders = new List { new("header", "headerValue") }; + _upstreamUrlPath = "matchInUrlMatcher/"; + _upstreamQuery = string.Empty; + _upstreamHeaders = upstreamHeaders; GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(urlPlaceholders)); GivenTheHeaderPlaceholderAndNameFinderReturns(headerPlaceholders); - GivenTheConfigurationIs( - new() - { - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new() {"Get"}) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build()) + _routesConfig = new() + { + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamHttpMethod(new() {"Get"}) .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .WithUpstreamHeaders(upstreamHeadersConfig) - .Build(), - }, - string.Empty, - serviceProviderConfig); + .Build()) + .WithUpstreamHttpMethod(new() {"Get"}) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .WithUpstreamHeaders(upstreamHeadersConfig) + .Build(), + }; + GivenTheConfigurationIs(string.Empty, serviceProviderConfig); GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true))); GivenTheHeadersMatcherReturns(true); - GivenTheUpstreamHttpMethodIs("Get"); + _upstreamHttpMethod = "Get"; // Act - WhenICallTheFinder(); + _result = _routeFinder.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _config, _upstreamHost, _upstreamHeaders); // Assert - ThenTheFollowingIsReturned(new DownstreamRouteHolder( - urlPlaceholders.Union(headerPlaceholders).ToList(), - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new() { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build()) + ThenTheFollowingIsReturned(new( + urlPlaceholders.Union(headerPlaceholders).ToList(), + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamHttpMethod(new() { "Get" }) .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build() + .Build()) + .WithUpstreamHttpMethod(new() { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .Build() )); ThenTheUrlMatcherIsCalledCorrectly(); } @@ -791,50 +827,45 @@ public void Should_not_return_route_when_upstream_headers_dont_match() ["header1"] = new UpstreamHeaderTemplate("headerValue1", "headerValue1"), ["header2"] = new UpstreamHeaderTemplate("headerValue2", "headerValue2"), }; - - GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher/"); - GivenTheUpstreamHeadersIs(new Dictionary() { { "header1", "headerValue1" } }); + _upstreamUrlPath = "matchInUrlMatcher/"; + _upstreamQuery = string.Empty; + _upstreamHeaders = new Dictionary() { { "header1", "headerValue1" } }; GivenTheTemplateVariableAndNameFinderReturns(new OkResponse>(new List())); GivenTheHeaderPlaceholderAndNameFinderReturns(new List()); - GivenTheConfigurationIs(new List - { - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new() { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build()) - .WithUpstreamHttpMethod(new() { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .WithUpstreamHeaders(upstreamHeadersConfig) - .Build(), - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("someDownstreamPath") - .WithUpstreamHttpMethod(new() { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .Build()) - .WithUpstreamHttpMethod(new() { "Get" }) - .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) - .WithUpstreamHeaders(upstreamHeadersConfig) - .Build(), - }, string.Empty, serviceProviderConfig - ); + _routesConfig = new() + { + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamHttpMethod(new() { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .Build()) + .WithUpstreamHttpMethod(new() { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .WithUpstreamHeaders(upstreamHeadersConfig) + .Build(), + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamHttpMethod(new() { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .Build()) + .WithUpstreamHttpMethod(new() { "Get" }) + .WithUpstreamPathTemplate(new UpstreamPathTemplate("someUpstreamPath", 1, false, "someUpstreamPath")) + .WithUpstreamHeaders(upstreamHeadersConfig) + .Build(), + }; + GivenTheConfigurationIs(string.Empty, serviceProviderConfig); GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true))); GivenTheHeadersMatcherReturns(false); - GivenTheUpstreamHttpMethodIs("Get"); + _upstreamHttpMethod = "Get"; // Act - WhenICallTheFinder(); + _result = _routeFinder.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _config, _upstreamHost, _upstreamHeaders); // Assert - ThenAnErrorResponseIsReturned(); + _result.IsError.ShouldBeTrue(); } - - private void GivenTheUpstreamHostIs(string upstreamHost) - { - _upstreamHost = upstreamHost; - } private void GivenTheTemplateVariableAndNameFinderReturns(Response> response) { @@ -850,21 +881,6 @@ private void GivenTheHeaderPlaceholderAndNameFinderReturns(List upstreamHeaders) - { - _upstreamHeaders = upstreamHeaders; - } - - private void ThenAnErrorResponseIsReturned() - { - _result.IsError.ShouldBeTrue(); - } - private void ThenTheUrlMatcherIsCalledCorrectly() { _mockUrlMatcher @@ -877,12 +893,6 @@ private void ThenTheUrlMatcherIsCalledCorrectly(int times, int index = 0) .Verify(x => x.Match(_upstreamUrlPath, _upstreamQuery, _routesConfig[index].UpstreamTemplatePattern), Times.Exactly(times)); } - private void ThenTheUrlMatcherIsCalledCorrectly(string expectedUpstreamUrlPath) - { - _mockUrlMatcher - .Verify(x => x.Match(expectedUpstreamUrlPath, _upstreamQuery, _routesConfig[0].UpstreamTemplatePattern), Times.Once); - } - private void ThenTheUrlMatcherIsNotCalled() { _mockUrlMatcher @@ -904,9 +914,8 @@ private void GivenTheHeadersMatcherReturns(bool headersMatch) .Returns(headersMatch); } - private void GivenTheConfigurationIs(List routesConfig, string adminPath, ServiceProviderConfiguration serviceProviderConfig) + private void GivenTheConfigurationIs(string adminPath, ServiceProviderConfiguration serviceProviderConfig) { - _routesConfig = routesConfig; _config = new InternalConfiguration( _routesConfig, adminPath, @@ -920,17 +929,6 @@ private void GivenTheConfigurationIs(List routesConfig, string adminPath, HttpVersionPolicy.RequestVersionOrLower); } - private void GivenThereIsAnUpstreamUrlPath(string upstreamUrlPath) - { - _upstreamUrlPath = upstreamUrlPath; - _upstreamQuery = string.Empty; - } - - private void WhenICallTheFinder() - { - _result = _downstreamRouteFinder.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _config, _upstreamHost, _upstreamHeaders); - } - private void ThenTheFollowingIsReturned(DownstreamRouteHolder expected) { _result.Data.Route.DownstreamRoute[0].DownstreamPathTemplate.Value.ShouldBe(expected.Route.DownstreamRoute[0].DownstreamPathTemplate.Value); diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteProviderFactoryTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteProviderFactoryTests.cs index 1cd13adaa..7725e8eb3 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteProviderFactoryTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteProviderFactoryTests.cs @@ -36,138 +36,132 @@ public DownstreamRouteProviderFactoryTests() } [Fact] - public void should_return_downstream_route_finder() + public void Should_return_downstream_route_finder() { - var routes = new List - { - new RouteBuilder().Build(), - }; - - this.Given(_ => GivenTheRoutes(routes)) - .When(_ => WhenIGet()) - .Then(_ => ThenTheResultShouldBe()) - .BDDfy(); - } + // Arrange + var route = new RouteBuilder().Build(); + GivenTheRoutes(route); - [Fact] - public void should_return_downstream_route_finder_when_not_dynamic_re_route_and_service_discovery_on() - { - var spConfig = new ServiceProviderConfigurationBuilder().WithScheme("http").WithHost("test").WithPort(50).WithType("test").Build(); - var routes = new List - { - new RouteBuilder().WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("woot").Build()).Build(), - }; - - this.Given(_ => GivenTheRoutes(routes, spConfig)) - .When(_ => WhenIGet()) - .Then(_ => ThenTheResultShouldBe()) - .BDDfy(); + // Act + _result = _factory.Get(_config); + + // Assert + _result.ShouldBeOfType(); } [Fact] - public void should_return_downstream_route_finder_as_no_service_discovery_given_no_scheme() + public void Should_return_downstream_route_finder_when_not_dynamic_re_route_and_service_discovery_on() { - var spConfig = new ServiceProviderConfigurationBuilder().WithScheme(string.Empty).WithHost("test").WithPort(50).Build(); - var routes = new List(); + // Arrange + var route = new RouteBuilder() + .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("woot").Build()) + .Build(); + var spConfig = new ServiceProviderConfigurationBuilder() + .WithScheme("http").WithHost("test").WithPort(50).WithType("test").Build(); + GivenTheRoutes(route, spConfig); + + // Act + _result = _factory.Get(_config); - this.Given(_ => GivenTheRoutes(routes, spConfig)) - .When(_ => WhenIGet()) - .Then(_ => ThenTheResultShouldBe()) - .BDDfy(); + // Assert + _result.ShouldBeOfType(); } [Fact] - public void should_return_downstream_route_finder_as_no_service_discovery_given_no_host() + public void Should_return_downstream_route_finder_as_no_service_discovery_given_no_scheme() { - var spConfig = new ServiceProviderConfigurationBuilder().WithScheme("http").WithHost(string.Empty).WithPort(50).Build(); - var routes = new List(); + // Arrange + var spConfig = new ServiceProviderConfigurationBuilder() + .WithScheme(string.Empty).WithHost("test").WithPort(50).Build(); + GivenTheRoutes(null, spConfig); + + // Act + _result = _factory.Get(_config); - this.Given(_ => GivenTheRoutes(routes, spConfig)) - .When(_ => WhenIGet()) - .Then(_ => ThenTheResultShouldBe()) - .BDDfy(); + // Assert + _result.ShouldBeOfType(); } [Fact] - public void should_return_downstream_route_finder_given_no_service_discovery_port() + public void Should_return_downstream_route_finder_as_no_service_discovery_given_no_host() { - var spConfig = new ServiceProviderConfigurationBuilder().WithScheme("http").WithHost("localhost").WithPort(0).Build(); - var routes = new List(); + // Arrange + var spConfig = new ServiceProviderConfigurationBuilder() + .WithScheme("http").WithHost(string.Empty).WithPort(50).Build(); + GivenTheRoutes(null, spConfig); - this.Given(_ => GivenTheRoutes(routes, spConfig)) - .When(_ => WhenIGet()) - .Then(_ => ThenTheResultShouldBe()) - .BDDfy(); + // Act + _result = _factory.Get(_config); + + // Assert + _result.ShouldBeOfType(); } [Fact] - public void should_return_downstream_route_finder_given_no_service_discovery_type() + public void Should_return_downstream_route_finder_given_no_service_discovery_port() { - var spConfig = new ServiceProviderConfigurationBuilder().WithScheme("http").WithHost("localhost").WithPort(50).WithType(string.Empty).Build(); - var routes = new List(); + // Arrange + var spConfig = new ServiceProviderConfigurationBuilder() + .WithScheme("http").WithHost("localhost").WithPort(0).Build(); + GivenTheRoutes(null, spConfig); + + // Act + _result = _factory.Get(_config); - this.Given(_ => GivenTheRoutes(routes, spConfig)) - .When(_ => WhenIGet()) - .Then(_ => ThenTheResultShouldBe()) - .BDDfy(); + // Assert + _result.ShouldBeOfType(); } [Fact] - public void should_return_downstream_route_creator() + public void Should_return_downstream_route_finder_given_no_service_discovery_type() { - var spConfig = new ServiceProviderConfigurationBuilder().WithScheme("http").WithHost("test").WithPort(50).WithType("test").Build(); - var routes = new List(); + // Arrange + var spConfig = new ServiceProviderConfigurationBuilder() + .WithScheme("http").WithHost("localhost").WithPort(50).WithType(string.Empty).Build(); + GivenTheRoutes(null, spConfig); - this.Given(_ => GivenTheRoutes(routes, spConfig)) - .When(_ => WhenIGet()) - .Then(_ => ThenTheResultShouldBe()) - .BDDfy(); + // Act + _result = _factory.Get(_config); + + // Assert + _result.ShouldBeOfType(); } [Fact] - public void should_return_downstream_route_creator_with_dynamic_re_route() + public void Should_return_downstream_route_creator() { - var spConfig = new ServiceProviderConfigurationBuilder().WithScheme("http").WithHost("test").WithPort(50).WithType("test").Build(); - var routes = new List - { - new RouteBuilder().Build(), - }; - - this.Given(_ => GivenTheRoutes(routes, spConfig)) - .When(_ => WhenIGet()) - .Then(_ => ThenTheResultShouldBe()) - .BDDfy(); - } + // Arrange + var spConfig = new ServiceProviderConfigurationBuilder() + .WithScheme("http").WithHost("test").WithPort(50).WithType("test").Build(); + GivenTheRoutes(null, spConfig); - private void ThenTheResultShouldBe() - { - _result.ShouldBeOfType(); + // Act + _result = _factory.Get(_config); + + // Assert + _result.ShouldBeOfType(); } - private void WhenIGet() + [Fact] + public void Should_return_downstream_route_creator_with_dynamic_re_route() { + // Arrange + var route = new RouteBuilder().Build(); + var spConfig = new ServiceProviderConfigurationBuilder() + .WithScheme("http").WithHost("test").WithPort(50).WithType("test").Build(); + GivenTheRoutes(route, spConfig); + + // Act _result = _factory.Get(_config); - } - 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"), - HttpVersionPolicy.RequestVersionOrLower); + // Assert + _result.ShouldBeOfType(); } - private void GivenTheRoutes(List routes, ServiceProviderConfiguration config) + private void GivenTheRoutes(Route route, ServiceProviderConfiguration config = null) { _config = new InternalConfiguration( - routes, + route == null ? new() : new() { route }, string.Empty, config, string.Empty, diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/HeaderMatcher/HeaderPlaceholderNameAndValueFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/HeaderMatcher/HeaderPlaceholderNameAndValueFinderTests.cs index b1a767602..c8116a4c8 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/HeaderMatcher/HeaderPlaceholderNameAndValueFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/HeaderMatcher/HeaderPlaceholderNameAndValueFinderTests.cs @@ -8,15 +8,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.HeaderMatcher; [Trait("Feat", "360")] public class HeaderPlaceholderNameAndValueFinderTests : UnitTest { - private readonly IHeaderPlaceholderNameAndValueFinder _finder; - private Dictionary _upstreamHeaders; - private Dictionary _upstreamHeaderTemplates; - private List _result; - - public HeaderPlaceholderNameAndValueFinderTests() - { - _finder = new HeaderPlaceholderNameAndValueFinder(); - } + private readonly HeaderPlaceholderNameAndValueFinder _finder = new(); [Fact] public void Should_return_no_placeholders() @@ -25,14 +17,12 @@ public void Should_return_no_placeholders() var upstreamHeaderTemplates = new Dictionary(); var upstreamHeaders = new Dictionary(); var expected = new List(); - GivenUpstreamHeaderTemplatesAre(upstreamHeaderTemplates); - GivenUpstreamHeadersAre(upstreamHeaders); // Act - WhenICallFindPlaceholders(); + var result = _finder.Find(upstreamHeaders, upstreamHeaderTemplates).ToList(); // Assert - TheResultIs(expected); + TheResultIs(result, expected); } [Fact] @@ -51,14 +41,12 @@ public void Should_return_one_placeholder_with_value_when_no_other_text() { new("{countrycode}", "PL"), }; - GivenUpstreamHeaderTemplatesAre(upstreamHeaderTemplates); - GivenUpstreamHeadersAre(upstreamHeaders); // Act - WhenICallFindPlaceholders(); + var result = _finder.Find(upstreamHeaders, upstreamHeaderTemplates).ToList(); // Assert - TheResultIs(expected); + TheResultIs(result, expected); } [Fact] @@ -77,14 +65,12 @@ public void Should_return_one_placeholder_with_value_when_other_text_on_the_righ { new("{countrycode}", "PL"), }; - GivenUpstreamHeaderTemplatesAre(upstreamHeaderTemplates); - GivenUpstreamHeadersAre(upstreamHeaders); // Act - WhenICallFindPlaceholders(); + var result = _finder.Find(upstreamHeaders, upstreamHeaderTemplates).ToList(); // Assert - TheResultIs(expected); + TheResultIs(result, expected); } [Fact] @@ -103,14 +89,12 @@ public void Should_return_one_placeholder_with_value_when_other_text_on_the_left { new("{countrycode}", "PL"), }; - GivenUpstreamHeaderTemplatesAre(upstreamHeaderTemplates); - GivenUpstreamHeadersAre(upstreamHeaders); // Act - WhenICallFindPlaceholders(); + var result = _finder.Find(upstreamHeaders, upstreamHeaderTemplates).ToList(); // Assert - TheResultIs(expected); + TheResultIs(result, expected); } [Fact] @@ -129,14 +113,12 @@ public void Should_return_one_placeholder_with_value_when_other_texts_surroundin { new("{countrycode}", "PL"), }; - GivenUpstreamHeaderTemplatesAre(upstreamHeaderTemplates); - GivenUpstreamHeadersAre(upstreamHeaders); // Act - WhenICallFindPlaceholders(); + var result = _finder.Find(upstreamHeaders, upstreamHeaderTemplates).ToList(); // Assert - TheResultIs(expected); + TheResultIs(result, expected); } [Fact] @@ -156,14 +138,12 @@ public void Should_return_two_placeholders_with_text_between() new("{countrycode}", "PL"), new("{version}", "v1"), }; - GivenUpstreamHeaderTemplatesAre(upstreamHeaderTemplates); - GivenUpstreamHeadersAre(upstreamHeaders); // Act - WhenICallFindPlaceholders(); + var result = _finder.Find(upstreamHeaders, upstreamHeaderTemplates).ToList(); // Assert - TheResultIs(expected); + TheResultIs(result, expected); } [Fact] @@ -185,36 +165,18 @@ public void Should_return_placeholders_from_different_headers() new("{countrycode}", "PL"), new("{version}", "v1"), }; - GivenUpstreamHeaderTemplatesAre(upstreamHeaderTemplates); - GivenUpstreamHeadersAre(upstreamHeaders); // Act - WhenICallFindPlaceholders(); + var result = _finder.Find(upstreamHeaders, upstreamHeaderTemplates).ToList(); // Assert - TheResultIs(expected); - } - - private void GivenUpstreamHeaderTemplatesAre(Dictionary upstreaHeaderTemplates) - { - _upstreamHeaderTemplates = upstreaHeaderTemplates; - } - - private void GivenUpstreamHeadersAre(Dictionary upstreamHeaders) - { - _upstreamHeaders = upstreamHeaders; - } - - private void WhenICallFindPlaceholders() - { - var result = _finder.Find(_upstreamHeaders, _upstreamHeaderTemplates); - _result = new(result); + TheResultIs(result, expected); } - private void TheResultIs(List expected) + private static void TheResultIs(List actual, List expected) { - _result.ShouldNotBeNull(); - _result.Count.ShouldBe(expected.Count); - _result.ForEach(x => expected.Any(e => e.Name == x.Name && e.Value == x.Value).ShouldBeTrue()); + actual.ShouldNotBeNull(); + actual.Count.ShouldBe(expected.Count); + actual.ForEach(x => expected.Any(e => e.Name == x.Name && e.Value == x.Value).ShouldBeTrue()); } } diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/HeaderMatcher/HeadersToHeaderTemplatesMatcherTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/HeaderMatcher/HeadersToHeaderTemplatesMatcherTests.cs index fae3cc0c5..f8bc0e048 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/HeaderMatcher/HeadersToHeaderTemplatesMatcherTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/HeaderMatcher/HeadersToHeaderTemplatesMatcherTests.cs @@ -7,15 +7,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.HeaderMatcher; [Trait("Feat", "360")] public class HeadersToHeaderTemplatesMatcherTests : UnitTest { - private readonly IHeadersToHeaderTemplatesMatcher _headerMatcher; - private Dictionary _upstreamHeaders; - private Dictionary _templateHeaders; - private bool _result; - - public HeadersToHeaderTemplatesMatcherTests() - { - _headerMatcher = new HeadersToHeaderTemplatesMatcher(); - } + private readonly HeadersToHeaderTemplatesMatcher _matcher = new(); [Fact] public void Should_match_when_no_template_headers() @@ -26,14 +18,12 @@ public void Should_match_when_no_template_headers() ["anyHeader"] = "anyHeaderValue", }; var templateHeaders = new Dictionary(); - GivenIHaveUpstreamHeaders(upstreamHeaders); - GivenIHaveTemplateHeadersInRoute(templateHeaders); // Act - WhenIMatchTheHeaders(); + var result = _matcher.Match(upstreamHeaders, templateHeaders); // Assert - ThenTheResultIsTrue(); + result.ShouldBeTrue(); } [Fact] @@ -48,14 +38,12 @@ public void Should_match_the_same_headers() { ["anyHeader"] = new("^(?i)anyHeaderValue$", "anyHeaderValue"), }; - GivenIHaveUpstreamHeaders(upstreamHeaders); - GivenIHaveTemplateHeadersInRoute(templateHeaders); // Act - WhenIMatchTheHeaders(); + var result = _matcher.Match(upstreamHeaders, templateHeaders); // Assert - ThenTheResultIsTrue(); + result.ShouldBeTrue(); } [Fact] @@ -70,14 +58,12 @@ public void Should_not_match_the_same_headers_when_differ_case_and_case_sensitiv { ["anyHeader"] = new("^anyHeaderValue$", "anyHeaderValue"), }; - GivenIHaveUpstreamHeaders(upstreamHeaders); - GivenIHaveTemplateHeadersInRoute(templateHeaders); // Act - WhenIMatchTheHeaders(); + var result = _matcher.Match(upstreamHeaders, templateHeaders); // Assert - ThenTheResultIsFalse(); + result.ShouldBeFalse(); } [Fact] @@ -92,14 +78,12 @@ public void Should_match_the_same_headers_when_differ_case_and_case_insensitive( { ["anyHeader"] = new("^(?i)anyHeaderValue$", "anyHeaderValue"), }; - GivenIHaveUpstreamHeaders(upstreamHeaders); - GivenIHaveTemplateHeadersInRoute(templateHeaders); // Act - WhenIMatchTheHeaders(); + var result = _matcher.Match(upstreamHeaders, templateHeaders); // Assert - ThenTheResultIsTrue(); + result.ShouldBeTrue(); } [Fact] @@ -114,14 +98,12 @@ public void Should_not_match_different_headers_values() { ["anyHeader"] = new("^(?i)anyHeaderValue$", "anyHeaderValue"), }; - GivenIHaveUpstreamHeaders(upstreamHeaders); - GivenIHaveTemplateHeadersInRoute(templateHeaders); // Act - WhenIMatchTheHeaders(); + var result = _matcher.Match(upstreamHeaders, templateHeaders); // Assert - ThenTheResultIsFalse(); + result.ShouldBeFalse(); } [Fact] @@ -136,14 +118,12 @@ public void Should_not_match_the_same_headers_names() { ["anyHeader"] = new("^(?i)anyHeaderValue$", "anyHeaderValue"), }; - GivenIHaveUpstreamHeaders(upstreamHeaders); - GivenIHaveTemplateHeadersInRoute(templateHeaders); // Act - WhenIMatchTheHeaders(); + var result = _matcher.Match(upstreamHeaders, templateHeaders); // Assert - ThenTheResultIsFalse(); + result.ShouldBeFalse(); } [Fact] @@ -163,14 +143,12 @@ public void Should_match_all_the_same_headers() ["thirdHeader"] = new("^(?i)thirdHeaderValue$", "thirdHeaderValue"), ["anyHeader"] = new("^(?i)anyHeaderValue$", "anyHeaderValue"), }; - GivenIHaveUpstreamHeaders(upstreamHeaders); - GivenIHaveTemplateHeadersInRoute(templateHeaders); // Act - WhenIMatchTheHeaders(); + var result = _matcher.Match(upstreamHeaders, templateHeaders); // Assert - ThenTheResultIsTrue(); + result.ShouldBeTrue(); } [Fact] @@ -190,14 +168,12 @@ public void Should_not_match_the_headers_when_one_of_them_different() ["thirdHeader"] = new("^(?i)thirdHeaderValue$", "thirdHeaderValue"), ["anyHeader"] = new("^(?i)anyHeaderValue$", "anyHeaderValue"), }; - GivenIHaveUpstreamHeaders(upstreamHeaders); - GivenIHaveTemplateHeadersInRoute(templateHeaders); // Act - WhenIMatchTheHeaders(); + var result = _matcher.Match(upstreamHeaders, templateHeaders); // Assert - ThenTheResultIsFalse(); + result.ShouldBeFalse(); } [Fact] @@ -212,14 +188,12 @@ public void Should_match_the_header_with_placeholder() { ["anyHeader"] = new("^(?i)(?.+)$", "{header:countrycode}"), }; - GivenIHaveUpstreamHeaders(upstreamHeaders); - GivenIHaveTemplateHeadersInRoute(templateHeaders); // Act - WhenIMatchTheHeaders(); + var result = _matcher.Match(upstreamHeaders, templateHeaders); // Assert - ThenTheResultIsTrue(); + result.ShouldBeTrue(); } [Fact] @@ -234,14 +208,12 @@ public void Should_match_the_header_with_placeholders() { ["anyHeader"] = new("^(?i)(?.+)-(?.+)$", "{header:countrycode}-{header:version}"), }; - GivenIHaveUpstreamHeaders(upstreamHeaders); - GivenIHaveTemplateHeadersInRoute(templateHeaders); // Act - WhenIMatchTheHeaders(); + var result = _matcher.Match(upstreamHeaders, templateHeaders); // Assert - ThenTheResultIsTrue(); + result.ShouldBeTrue(); } [Fact] @@ -256,38 +228,11 @@ public void Should_not_match_the_header_with_placeholders() { ["anyHeader"] = new("^(?i)(?.+)-(?.+)$", "{header:countrycode}-{header:version}"), }; - GivenIHaveUpstreamHeaders(upstreamHeaders); - GivenIHaveTemplateHeadersInRoute(templateHeaders); // Act - WhenIMatchTheHeaders(); + var result = _matcher.Match(upstreamHeaders, templateHeaders); // Assert - ThenTheResultIsFalse(); - } - - private void GivenIHaveUpstreamHeaders(Dictionary upstreamHeaders) - { - _upstreamHeaders = upstreamHeaders; - } - - private void GivenIHaveTemplateHeadersInRoute(Dictionary templateHeaders) - { - _templateHeaders = templateHeaders; - } - - private void WhenIMatchTheHeaders() - { - _result = _headerMatcher.Match(_upstreamHeaders, _templateHeaders); - } - - private void ThenTheResultIsTrue() - { - _result.ShouldBeTrue(); - } - - private void ThenTheResultIsFalse() - { - _result.ShouldBeFalse(); + result.ShouldBeFalse(); } } diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcherTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcherTests.cs index 5189b42ec..ec5312b3e 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcherTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/RegExUrlMatcherTests.cs @@ -1,288 +1,327 @@ using Ocelot.DownstreamRouteFinder.UrlMatcher; -using Ocelot.Responses; using Ocelot.Values; namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher; public class RegExUrlMatcherTests : UnitTest { - private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; - private string _path; - private string _downstreamPathTemplate; - private Response _result; - private string _queryString; - private bool _containsQueryString; - - public RegExUrlMatcherTests() - { - _urlMatcher = new RegExUrlMatcher(); - } + private readonly RegExUrlMatcher _matcher = new(); + private static readonly string Empty = string.Empty; [Fact] - public void should_not_match() + public void Should_not_match() { - this.Given(x => x.GivenIHaveAUpstreamPath("/api/v1/aaaaaaaaa/cards")) - .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^(?i)/api/v[^/]+/cards$")) - .When(x => x.WhenIMatchThePaths()) - .And(x => x.ThenTheResultIsFalse()) - .BDDfy(); + // Arrange + const string path = "/api/v1/aaaaaaaaa/cards"; + const string downstreamPathTemplate = "^(?i)/api/v[^/]+/cards$"; + + // Act + var result = _matcher.Match(path, Empty, new UpstreamPathTemplate(downstreamPathTemplate, 0, false, downstreamPathTemplate)); + + // Assert + result.Data.Match.ShouldBeFalse(); } [Fact] - public void should_match() + public void Should_match() { - this.Given(x => x.GivenIHaveAUpstreamPath("/api/v1/cards")) - .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^(?i)/api/v[^/]+/cards$")) - .When(x => x.WhenIMatchThePaths()) - .And(x => x.ThenTheResultIsTrue()) - .BDDfy(); + // Arrange + const string path = "/api/v1/cards"; + const string downstreamPathTemplate = "^(?i)/api/v[^/]+/cards$"; + + // Act + var result = _matcher.Match(path, Empty, new UpstreamPathTemplate(downstreamPathTemplate, 0, false, downstreamPathTemplate)); + + // Assert + result.Data.Match.ShouldBeTrue(); } [Fact] - public void should_match_path_with_no_query_string() + public void Should_match_path_with_no_query_string() { + // Arrange const string regExForwardSlashAndOnePlaceHolder = "^(?i)/newThing$"; + const string path = "/newThing"; + const string queryString = "?DeviceType=IphoneApp&Browser=moonpigIphone&BrowserString=-&CountryCode=123&DeviceName=iPhone 5 (GSM+CDMA)&OperatingSystem=iPhone OS 7.1.2&BrowserVersion=3708AdHoc&ipAddress=-"; + const string downstreamPathTemplate = regExForwardSlashAndOnePlaceHolder; + + // Act + var result = _matcher.Match(path, queryString, new UpstreamPathTemplate(downstreamPathTemplate, 0, false, downstreamPathTemplate)); - this.Given(x => x.GivenIHaveAUpstreamPath("/newThing")) - .And(_ => GivenIHaveAQueryString("?DeviceType=IphoneApp&Browser=moonpigIphone&BrowserString=-&CountryCode=123&DeviceName=iPhone 5 (GSM+CDMA)&OperatingSystem=iPhone OS 7.1.2&BrowserVersion=3708AdHoc&ipAddress=-")) - .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern(regExForwardSlashAndOnePlaceHolder)) - .When(x => x.WhenIMatchThePaths()) - .And(x => x.ThenTheResultIsTrue()) - .BDDfy(); + // Assert + result.Data.Match.ShouldBeTrue(); } [Fact] - public void should_match_query_string() + public void Should_match_query_string() { + // Arrange const string regExForwardSlashAndOnePlaceHolder = "^(?i)/api/subscriptions/[^/]+/updates\\?unitId=.+$"; + const string path = "/api/subscriptions/1/updates"; + const string queryString = "?unitId=2"; + const string downstreamPathTemplate = regExForwardSlashAndOnePlaceHolder; + const bool containsQueryString = true; - this.Given(x => x.GivenIHaveAUpstreamPath("/api/subscriptions/1/updates")) - .And(_ => GivenIHaveAQueryString("?unitId=2")) - .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern(regExForwardSlashAndOnePlaceHolder)) - .And(_ => GivenThereIsAQueryInTemplate()) - .When(x => x.WhenIMatchThePaths()) - .And(x => x.ThenTheResultIsTrue()) - .BDDfy(); + // Act + var result = _matcher.Match(path, queryString, new UpstreamPathTemplate(downstreamPathTemplate, 0, containsQueryString, downstreamPathTemplate)); + + // Assert + result.Data.Match.ShouldBeTrue(); } [Fact] - public void should_match_query_string_with_multiple_params() + public void Should_match_query_string_with_multiple_params() { + // Arrange const string regExForwardSlashAndOnePlaceHolder = "^(?i)/api/subscriptions/[^/]+/updates\\?unitId=.+&productId=.+$"; + const string path = "/api/subscriptions/1/updates?unitId=2"; + const string queryString = "?unitId=2&productId=2"; + const string downstreamPathTemplate = regExForwardSlashAndOnePlaceHolder; + const bool containsQueryString = true; + + // Act + var result = _matcher.Match(path, queryString, new UpstreamPathTemplate(downstreamPathTemplate, 0, containsQueryString, downstreamPathTemplate)); - this.Given(x => x.GivenIHaveAUpstreamPath("/api/subscriptions/1/updates?unitId=2")) - .And(_ => GivenIHaveAQueryString("?unitId=2&productId=2")) - .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern(regExForwardSlashAndOnePlaceHolder)) - .And(_ => GivenThereIsAQueryInTemplate()) - .When(x => x.WhenIMatchThePaths()) - .And(x => x.ThenTheResultIsTrue()) - .BDDfy(); + // Assert + result.Data.Match.ShouldBeTrue(); } [Fact] - public void should_not_match_slash_becaue_we_need_to_match_something_after_it() + public void Should_not_match_slash_becaue_we_need_to_match_something_after_it() { + // Arrange const string regExForwardSlashAndOnePlaceHolder = "^/[0-9a-zA-Z].+"; + const string path = "/"; + const string downstreamPathTemplate = regExForwardSlashAndOnePlaceHolder; - this.Given(x => x.GivenIHaveAUpstreamPath("/")) - .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern(regExForwardSlashAndOnePlaceHolder)) - .When(x => x.WhenIMatchThePaths()) - .And(x => x.ThenTheResultIsFalse()) - .BDDfy(); - } + // Act + var result = _matcher.Match(path, Empty, new UpstreamPathTemplate(downstreamPathTemplate, 0, false, downstreamPathTemplate)); - [Fact] - public void should_not_match_forward_slash_only_regex() - { - this.Given(x => x.GivenIHaveAUpstreamPath("/working/")) - .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^/$")) - .When(x => x.WhenIMatchThePaths()) - .And(x => x.ThenTheResultIsFalse()) - .BDDfy(); + // Assert + result.Data.Match.ShouldBeFalse(); } [Fact] - public void should_not_match_issue_134() + public void Should_not_match_forward_slash_only_regex() { - this.Given(x => x.GivenIHaveAUpstreamPath("/api/vacancy/1/")) - .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^(?i)/vacancy/[^/]+/$")) - .When(x => x.WhenIMatchThePaths()) - .And(x => x.ThenTheResultIsFalse()) - .BDDfy(); - } + // Arrange + const string path = "/working/"; + const string downstreamPathTemplate = "^/$"; - [Fact] - public void should_match_forward_slash_only_regex() - { - this.Given(x => x.GivenIHaveAUpstreamPath("/")) - .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^/$")) - .When(x => x.WhenIMatchThePaths()) - .And(x => x.ThenTheResultIsTrue()) - .BDDfy(); + // Act + var result = _matcher.Match(path, Empty, new UpstreamPathTemplate(downstreamPathTemplate, 0, false, downstreamPathTemplate)); + + // Assert + result.Data.Match.ShouldBeFalse(); } [Fact] - public void should_find_match_when_template_smaller_than_valid_path() + public void Should_not_match_issue_134() { - this.Given(x => x.GivenIHaveAUpstreamPath("/api/products/2354325435624623464235")) - .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^/api/products/.+$")) - .When(x => x.WhenIMatchThePaths()) - .And(x => x.ThenTheResultIsTrue()) - .BDDfy(); + // Arrange + const string path = "/api/vacancy/1/"; + const string downstreamPathTemplate = "^(?i)/vacancy/[^/]+/$"; + + // Act + var result = _matcher.Match(path, Empty, new UpstreamPathTemplate(downstreamPathTemplate, 0, false, downstreamPathTemplate)); + + // Assert + result.Data.Match.ShouldBeFalse(); } [Fact] - public void should_not_find_match() + public void Should_match_forward_slash_only_regex() { - this.Given(x => x.GivenIHaveAUpstreamPath("/api/values")) - .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^/$")) - .When(x => x.WhenIMatchThePaths()) - .And(x => x.ThenTheResultIsFalse()) - .BDDfy(); + // Arrange + const string path = "/"; + const string downstreamPathTemplate = "^/$"; + + // Act + var result = _matcher.Match(path, Empty, new UpstreamPathTemplate(downstreamPathTemplate, 0, false, downstreamPathTemplate)); + + // Assert + result.Data.Match.ShouldBeTrue(); } [Fact] - public void can_match_down_stream_url() + public void Should_find_match_when_template_smaller_than_valid_path() { - this.Given(x => x.GivenIHaveAUpstreamPath(string.Empty)) - .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^$")) - .When(x => x.WhenIMatchThePaths()) - .And(x => x.ThenTheResultIsTrue()) - .BDDfy(); + // Arrange + const string path = "/api/products/2354325435624623464235"; + const string downstreamPathTemplate = "^/api/products/.+$"; + + // Act + var result = _matcher.Match(path, Empty, new UpstreamPathTemplate(downstreamPathTemplate, 0, false, downstreamPathTemplate)); + + // Assert + result.Data.Match.ShouldBeTrue(); } [Fact] - public void can_match_down_stream_url_with_no_slash() + public void Should_not_find_match() { - this.Given(x => x.GivenIHaveAUpstreamPath("api")) - .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api$")) - .When(x => x.WhenIMatchThePaths()) - .Then(x => x.ThenTheResultIsTrue()) - .BDDfy(); + // Arrange + const string path = "/api/values"; + const string downstreamPathTemplate = "^/$"; + + // Act + var result = _matcher.Match(path, Empty, new UpstreamPathTemplate(downstreamPathTemplate, 0, false, downstreamPathTemplate)); + + // Assert + result.Data.Match.ShouldBeFalse(); } [Fact] - public void can_match_down_stream_url_with_one_slash() + public void Can_match_down_stream_url() { - this.Given(x => x.GivenIHaveAUpstreamPath("api/")) - .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/$")) - .When(x => x.WhenIMatchThePaths()) - .Then(x => x.ThenTheResultIsTrue()) - .BDDfy(); + // Arrange + const string path = ""; + const string downstreamPathTemplate = "^$"; + + // Act + var result = _matcher.Match(path, Empty, new UpstreamPathTemplate(downstreamPathTemplate, 0, false, downstreamPathTemplate)); + + // Assert + result.Data.Match.ShouldBeTrue(); } [Fact] - public void can_match_down_stream_url_with_downstream_template() + public void Can_match_down_stream_url_with_no_slash() { - this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/")) - .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/$")) - .When(x => x.WhenIMatchThePaths()) - .Then(x => x.ThenTheResultIsTrue()) - .BDDfy(); + // Arrange + const string path = "api"; + const string downstreamPathTemplate = "^api$"; + + // Act + var result = _matcher.Match(path, Empty, new UpstreamPathTemplate(downstreamPathTemplate, 0, false, downstreamPathTemplate)); + + // Assert + result.Data.Match.ShouldBeTrue(); } [Fact] - public void can_match_down_stream_url_with_downstream_template_with_one_place_holder() + public void Can_match_down_stream_url_with_one_slash() { - this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1")) - .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/.+$")) - .When(x => x.WhenIMatchThePaths()) - .Then(x => x.ThenTheResultIsTrue()) - .BDDfy(); + // Arrange + const string path = "api/"; + const string downstreamPathTemplate = "^api/$"; + + // Act + var result = _matcher.Match(path, Empty, new UpstreamPathTemplate(downstreamPathTemplate, 0, false, downstreamPathTemplate)); + + // Assert + result.Data.Match.ShouldBeTrue(); } [Fact] - public void can_match_down_stream_url_with_downstream_template_with_two_place_holders() + public void Can_match_down_stream_url_with_downstream_template() { - this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/2")) - .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/[^/]+/.+$")) - .When(x => x.WhenIMatchThePaths()) - .Then(x => x.ThenTheResultIsTrue()) - .BDDfy(); + // Arrange + const string path = "api/product/products/"; + const string downstreamPathTemplate = "^api/product/products/$"; + + // Act + var result = _matcher.Match(path, Empty, new UpstreamPathTemplate(downstreamPathTemplate, 0, false, downstreamPathTemplate)); + + // Assert + result.Data.Match.ShouldBeTrue(); } [Fact] - public void can_match_down_stream_url_with_downstream_template_with_two_place_holders_seperated_by_something() + public void Can_match_down_stream_url_with_downstream_template_with_one_place_holder() { - this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2")) - .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/[^/]+/categories/.+$")) - .When(x => x.WhenIMatchThePaths()) - .Then(x => x.ThenTheResultIsTrue()) - .BDDfy(); + // Arrange + const string path = "api/product/products/1"; + const string downstreamPathTemplate = "^api/product/products/.+$"; + + // Act + var result = _matcher.Match(path, Empty, new UpstreamPathTemplate(downstreamPathTemplate, 0, false, downstreamPathTemplate)); + + // Assert + result.Data.Match.ShouldBeTrue(); } [Fact] - public void can_match_down_stream_url_with_downstream_template_with_three_place_holders_seperated_by_something() + public void Can_match_down_stream_url_with_downstream_template_with_two_place_holders() { - this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/123")) - .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/[^/]+/categories/[^/]+/variant/.+$")) - .When(x => x.WhenIMatchThePaths()) - .Then(x => x.ThenTheResultIsTrue()) - .BDDfy(); + // Arrange + const string path = "api/product/products/1/2"; + const string downstreamPathTemplate = "^api/product/products/[^/]+/.+$"; + + // Act + var result = _matcher.Match(path, Empty, new UpstreamPathTemplate(downstreamPathTemplate, 0, false, downstreamPathTemplate)); + + // Assert + result.Data.Match.ShouldBeTrue(); } [Fact] - public void can_match_down_stream_url_with_downstream_template_with_three_place_holders() + public void Can_match_down_stream_url_with_downstream_template_with_two_place_holders_seperated_by_something() { - this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/")) - .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/[^/]+/categories/[^/]+/variant/$")) - .When(x => x.WhenIMatchThePaths()) - .Then(x => x.ThenTheResultIsTrue()) - .BDDfy(); + // Arrange + const string path = "api/product/products/1/categories/2"; + const string downstreamPathTemplate = "^api/product/products/[^/]+/categories/.+$"; + + // Act + var result = _matcher.Match(path, Empty, new UpstreamPathTemplate(downstreamPathTemplate, 0, false, downstreamPathTemplate)); + + // Assert + result.Data.Match.ShouldBeTrue(); } [Fact] - public void should_ignore_case_sensitivity() + public void Can_match_down_stream_url_with_downstream_template_with_three_place_holders_seperated_by_something() { - this.Given(x => x.GivenIHaveAUpstreamPath("API/product/products/1/categories/2/variant/")) - .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^(?i)api/product/products/[^/]+/categories/[^/]+/variant/$")) - .When(x => x.WhenIMatchThePaths()) - .Then(x => x.ThenTheResultIsTrue()) - .BDDfy(); + // Arrange + const string path = "api/product/products/1/categories/2/variant/123"; + const string downstreamPathTemplate = "^api/product/products/[^/]+/categories/[^/]+/variant/.+$"; + + // Act + var result = _matcher.Match(path, Empty, new UpstreamPathTemplate(downstreamPathTemplate, 0, false, downstreamPathTemplate)); + + // Assert + result.Data.Match.ShouldBeTrue(); } [Fact] - public void should_respect_case_sensitivity() + public void Can_match_down_stream_url_with_downstream_template_with_three_place_holders() { - this.Given(x => x.GivenIHaveAUpstreamPath("API/product/products/1/categories/2/variant/")) - .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("^api/product/products/[^/]+/categories/[^/]+/variant/$")) - .When(x => x.WhenIMatchThePaths()) - .Then(x => x.ThenTheResultIsFalse()) - .BDDfy(); - } + // Arrange + const string path = "api/product/products/1/categories/2/variant/"; + const string downstreamPathTemplate = "^api/product/products/[^/]+/categories/[^/]+/variant/$"; - private void GivenIHaveAUpstreamPath(string path) - { - _path = path; - } + // Act + var result = _matcher.Match(path, Empty, new UpstreamPathTemplate(downstreamPathTemplate, 0, false, downstreamPathTemplate)); - private void GivenIHaveAQueryString(string queryString) - { - _queryString = queryString; + // Assert + result.Data.Match.ShouldBeTrue(); } - private void GivenIHaveAnUpstreamUrlTemplatePattern(string downstreamUrlTemplate) + [Fact] + public void Should_ignore_case_sensitivity() { - _downstreamPathTemplate = downstreamUrlTemplate; - } + // Arrange + const string path = "API/product/products/1/categories/2/variant/"; + const string downstreamPathTemplate = "^(?i)api/product/products/[^/]+/categories/[^/]+/variant/$"; - private void WhenIMatchThePaths() - { - _result = _urlMatcher.Match(_path, _queryString, new UpstreamPathTemplate(_downstreamPathTemplate, 0, _containsQueryString, _downstreamPathTemplate)); - } + // Act + var result = _matcher.Match(path, Empty, new UpstreamPathTemplate(downstreamPathTemplate, 0, false, downstreamPathTemplate)); - private void ThenTheResultIsTrue() - { - _result.Data.Match.ShouldBeTrue(); + // Assert + result.Data.Match.ShouldBeTrue(); } - private void ThenTheResultIsFalse() + [Fact] + public void Should_respect_case_sensitivity() { - _result.Data.Match.ShouldBeFalse(); - } + // Arrange + const string path = "API/product/products/1/categories/2/variant/"; + const string downstreamPathTemplate = "^api/product/products/[^/]+/categories/[^/]+/variant/$"; - private void GivenThereIsAQueryInTemplate() - { - _containsQueryString = true; + // Act + var result = _matcher.Match(path, Empty, new UpstreamPathTemplate(downstreamPathTemplate, 0, false, downstreamPathTemplate)); + + // Assert + result.Data.Match.ShouldBeFalse(); } } diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/UrlPathPlaceholderNameAndValueFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/UrlPathPlaceholderNameAndValueFinderTests.cs index 3eeafcb38..502cf214e 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/UrlPathPlaceholderNameAndValueFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/UrlMatcher/UrlPathPlaceholderNameAndValueFinderTests.cs @@ -5,15 +5,10 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher; public class UrlPathPlaceholderNameAndValueFinderTests : UnitTest { - private readonly UrlPathPlaceholderNameAndValueFinder _finder; + private readonly UrlPathPlaceholderNameAndValueFinder _finder = new(); private Response> _result; private static readonly string Empty = string.Empty; - public UrlPathPlaceholderNameAndValueFinderTests() - { - _finder = new UrlPathPlaceholderNameAndValueFinder(); - } - [Fact] public void Can_match_down_stream_url() { @@ -402,6 +397,7 @@ public void Find_CaseInsensitive_CannotMatchPlaceholders(string template, string string placeholderName1, string placeholderValue1, string placeholderName2, string placeholderValue2, string placeholderName3, string placeholderValue3, string placeholderName4, string placeholderValue4) { + // Arrange var expectedTemplates = new List { new(placeholderName1, placeholderValue1), @@ -429,6 +425,7 @@ public void Find_HasCatchAll_OnlyTheLastPlaceholderCanContainSlashes(string temp string placeholderName1, string placeholderValue1, string placeholderName2, string placeholderValue2, string placeholderName3 = null, string placeholderValue3 = null, string placeholderName4 = null, string placeholderValue4 = null) { + // Arrange var expectedTemplates = new List { new(placeholderName1, placeholderValue1), diff --git a/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamPathPlaceholderReplacerTests.cs b/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamPathPlaceholderReplacerTests.cs index 7dee35998..e0a3bc2de 100644 --- a/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamPathPlaceholderReplacerTests.cs +++ b/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamPathPlaceholderReplacerTests.cs @@ -2,204 +2,210 @@ using Ocelot.DownstreamRouteFinder; using Ocelot.DownstreamRouteFinder.UrlMatcher; using Ocelot.DownstreamUrlCreator; -using Ocelot.Responses; -using Ocelot.Values; namespace Ocelot.UnitTests.DownstreamUrlCreator; public class DownstreamPathPlaceholderReplacerTests : UnitTest { - private DownstreamRouteHolder _downstreamRoute; - private Response _result; - private readonly IDownstreamPathPlaceholderReplacer _downstreamPathReplacer; - - public DownstreamPathPlaceholderReplacerTests() - { - _downstreamPathReplacer = new DownstreamPathPlaceholderReplacer(); - } + private readonly DownstreamPathPlaceholderReplacer _replacer = new(); [Fact] - public void can_replace_no_template_variables() + public void Can_replace_no_template_variables() { - this.Given(x => x.GivenThereIsAUrlMatch( - new DownstreamRouteHolder( - new List(), - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithUpstreamHttpMethod(new List { "Get" }) - .Build()) - .WithUpstreamHttpMethod(new List { "Get" }) - .Build()))) - .When(x => x.WhenIReplaceTheTemplateVariables()) - .Then(x => x.ThenTheDownstreamUrlPathIsReturned(string.Empty)) - .BDDfy(); + // Arrange + var holder = new DownstreamRouteHolder( + new List(), + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithUpstreamHttpMethod(new List { "Get" }) + .Build()) + .WithUpstreamHttpMethod(new List { "Get" }) + .Build()); + + // Act + var result = _replacer.Replace(holder.Route.DownstreamRoute[0].DownstreamPathTemplate.Value, holder.TemplatePlaceholderNameAndValues); + + // Assert + result.Data.Value.ShouldBe(string.Empty); } [Fact] - public void can_replace_no_template_variables_with_slash() + public void Can_replace_no_template_variables_with_slash() { - this.Given(x => x.GivenThereIsAUrlMatch( - new DownstreamRouteHolder( - new List(), - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("/") - .WithUpstreamHttpMethod(new List { "Get" }) - .Build()) - .WithUpstreamHttpMethod(new List { "Get" }) - .Build()))) - .When(x => x.WhenIReplaceTheTemplateVariables()) - .Then(x => x.ThenTheDownstreamUrlPathIsReturned("/")) - .BDDfy(); + // Arrange + var holder = new DownstreamRouteHolder( + new List(), + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("/") + .WithUpstreamHttpMethod(new List { "Get" }) + .Build()) + .WithUpstreamHttpMethod(new List { "Get" }) + .Build()); + + // Act + var result = _replacer.Replace(holder.Route.DownstreamRoute[0].DownstreamPathTemplate.Value, holder.TemplatePlaceholderNameAndValues); + + // Assert + result.Data.Value.ShouldBe("/"); } [Fact] - public void can_replace_url_no_slash() + public void Can_replace_url_no_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRouteHolder(new List(), - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("api") - .WithUpstreamHttpMethod(new List { "Get" }) - .Build()) - .WithUpstreamHttpMethod(new List { "Get" }) - .Build()))) - .When(x => x.WhenIReplaceTheTemplateVariables()) - .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api")) - .BDDfy(); + // Arrange + var holder = new DownstreamRouteHolder(new List(), + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("api") + .WithUpstreamHttpMethod(new List { "Get" }) + .Build()) + .WithUpstreamHttpMethod(new List { "Get" }) + .Build()); + + // Act + var result = _replacer.Replace(holder.Route.DownstreamRoute[0].DownstreamPathTemplate.Value, holder.TemplatePlaceholderNameAndValues); + + // Assert + result.Data.Value.ShouldBe("api"); } [Fact] - public void can_replace_url_one_slash() + public void Can_replace_url_one_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRouteHolder(new List(), - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("api/") - .WithUpstreamHttpMethod(new List { "Get" }) - .Build()) - .WithUpstreamHttpMethod(new List { "Get" }) - .Build()))) - .When(x => x.WhenIReplaceTheTemplateVariables()) - .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/")) - .BDDfy(); + // Arrange + var holder = new DownstreamRouteHolder(new List(), + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("api/") + .WithUpstreamHttpMethod(new List { "Get" }) + .Build()) + .WithUpstreamHttpMethod(new List { "Get" }) + .Build()); + + // Act + var result = _replacer.Replace(holder.Route.DownstreamRoute[0].DownstreamPathTemplate.Value, holder.TemplatePlaceholderNameAndValues); + + // Assert + result.Data.Value.ShouldBe("api/"); } [Fact] - public void can_replace_url_multiple_slash() + public void Can_replace_url_multiple_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRouteHolder(new List(), - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("api/product/products/") - .WithUpstreamHttpMethod(new List { "Get" }) - .Build()) - .WithUpstreamHttpMethod(new List { "Get" }) - .Build()))) - .When(x => x.WhenIReplaceTheTemplateVariables()) - .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/product/products/")) - .BDDfy(); + // Arrange + var holder = new DownstreamRouteHolder(new List(), + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("api/product/products/") + .WithUpstreamHttpMethod(new List { "Get" }) + .Build()) + .WithUpstreamHttpMethod(new List { "Get" }) + .Build()); + + // Act + var result = _replacer.Replace(holder.Route.DownstreamRoute[0].DownstreamPathTemplate.Value, holder.TemplatePlaceholderNameAndValues); + + // Assert + result.Data.Value.ShouldBe("api/product/products/"); } [Fact] - public void can_replace_url_one_template_variable() + public void Can_replace_url_one_template_variable() { + // Arrange var templateVariables = new List { new("{productId}", "1"), }; - - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRouteHolder(templateVariables, - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("productservice/products/{productId}/") - .WithUpstreamHttpMethod(new List { "Get" }) - .Build()) - .WithUpstreamHttpMethod(new List { "Get" }) - .Build()))) - .When(x => x.WhenIReplaceTheTemplateVariables()) - .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/")) - .BDDfy(); + var holder = new DownstreamRouteHolder(templateVariables, + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("productservice/products/{productId}/") + .WithUpstreamHttpMethod(new List { "Get" }) + .Build()) + .WithUpstreamHttpMethod(new List { "Get" }) + .Build()); + + // Act + var result = _replacer.Replace(holder.Route.DownstreamRoute[0].DownstreamPathTemplate.Value, holder.TemplatePlaceholderNameAndValues); + + // Assert + result.Data.Value.ShouldBe("productservice/products/1/"); } [Fact] - public void can_replace_url_one_template_variable_with_path_after() + public void Can_replace_url_one_template_variable_with_path_after() { + // Arrange var templateVariables = new List { new("{productId}", "1"), }; - - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRouteHolder(templateVariables, - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("productservice/products/{productId}/variants") - .WithUpstreamHttpMethod(new List { "Get" }) - .Build()) - .WithUpstreamHttpMethod(new List { "Get" }) - .Build()))) - .When(x => x.WhenIReplaceTheTemplateVariables()) - .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants")) - .BDDfy(); + var holder = new DownstreamRouteHolder(templateVariables, + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("productservice/products/{productId}/variants") + .WithUpstreamHttpMethod(new List { "Get" }) + .Build()) + .WithUpstreamHttpMethod(new List { "Get" }) + .Build()); + + // Act + var result = _replacer.Replace(holder.Route.DownstreamRoute[0].DownstreamPathTemplate.Value, holder.TemplatePlaceholderNameAndValues); + + // Assert + result.Data.Value.ShouldBe("productservice/products/1/variants"); } [Fact] - public void can_replace_url_two_template_variable() + public void Can_replace_url_two_template_variable() { + // Arrange var templateVariables = new List { new("{productId}", "1"), new("{variantId}", "12"), }; - - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRouteHolder(templateVariables, - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("productservice/products/{productId}/variants/{variantId}") - .WithUpstreamHttpMethod(new List { "Get" }) - .Build()) - .WithUpstreamHttpMethod(new List { "Get" }) - .Build()))) - .When(x => x.WhenIReplaceTheTemplateVariables()) - .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants/12")) - .BDDfy(); + var holder = new DownstreamRouteHolder(templateVariables, + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("productservice/products/{productId}/variants/{variantId}") + .WithUpstreamHttpMethod(new List { "Get" }) + .Build()) + .WithUpstreamHttpMethod(new List { "Get" }) + .Build()); + + // Act + var result = _replacer.Replace(holder.Route.DownstreamRoute[0].DownstreamPathTemplate.Value, holder.TemplatePlaceholderNameAndValues); + + // Assert + result.Data.Value.ShouldBe("productservice/products/1/variants/12"); } [Fact] - public void can_replace_url_three_template_variable() + public void Can_replace_url_three_template_variable() { + // Arrange var templateVariables = new List { new("{productId}", "1"), new("{variantId}", "12"), new("{categoryId}", "34"), }; - - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRouteHolder(templateVariables, - new RouteBuilder() - .WithDownstreamRoute(new DownstreamRouteBuilder() - .WithDownstreamPathTemplate("productservice/category/{categoryId}/products/{productId}/variants/{variantId}") - .WithUpstreamHttpMethod(new List { "Get" }) - .Build()) - .WithUpstreamHttpMethod(new List { "Get" }) - .Build()))) - .When(x => x.WhenIReplaceTheTemplateVariables()) - .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/category/34/products/1/variants/12")) - .BDDfy(); - } - - private void GivenThereIsAUrlMatch(DownstreamRouteHolder downstreamRoute) - { - _downstreamRoute = downstreamRoute; - } - - private void WhenIReplaceTheTemplateVariables() - { - _result = _downstreamPathReplacer.Replace(_downstreamRoute.Route.DownstreamRoute[0].DownstreamPathTemplate.Value, _downstreamRoute.TemplatePlaceholderNameAndValues); - } - - private void ThenTheDownstreamUrlPathIsReturned(string expected) - { - _result.Data.Value.ShouldBe(expected); + var holder = new DownstreamRouteHolder(templateVariables, + new RouteBuilder() + .WithDownstreamRoute(new DownstreamRouteBuilder() + .WithDownstreamPathTemplate("productservice/category/{categoryId}/products/{productId}/variants/{variantId}") + .WithUpstreamHttpMethod(new List { "Get" }) + .Build()) + .WithUpstreamHttpMethod(new List { "Get" }) + .Build()); + + // Act + var result = _replacer.Replace(holder.Route.DownstreamRoute[0].DownstreamPathTemplate.Value, holder.TemplatePlaceholderNameAndValues); + + // Assert + result.Data.Value.ShouldBe("productservice/category/34/products/1/variants/12"); } } diff --git a/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs b/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs index 12e345f13..642c14c26 100644 --- a/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs @@ -26,12 +26,10 @@ public sealed class DownstreamUrlCreatorMiddlewareTests : UnitTest private DownstreamUrlCreatorMiddleware _middleware; private readonly RequestDelegate _next; private readonly HttpRequestMessage _request; - private readonly HttpContext _httpContext; - private readonly Mock _repo; + private readonly DefaultHttpContext _httpContext; public DownstreamUrlCreatorMiddlewareTests() { - _repo = new Mock(); _httpContext = new DefaultHttpContext(); _loggerFactory = new Mock(); _logger = new Mock(); diff --git a/test/Ocelot.UnitTests/Errors/ErrorTests.cs b/test/Ocelot.UnitTests/Errors/ErrorTests.cs index db5c6f53b..bcdc8f160 100644 --- a/test/Ocelot.UnitTests/Errors/ErrorTests.cs +++ b/test/Ocelot.UnitTests/Errors/ErrorTests.cs @@ -5,10 +5,15 @@ namespace Ocelot.UnitTests.Errors; public class ErrorTests { [Fact] - public void should_return_message() + public void Should_return_message() { + // Arrange var error = new CannotAddDataError("message"); + + // Act var result = error.ToString(); + + // Assert result.ShouldBe("message"); } } diff --git a/test/Ocelot.UnitTests/Errors/ExceptionHandlerMiddlewareTests.cs b/test/Ocelot.UnitTests/Errors/ExceptionHandlerMiddlewareTests.cs index b1ea1ab5d..6977f8269 100644 --- a/test/Ocelot.UnitTests/Errors/ExceptionHandlerMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Errors/ExceptionHandlerMiddlewareTests.cs @@ -15,7 +15,7 @@ public class ExceptionHandlerMiddlewareTests : UnitTest private readonly Mock _logger; private readonly ExceptionHandlerMiddleware _middleware; private readonly RequestDelegate _next; - private readonly HttpContext _httpContext; + private readonly DefaultHttpContext _httpContext; public ExceptionHandlerMiddlewareTests() { @@ -27,7 +27,6 @@ public ExceptionHandlerMiddlewareTests() _next = async context => { await Task.CompletedTask; - if (_shouldThrowAnException) { throw new Exception("BOOM"); @@ -35,126 +34,89 @@ public ExceptionHandlerMiddlewareTests() _httpContext.Response.StatusCode = (int)HttpStatusCode.OK; }; - _middleware = new ExceptionHandlerMiddleware(_next, _loggerFactory.Object, _repo.Object); } [Fact] - public void NoDownstreamException() + public async Task NoDownstreamException() { + // Arrange + _shouldThrowAnException = false; var config = new InternalConfiguration(null, null, null, null, null, null, null, null, null, null); + _httpContext.Items.Add(nameof(IInternalConfiguration), config); - this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream()) - .And(_ => GivenTheConfigurationIs(config)) - .When(_ => WhenICallTheMiddleware()) - .Then(_ => ThenTheResponseIsOk()) - .And(_ => TheAspDotnetRequestIdIsSet()) - .BDDfy(); + // Act + await _middleware.Invoke(_httpContext); + + // Assert + _httpContext.Response.StatusCode.ShouldBe((int)HttpStatusCode.OK); + _repo.Verify(x => x.Add(It.IsAny(), It.IsAny()), Times.Once); } [Fact] - public void DownstreamException() + public async Task DownstreamException() { + // Arrange + _shouldThrowAnException = true; var config = new InternalConfiguration(null, null, null, null, null, null, null, null, null, null); + _httpContext.Items.Add(nameof(IInternalConfiguration), config); - this.Given(_ => GivenAnExceptionWillBeThrownDownstream()) - .And(_ => GivenTheConfigurationIs(config)) - .When(_ => WhenICallTheMiddleware()) - .Then(_ => ThenTheResponseIsError()) - .BDDfy(); + // Act + await _middleware.Invoke(_httpContext); + + // Assert + _httpContext.Response.StatusCode.ShouldBe((int)HttpStatusCode.InternalServerError); } [Fact] - public void ShouldSetRequestId() + public async Task ShouldSetRequestId() { + // Arrange + _shouldThrowAnException = false; var config = new InternalConfiguration(null, null, null, "requestidkey", null, null, null, null, null, null); + _httpContext.Items.Add(nameof(IInternalConfiguration), config); + _httpContext.Request.Headers.Append("requestidkey", "1234"); - this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream()) - .And(_ => GivenTheConfigurationIs(config)) - .When(_ => WhenICallTheMiddlewareWithTheRequestIdKey("requestidkey", "1234")) - .Then(_ => ThenTheResponseIsOk()) - .And(_ => TheRequestIdIsSet("RequestId", "1234")) - .BDDfy(); - } - - [Fact] - public void ShouldSetAspDotNetRequestId() - { - var config = new InternalConfiguration(null, null, null, null, null, null, null, null, null, null); + // Act + await _middleware.Invoke(_httpContext); - this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream()) - .And(_ => GivenTheConfigurationIs(config)) - .When(_ => WhenICallTheMiddlewareWithTheRequestIdKey("requestidkey", "1234")) - .Then(_ => ThenTheResponseIsOk()) - .And(_ => TheAspDotnetRequestIdIsSet()) - .BDDfy(); + // Assert + _httpContext.Response.StatusCode.ShouldBe((int)HttpStatusCode.OK); + _repo.Verify(x => x.Add("RequestId", "1234"), Times.Once); } [Fact] - public void should_throw_exception_if_config_provider_throws() + public async Task ShouldSetAspDotNetRequestId() { - this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream()) - .And(_ => GivenTheConfigThrows()) - .When(_ => WhenICallTheMiddlewareWithTheRequestIdKey("requestidkey", "1234")) - .Then(_ => ThenAnExceptionIsThrown()) - .BDDfy(); - } - - private async Task WhenICallTheMiddlewareWithTheRequestIdKey(string key, string value) - { - _httpContext.Request.Headers.Append(key, value); - await _middleware.Invoke(_httpContext); - } + // Arrange + _shouldThrowAnException = false; + var config = new InternalConfiguration(null, null, null, null, null, null, null, null, null, null); + _httpContext.Items.Add(nameof(IInternalConfiguration), config); + _httpContext.Request.Headers.Append("requestidkey", "1234"); - private async Task WhenICallTheMiddleware() - { + // Act await _middleware.Invoke(_httpContext); - } - private void GivenTheConfigThrows() - { - // this will break when we handle not having the configuratio in the items dictionary - _httpContext.Items = new Dictionary(); - } - - private void ThenAnExceptionIsThrown() - { - _httpContext.Response.StatusCode.ShouldBe(500); - } - - private void TheRequestIdIsSet(string key, string value) - { - _repo.Verify(x => x.Add(key, value), Times.Once); - } - - private void GivenTheConfigurationIs(IInternalConfiguration config) - { - _httpContext.Items.Add("IInternalConfiguration", config); + // Assert + _httpContext.Response.StatusCode.ShouldBe((int)HttpStatusCode.OK); + _repo.Verify(x => x.Add(It.IsAny(), It.IsAny()), Times.Once); } - private void GivenAnExceptionWillNotBeThrownDownstream() + [Fact] + public async Task Should_throw_exception_if_config_provider_throws() { + // Arrange _shouldThrowAnException = false; - } - private void GivenAnExceptionWillBeThrownDownstream() - { - _shouldThrowAnException = true; - } - - private void ThenTheResponseIsOk() - { - _httpContext.Response.StatusCode.ShouldBe(200); - } + // this will break when we handle not having the configuratio in the items dictionary + _httpContext.Items = new Dictionary(); + _httpContext.Request.Headers.Append("requestidkey", "1234"); - private void ThenTheResponseIsError() - { - _httpContext.Response.StatusCode.ShouldBe(500); - } + // Act + await _middleware.Invoke(_httpContext); - private void TheAspDotnetRequestIdIsSet() - { - _repo.Verify(x => x.Add(It.IsAny(), It.IsAny()), Times.Once); + // Assert + _httpContext.Response.StatusCode.ShouldBe((int)HttpStatusCode.InternalServerError); } private class FakeError : Error diff --git a/test/Ocelot.UnitTests/Eureka/EurekaMiddlewareConfigurationProviderTests.cs b/test/Ocelot.UnitTests/Eureka/EurekaMiddlewareConfigurationProviderTests.cs index ed40f8881..ad4bf0855 100644 --- a/test/Ocelot.UnitTests/Eureka/EurekaMiddlewareConfigurationProviderTests.cs +++ b/test/Ocelot.UnitTests/Eureka/EurekaMiddlewareConfigurationProviderTests.cs @@ -14,19 +14,25 @@ public class EurekaMiddlewareConfigurationProviderTests [Fact] public void ShouldNotBuild() { + // Arrange var configRepo = new Mock(); configRepo.Setup(x => x.Get()) .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(true); + + // Act var provider = EurekaMiddlewareConfigurationProvider.Get(new ApplicationBuilder(sp)); + + // Assert provider.Status.ShouldBe(TaskStatus.RanToCompletion); } [Fact] public void ShouldBuild() { + // Arrange var serviceProviderConfig = new ServiceProviderConfigurationBuilder().WithType("eureka").Build(); var client = new Mock(); var configRepo = new Mock(); @@ -36,7 +42,11 @@ public void ShouldBuild() services.AddSingleton(configRepo.Object); services.AddSingleton(client.Object); var sp = services.BuildServiceProvider(true); + + // Act var provider = EurekaMiddlewareConfigurationProvider.Get(new ApplicationBuilder(sp)); + + // Assert provider.Status.ShouldBe(TaskStatus.RanToCompletion); } } diff --git a/test/Ocelot.UnitTests/Eureka/EurekaProviderFactoryTests.cs b/test/Ocelot.UnitTests/Eureka/EurekaProviderFactoryTests.cs index 90c9f1b2a..93d95998f 100644 --- a/test/Ocelot.UnitTests/Eureka/EurekaProviderFactoryTests.cs +++ b/test/Ocelot.UnitTests/Eureka/EurekaProviderFactoryTests.cs @@ -8,17 +8,20 @@ namespace Ocelot.UnitTests.Eureka; public class EurekaProviderFactoryTests { [Fact] - public void should_not_get() + public void Should_not_get() { + // Arrange var config = new ServiceProviderConfigurationBuilder().Build(); var sp = new ServiceCollection().BuildServiceProvider(true); - Should.Throw(() => - EurekaProviderFactory.Get(sp, config, null)); + + // Act, Assert + Should.Throw(() => EurekaProviderFactory.Get(sp, config, null)); } [Fact] - public void should_get() + public void Should_get() { + // Arrange var config = new ServiceProviderConfigurationBuilder().WithType("eureka").Build(); var client = new Mock(); var services = new ServiceCollection(); @@ -27,7 +30,11 @@ public void should_get() var route = new DownstreamRouteBuilder() .WithServiceName(string.Empty) .Build(); + + // Act var provider = EurekaProviderFactory.Get(sp, config, route); + + // Assert provider.ShouldBeOfType(); } } diff --git a/test/Ocelot.UnitTests/Eureka/EurekaServiceDiscoveryProviderTests.cs b/test/Ocelot.UnitTests/Eureka/EurekaServiceDiscoveryProviderTests.cs index ebe97045c..8d642d6ed 100644 --- a/test/Ocelot.UnitTests/Eureka/EurekaServiceDiscoveryProviderTests.cs +++ b/test/Ocelot.UnitTests/Eureka/EurekaServiceDiscoveryProviderTests.cs @@ -10,7 +10,6 @@ public class EurekaServiceDiscoveryProviderTests : UnitTest private readonly _Eureka_ _provider; private readonly Mock _client; private readonly string _serviceId; - private List _instances; private List _result; public EurekaServiceDiscoveryProviderTests() @@ -21,72 +20,56 @@ public EurekaServiceDiscoveryProviderTests() } [Fact] - public void should_return_empty_services() + public async Task Should_return_empty_services() { - this.When(_ => WhenIGet()) - .Then(_ => ThenTheCountIs(0)) - .BDDfy(); + // Arrange, Act + _result = await _provider.GetAsync(); + + // Assert + _result.Count.ShouldBe(0); } [Fact] - public void should_return_service_from_client() + public async Task Should_return_service_from_client() { + // Arrange var instances = new List { new EurekaService(_serviceId, "somehost", 801, false, new Uri("http://somehost:801"), new Dictionary()), }; + _client.Setup(x => x.GetInstances(It.IsAny())).Returns(instances); - this.Given(_ => GivenThe(instances)) - .When(_ => WhenIGet()) - .Then(_ => ThenTheCountIs(1)) - .And(_ => ThenTheClientIsCalledCorrectly()) - .And(_ => ThenTheServiceIsMapped()) - .BDDfy(); + // Act + _result = await _provider.GetAsync(); + _result.Count.ShouldBe(1); + + // Assert + _client.Verify(x => x.GetInstances(_serviceId), Times.Once); + + // Assert: Then The Service Is Mapped + _result[0].HostAndPort.DownstreamHost.ShouldBe("somehost"); + _result[0].HostAndPort.DownstreamPort.ShouldBe(801); + _result[0].Name.ShouldBe(_serviceId); } [Fact] - public void should_return_services_from_client() + public async Task Should_return_services_from_client() { + // Arrange var instances = new List { new EurekaService(_serviceId, "somehost", 801, false, new Uri("http://somehost:801"), new Dictionary()), new EurekaService(_serviceId, "somehost", 801, false, new Uri("http://somehost:801"), new Dictionary()), }; + _client.Setup(x => x.GetInstances(It.IsAny())).Returns(instances); - this.Given(_ => GivenThe(instances)) - .When(_ => WhenIGet()) - .Then(_ => ThenTheCountIs(2)) - .And(_ => ThenTheClientIsCalledCorrectly()) - .BDDfy(); - } - - private void ThenTheServiceIsMapped() - { - _result[0].HostAndPort.DownstreamHost.ShouldBe("somehost"); - _result[0].HostAndPort.DownstreamPort.ShouldBe(801); - _result[0].Name.ShouldBe(_serviceId); - } - - private void ThenTheCountIs(int expected) - { - _result.Count.ShouldBe(expected); - } + // Act + _result = await _provider.GetAsync(); - private void ThenTheClientIsCalledCorrectly() - { + // Assert + _result.Count.ShouldBe(2); _client.Verify(x => x.GetInstances(_serviceId), Times.Once); } - - private async Task WhenIGet() - { - _result = await _provider.GetAsync(); - } - - private void GivenThe(List instances) - { - _instances = instances; - _client.Setup(x => x.GetInstances(It.IsAny())).Returns(instances); - } } public class EurekaService : IServiceInstance diff --git a/test/Ocelot.UnitTests/Eureka/OcelotBuilderExtensionsTests.cs b/test/Ocelot.UnitTests/Eureka/OcelotBuilderExtensionsTests.cs index 586e64df5..b00facbb5 100644 --- a/test/Ocelot.UnitTests/Eureka/OcelotBuilderExtensionsTests.cs +++ b/test/Ocelot.UnitTests/Eureka/OcelotBuilderExtensionsTests.cs @@ -35,7 +35,8 @@ private static IWebHostEnvironment GetHostingEnvironment() [Fact] [Trait("PR", "734")] - [Trait("Feat", "324, 844")] + [Trait("Feat", "324")] + [Trait("Feat", "844")] public void AddEureka_NoExceptions_ShouldSetUpEureka() { // Arrange @@ -51,7 +52,8 @@ public void AddEureka_NoExceptions_ShouldSetUpEureka() [Fact] [Trait("PR", "734")] - [Trait("Feat", "324, 844")] + [Trait("Feat", "324")] + [Trait("Feat", "844")] public void AddEureka_DefaultServices_HappyPath() { // Arrange, Act diff --git a/test/Ocelot.UnitTests/Headers/AddHeadersToRequestClaimToThingTests.cs b/test/Ocelot.UnitTests/Headers/AddHeadersToRequestClaimToThingTests.cs index 11e35a192..1ff882389 100644 --- a/test/Ocelot.UnitTests/Headers/AddHeadersToRequestClaimToThingTests.cs +++ b/test/Ocelot.UnitTests/Headers/AddHeadersToRequestClaimToThingTests.cs @@ -15,10 +15,6 @@ public class AddHeadersToRequestClaimToThingTests : UnitTest private readonly AddHeadersToRequest _addHeadersToRequest; private readonly Mock _parser; private readonly DownstreamRequest _downstreamRequest; - private List _claims; - private List _configuration; - private Response _result; - private Response _claimValue; private readonly Mock _placeholders; private readonly Mock _factory; @@ -32,112 +28,77 @@ public AddHeadersToRequestClaimToThingTests() } [Fact] - public void should_add_headers_to_downstreamRequest() + public void Should_add_headers_to_downstreamRequest() { + // Arrange var claims = new List { new("test", "data"), }; + var configuration = new List + { + new("header-key", string.Empty, string.Empty, 0), + }; + var claimValue = GivenTheClaimParserReturns(new OkResponse("value")); - this.Given( - x => x.GivenConfigurationHeaderExtractorProperties(new List - { - new("header-key", string.Empty, string.Empty, 0), - })) - .Given(x => x.GivenClaims(claims)) - .And(x => x.GivenTheClaimParserReturns(new OkResponse("value"))) - .When(x => x.WhenIAddHeadersToTheRequest()) - .Then(x => x.ThenTheResultIsSuccess()) - .And(x => x.ThenTheHeaderIsAdded()) - .BDDfy(); - } + // Act + var result = _addHeadersToRequest.SetHeadersOnDownstreamRequest(configuration, claims, _downstreamRequest); - [Fact] - public void should_replace_existing_headers_on_request() - { - this.Given( - x => x.GivenConfigurationHeaderExtractorProperties(new List - { - new("header-key", string.Empty, string.Empty, 0), - })) - .Given(x => x.GivenClaims(new List - { - new("test", "data"), - })) - .And(x => x.GivenTheClaimParserReturns(new OkResponse("value"))) - .And(x => x.GivenThatTheRequestContainsHeader("header-key", "initial")) - .When(x => x.WhenIAddHeadersToTheRequest()) - .Then(x => x.ThenTheResultIsSuccess()) - .And(x => x.ThenTheHeaderIsAdded()) - .BDDfy(); + // Assert + result.IsError.ShouldBeFalse(); + ThenTheHeaderIsAdded(claimValue); } [Fact] - public void should_return_error() - { - this.Given( - x => x.GivenConfigurationHeaderExtractorProperties(new List - { - new(string.Empty, string.Empty, string.Empty, 0), - })) - .Given(x => x.GivenClaims(new List())) - .And(x => x.GivenTheClaimParserReturns(new ErrorResponse(new List - { - new AnyError(), - }))) - .When(x => x.WhenIAddHeadersToTheRequest()) - .Then(x => x.ThenTheResultIsError()) - .BDDfy(); - } - - private void GivenClaims(List claims) + public void Should_replace_existing_headers_on_request() { - _claims = claims; - } + // Arrange + var claims = new List + { + new("test", "data"), + }; + var configuration = new List + { + new("header-key", string.Empty, string.Empty, 0), + }; + var claimValue = GivenTheClaimParserReturns(new OkResponse("value")); + _downstreamRequest.Headers.Add("header-key", "initial"); - private void GivenConfigurationHeaderExtractorProperties(List configuration) - { - _configuration = configuration; - } + // Act + var result = _addHeadersToRequest.SetHeadersOnDownstreamRequest(configuration, claims, _downstreamRequest); - private void GivenThatTheRequestContainsHeader(string key, string value) - { - _downstreamRequest.Headers.Add(key, value); + // Assert + result.IsError.ShouldBeFalse(); + ThenTheHeaderIsAdded(claimValue); } - private void GivenTheClaimParserReturns(Response claimValue) + [Fact] + public void Should_return_error() { - _claimValue = claimValue; - _parser - .Setup( - x => - x.GetValue(It.IsAny>(), - It.IsAny(), - It.IsAny(), - It.IsAny())) - .Returns(_claimValue); - } + // Arrange + var claims = new List(); + var configuration = new List + { + new(string.Empty, string.Empty, string.Empty, 0), + }; + _ = GivenTheClaimParserReturns(new ErrorResponse(new List { new AnyError() })); - private void WhenIAddHeadersToTheRequest() - { - _result = _addHeadersToRequest.SetHeadersOnDownstreamRequest(_configuration, _claims, _downstreamRequest); - } + // Act + var result = _addHeadersToRequest.SetHeadersOnDownstreamRequest(configuration, claims, _downstreamRequest); - private void ThenTheResultIsSuccess() - { - _result.IsError.ShouldBe(false); + // Assert + result.IsError.ShouldBeTrue(); } - private void ThenTheResultIsError() + private Response GivenTheClaimParserReturns(Response claimValue) { - _result.IsError.ShouldBe(true); + _parser.Setup(x => x.GetValue(It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(claimValue); + return claimValue; } - private void ThenTheHeaderIsAdded() - { - var header = _downstreamRequest.Headers.First(x => x.Key == "header-key"); - header.Value.First().ShouldBe(_claimValue.Data); - } + private void ThenTheHeaderIsAdded(Response claimValue) + => _downstreamRequest.Headers.First(x => x.Key == "header-key").Value.First().ShouldBe(claimValue.Data); private class AnyError : Error { diff --git a/test/Ocelot.UnitTests/Headers/AddHeadersToRequestPlainTests.cs b/test/Ocelot.UnitTests/Headers/AddHeadersToRequestPlainTests.cs index 79b57c26a..920ed8191 100644 --- a/test/Ocelot.UnitTests/Headers/AddHeadersToRequestPlainTests.cs +++ b/test/Ocelot.UnitTests/Headers/AddHeadersToRequestPlainTests.cs @@ -13,7 +13,7 @@ namespace Ocelot.UnitTests.Headers; public class AddHeadersToRequestPlainTests : UnitTest { private readonly AddHeadersToRequest _addHeadersToRequest; - private HttpContext _context; + private readonly DefaultHttpContext _context; private AddHeader _addedHeader; private readonly Mock _placeholders; private readonly Mock _factory; @@ -26,63 +26,56 @@ public AddHeadersToRequestPlainTests() _logger = new Mock(); _factory.Setup(x => x.CreateLogger()).Returns(_logger.Object); _addHeadersToRequest = new AddHeadersToRequest(Mock.Of(), _placeholders.Object, _factory.Object); + _context = new DefaultHttpContext(); } [Fact] - public void should_log_error_if_cannot_find_placeholder() + public void Should_log_error_if_cannot_find_placeholder() { + // Arrange _placeholders.Setup(x => x.Get(It.IsAny())).Returns(new ErrorResponse(new AnyError())); - this.Given(_ => GivenHttpRequestWithoutHeaders()) - .When(_ => WhenAddingHeader("X-Forwarded-For", "{RemoteIdAddress}")) - .Then(_ => ThenAnErrorIsLogged("X-Forwarded-For", "{RemoteIdAddress}")) - .BDDfy(); + // Act + WhenAddingHeader("X-Forwarded-For", "{RemoteIdAddress}"); + + // Assert + _logger.Verify(x => x.LogWarning(It.Is>(y => y.Invoke() == $"Unable to add header to response X-Forwarded-For: {{RemoteIdAddress}}")), Times.Once); } [Fact] - public void should_add_placeholder_to_downstream_request() + public void Should_add_placeholder_to_downstream_request() { + // Arrange _placeholders.Setup(x => x.Get(It.IsAny())).Returns(new OkResponse("replaced")); - this.Given(_ => GivenHttpRequestWithoutHeaders()) - .When(_ => WhenAddingHeader("X-Forwarded-For", "{RemoteIdAddress}")) - .Then(_ => ThenTheHeaderGetsTakenOverToTheRequestHeaders("replaced")) - .BDDfy(); - } + // Act + WhenAddingHeader("X-Forwarded-For", "{RemoteIdAddress}"); - [Fact] - public void should_add_plain_text_header_to_downstream_request() - { - this.Given(_ => GivenHttpRequestWithoutHeaders()) - .When(_ => WhenAddingHeader("X-Custom-Header", "PlainValue")) - .Then(_ => ThenTheHeaderGetsTakenOverToTheRequestHeaders()) - .BDDfy(); + // Assert + ThenTheHeaderGetsTakenOverToTheRequestHeaders("replaced"); } [Fact] - public void should_overwrite_existing_header_with_added_header() + public void Should_add_plain_text_header_to_downstream_request() { - this.Given(_ => GivenHttpRequestWithHeader("X-Custom-Header", "This should get overwritten")) - .When(_ => WhenAddingHeader("X-Custom-Header", "PlainValue")) - .Then(_ => ThenTheHeaderGetsTakenOverToTheRequestHeaders()) - .BDDfy(); - } + // Arrange, Act + WhenAddingHeader("X-Custom-Header", "PlainValue"); - private void ThenAnErrorIsLogged(string key, string value) - { - _logger.Verify(x => x.LogWarning(It.Is>(y => y.Invoke() == $"Unable to add header to response {key}: {value}")), Times.Once); + // Assert + ThenTheHeaderGetsTakenOverToTheRequestHeaders(); } - private void GivenHttpRequestWithoutHeaders() + [Fact] + public void Should_overwrite_existing_header_with_added_header() { - _context = new DefaultHttpContext(); - } + // Arrange + _context.Request.Headers.Append("X-Custom-Header", "This should get overwritten"); + + // Act + WhenAddingHeader("X-Custom-Header", "PlainValue"); - private void GivenHttpRequestWithHeader(string headerKey, string headerValue) - { - var context = new DefaultHttpContext(); - context.Request.Headers.Append(headerKey, headerValue); - _context = context; + // Assert + ThenTheHeaderGetsTakenOverToTheRequestHeaders(); } private void WhenAddingHeader(string headerKey, string headerValue) @@ -96,7 +89,7 @@ private void ThenTheHeaderGetsTakenOverToTheRequestHeaders() var requestHeaders = _context.Request.Headers; requestHeaders.ContainsKey(_addedHeader.Key).ShouldBeTrue($"Header {_addedHeader.Key} was expected but not there."); var value = requestHeaders[_addedHeader.Key]; - value.ShouldNotBe(default(StringValues), $"Value of header {_addedHeader.Key} was expected to not be null."); + value.ShouldNotBe(default, $"Value of header {_addedHeader.Key} was expected to not be null."); value.ToString().ShouldBe(_addedHeader.Value); } diff --git a/test/Ocelot.UnitTests/Headers/AddHeadersToResponseTests.cs b/test/Ocelot.UnitTests/Headers/AddHeadersToResponseTests.cs index f351f2b7c..ccfcc3ccb 100644 --- a/test/Ocelot.UnitTests/Headers/AddHeadersToResponseTests.cs +++ b/test/Ocelot.UnitTests/Headers/AddHeadersToResponseTests.cs @@ -10,9 +10,9 @@ namespace Ocelot.UnitTests.Headers; public class AddHeadersToResponseTests : UnitTest { - private readonly IAddHeadersToResponse _adder; + private readonly AddHeadersToResponse _adder; private readonly Mock _placeholders; - private DownstreamResponse _response; + private readonly DownstreamResponse _response; private List _addHeaders; private readonly Mock _factory; private readonly Mock _logger; @@ -24,116 +24,89 @@ public AddHeadersToResponseTests() _factory.Setup(x => x.CreateLogger()).Returns(_logger.Object); _placeholders = new Mock(); _adder = new AddHeadersToResponse(_placeholders.Object, _factory.Object); + _response = new DownstreamResponse(new HttpResponseMessage()); } [Fact] - public void should_add_header() + public void Should_add_header() { - var addHeaders = new List + // Arrange + _addHeaders = new List { new("Laura", "Tom"), }; - this.Given(_ => GivenAResponseMessage()) - .And(_ => GivenTheAddHeaders(addHeaders)) - .When(_ => WhenIAdd()) - .And(_ => ThenTheHeaderIsReturned("Laura", "Tom")) - .BDDfy(); + // Act + _adder.Add(_addHeaders, _response); + + // Assert + ThenTheHeaderIsReturned("Laura", "Tom"); } [Fact] - public void should_add_trace_id_placeholder() + public void Should_add_trace_id_placeholder() { - var addHeaders = new List + // Arrange + _addHeaders = new List { new("Trace-Id", "{TraceId}"), }; - var traceId = "123"; + GivenTheTraceIdIs(traceId); - this.Given(_ => GivenAResponseMessage()) - .And(_ => GivenTheTraceIdIs(traceId)) - .And(_ => GivenTheAddHeaders(addHeaders)) - .When(_ => WhenIAdd()) - .Then(_ => ThenTheHeaderIsReturned("Trace-Id", traceId)) - .BDDfy(); + // Act + _adder.Add(_addHeaders, _response); + + // Assert + ThenTheHeaderIsReturned("Trace-Id", traceId); } [Fact] - public void should_add_trace_id_placeholder_and_normal() + public void Should_add_trace_id_placeholder_and_normal() { - var addHeaders = new List + // Arrange + _addHeaders = new List { new("Trace-Id", "{TraceId}"), new("Tom", "Laura"), }; - var traceId = "123"; + GivenTheTraceIdIs(traceId); + + // Act + _adder.Add(_addHeaders, _response); - this.Given(_ => GivenAResponseMessage()) - .And(_ => GivenTheTraceIdIs(traceId)) - .And(_ => GivenTheAddHeaders(addHeaders)) - .When(_ => WhenIAdd()) - .Then(_ => ThenTheHeaderIsReturned("Trace-Id", traceId)) - .Then(_ => ThenTheHeaderIsReturned("Tom", "Laura")) - .BDDfy(); + // Assert + ThenTheHeaderIsReturned("Trace-Id", traceId); + ThenTheHeaderIsReturned("Tom", "Laura"); } [Fact] - public void should_do_nothing_and_log_error() + public void Should_do_nothing_and_log_error() { - var addHeaders = new List + // Arrange + _addHeaders = new List { new("Trace-Id", "{TraceId}"), }; + _placeholders.Setup(x => x.Get("{TraceId}")).Returns(new ErrorResponse(new AnyError())); - this.Given(_ => GivenAResponseMessage()) - .And(_ => GivenTheTraceIdErrors()) - .And(_ => GivenTheAddHeaders(addHeaders)) - .When(_ => WhenIAdd()) - .Then(_ => ThenTheHeaderIsNotAdded("Trace-Id")) - .And(_ => ThenTheErrorIsLogged()) - .BDDfy(); - } + // Act + _adder.Add(_addHeaders, _response); - private void ThenTheErrorIsLogged() - { + // Assert + _response.Headers.Any(x => x.Key == "Trace-Id").ShouldBeFalse(); _logger.Verify(x => x.LogWarning(It.Is>(y => y.Invoke() == "Unable to add header to response Trace-Id: {TraceId}")), Times.Once); } - private void ThenTheHeaderIsNotAdded(string key) - { - _response.Headers.Any(x => x.Key == key).ShouldBeFalse(); - } - private void GivenTheTraceIdIs(string traceId) { _placeholders.Setup(x => x.Get("{TraceId}")).Returns(new OkResponse(traceId)); } - private void GivenTheTraceIdErrors() - { - _placeholders.Setup(x => x.Get("{TraceId}")).Returns(new ErrorResponse(new AnyError())); - } - private void ThenTheHeaderIsReturned(string key, string value) { var values = _response.Headers.First(x => x.Key == key); values.Values.First().ShouldBe(value); } - - private void WhenIAdd() - { - _adder.Add(_addHeaders, _response); - } - - private void GivenAResponseMessage() - { - _response = new DownstreamResponse(new HttpResponseMessage()); - } - - private void GivenTheAddHeaders(List addHeaders) - { - _addHeaders = addHeaders; - } } diff --git a/test/Ocelot.UnitTests/Headers/ClaimsToHeadersMiddlewareTests.cs b/test/Ocelot.UnitTests/Headers/ClaimsToHeadersMiddlewareTests.cs index ed215b9d7..47b7c6f31 100644 --- a/test/Ocelot.UnitTests/Headers/ClaimsToHeadersMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Headers/ClaimsToHeadersMiddlewareTests.cs @@ -1,25 +1,25 @@ using Microsoft.AspNetCore.Http; using Ocelot.Configuration; using Ocelot.Configuration.Builder; -using Ocelot.DownstreamRouteFinder.UrlMatcher; +using Ocelot.DownstreamRouteFinder; using Ocelot.Headers; using Ocelot.Headers.Middleware; using Ocelot.Logging; using Ocelot.Middleware; using Ocelot.Request.Middleware; using Ocelot.Responses; +using System.Security.Claims; namespace Ocelot.UnitTests.Headers; public class ClaimsToHeadersMiddlewareTests : UnitTest { private readonly Mock _addHeaders; - private Response _downstreamRoute; private readonly Mock _loggerFactory; private readonly Mock _logger; private readonly ClaimsToHeadersMiddleware _middleware; private readonly RequestDelegate _next; - private readonly HttpContext _httpContext; + private readonly DefaultHttpContext _httpContext; public ClaimsToHeadersMiddlewareTests() { @@ -34,9 +34,10 @@ public ClaimsToHeadersMiddlewareTests() } [Fact] - public void should_call_add_headers_to_request_correctly() + public async Task Should_call_add_headers_to_request_correctly() { - var downstreamRoute = new Ocelot.DownstreamRouteFinder.DownstreamRouteHolder(new List(), + // Arrange + var downstreamRoute = new DownstreamRouteHolder(new(), new RouteBuilder() .WithDownstreamRoute(new DownstreamRouteBuilder() .WithDownstreamPathTemplate("any old string") @@ -49,43 +50,20 @@ public void should_call_add_headers_to_request_correctly() .WithUpstreamHttpMethod(new List { "Get" }) .Build()); - this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) - .And(x => x.GivenTheAddHeadersToDownstreamRequestReturnsOk()) - .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.ThenTheAddHeadersToRequestIsCalledCorrectly()) - .BDDfy(); - } - - private async Task WhenICallTheMiddleware() - { - await _middleware.Invoke(_httpContext); - } - - private void GivenTheDownStreamRouteIs(Ocelot.DownstreamRouteFinder.DownstreamRouteHolder downstreamRoute) - { - _downstreamRoute = new OkResponse(downstreamRoute); - + // Arrange: Given The Down Stream Route Is _httpContext.Items.UpsertTemplatePlaceholderNameAndValues(downstreamRoute.TemplatePlaceholderNameAndValues); - _httpContext.Items.UpsertDownstreamRoute(downstreamRoute.Route.DownstreamRoute[0]); - } - private void GivenTheAddHeadersToDownstreamRequestReturnsOk() - { - _addHeaders - .Setup(x => x.SetHeadersOnDownstreamRequest( - It.IsAny>(), - It.IsAny>(), - It.IsAny())) + // Arrange: Given The AddHeaders To Downstream Request Returns Ok + _addHeaders.Setup(x => x.SetHeadersOnDownstreamRequest(It.IsAny>(), It.IsAny>(), It.IsAny())) .Returns(new OkResponse()); - } - private void ThenTheAddHeadersToRequestIsCalledCorrectly() - { - _addHeaders - .Verify(x => x.SetHeadersOnDownstreamRequest( - It.IsAny>(), - It.IsAny>(), - _httpContext.Items.DownstreamRequest()), Times.Once); + // Act + await _middleware.Invoke(_httpContext); + + // Assert: Then The AddHeaders ToRequest Is Called Correctly + _addHeaders.Verify( + x => x.SetHeadersOnDownstreamRequest(It.IsAny>(), It.IsAny>(), _httpContext.Items.DownstreamRequest()), + Times.Once); } } diff --git a/test/Ocelot.UnitTests/Headers/HttpContextRequestHeaderReplacerTests.cs b/test/Ocelot.UnitTests/Headers/HttpContextRequestHeaderReplacerTests.cs index d208ff903..8f5110a04 100644 --- a/test/Ocelot.UnitTests/Headers/HttpContextRequestHeaderReplacerTests.cs +++ b/test/Ocelot.UnitTests/Headers/HttpContextRequestHeaderReplacerTests.cs @@ -7,78 +7,50 @@ namespace Ocelot.UnitTests.Headers; public class HttpContextRequestHeaderReplacerTests : UnitTest { - private HttpContext _context; - private List _fAndRs; + private readonly DefaultHttpContext _context; private readonly HttpContextRequestHeaderReplacer _replacer; - private Response _result; public HttpContextRequestHeaderReplacerTests() { - _replacer = new HttpContextRequestHeaderReplacer(); + _replacer = new(); + _context = new(); } [Fact] - public void should_replace_headers() + public void Should_replace_headers() { - var context = new DefaultHttpContext(); - context.Request.Headers.Append("test", "test"); - + // Arrange + _context.Request.Headers.Append("test", "test"); var fAndRs = new List { new("test", "test", "chiken", 0) }; - this.Given(x => GivenTheFollowingHttpRequest(context)) - .And(x => GivenTheFollowingHeaderReplacements(fAndRs)) - .When(x => WhenICallTheReplacer()) - .Then(x => ThenTheHeadersAreReplaced()) - .BDDfy(); - } - - [Fact] - public void should_not_replace_headers() - { - var context = new DefaultHttpContext(); - context.Request.Headers.Append("test", "test"); + // Act + var result = _replacer.Replace(_context, fAndRs); - var fAndRs = new List(); - - this.Given(x => GivenTheFollowingHttpRequest(context)) - .And(x => GivenTheFollowingHeaderReplacements(fAndRs)) - .When(x => WhenICallTheReplacer()) - .Then(x => ThenTheHeadersAreNotReplaced()) - .BDDfy(); - } - - private void ThenTheHeadersAreNotReplaced() - { - _result.ShouldBeOfType(); - foreach (var f in _fAndRs) + // Assert + result.ShouldBeOfType(); + foreach (var f in fAndRs) { _context.Request.Headers.TryGetValue(f.Key, out var values); - values[f.Index].ShouldBe("test"); + values[f.Index].ShouldBe(f.Replace); } } - private void GivenTheFollowingHttpRequest(HttpContext context) + [Fact] + public void Should_not_replace_headers() { - _context = context; - } + // Arrange + _context.Request.Headers.Append("test", "test"); + var fAndRs = new List(); - private void GivenTheFollowingHeaderReplacements(List fAndRs) - { - _fAndRs = fAndRs; - } + // Act + var result = _replacer.Replace(_context, fAndRs); - private void WhenICallTheReplacer() - { - _result = _replacer.Replace(_context, _fAndRs); - } - - private void ThenTheHeadersAreReplaced() - { - _result.ShouldBeOfType(); - foreach (var f in _fAndRs) + // Assert + result.ShouldBeOfType(); + foreach (var f in fAndRs) { _context.Request.Headers.TryGetValue(f.Key, out var values); - values[f.Index].ShouldBe(f.Replace); + values[f.Index].ShouldBe("test"); } } } diff --git a/test/Ocelot.UnitTests/Headers/HttpHeadersTransformationMiddlewareTests.cs b/test/Ocelot.UnitTests/Headers/HttpHeadersTransformationMiddlewareTests.cs index 95e395e9c..21d11ced1 100644 --- a/test/Ocelot.UnitTests/Headers/HttpHeadersTransformationMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Headers/HttpHeadersTransformationMiddlewareTests.cs @@ -20,7 +20,7 @@ public class HttpHeadersTransformationMiddlewareTests : UnitTest private readonly RequestDelegate _next; private readonly Mock _addHeadersToResponse; private readonly Mock _addHeadersToRequest; - private readonly HttpContext _httpContext; + private readonly DefaultHttpContext _httpContext; public HttpHeadersTransformationMiddlewareTests() { @@ -39,18 +39,22 @@ public HttpHeadersTransformationMiddlewareTests() } [Fact] - public void should_call_pre_and_post_header_transforms() + public async Task Should_call_pre_and_post_header_transforms() { - this.Given(x => GivenTheFollowingRequest()) - .And(x => GivenTheDownstreamRequestIs()) - .And(x => GivenTheRouteHasPreFindAndReplaceSetUp()) - .And(x => GivenTheHttpResponseMessageIs()) - .When(x => WhenICallTheMiddleware()) - .Then(x => ThenTheIHttpContextRequestHeaderReplacerIsCalledCorrectly()) - .Then(x => ThenAddHeadersToRequestIsCalledCorrectly()) - .And(x => ThenTheIHttpResponseHeaderReplacerIsCalledCorrectly()) - .And(x => ThenAddHeadersToResponseIsCalledCorrectly()) - .BDDfy(); + // Arrange + GivenTheFollowingRequest(); + GivenTheDownstreamRequestIs(); + GivenTheRouteHasPreFindAndReplaceSetUp(); + GivenTheHttpResponseMessageIs(); + + // Act + await _middleware.Invoke(_httpContext); + + // Assert + ThenTheIHttpContextRequestHeaderReplacerIsCalledCorrectly(); + ThenAddHeadersToRequestIsCalledCorrectly(); + ThenTheIHttpResponseHeaderReplacerIsCalledCorrectly(); + ThenAddHeadersToResponseIsCalledCorrectly(); } private void ThenAddHeadersToResponseIsCalledCorrectly() @@ -65,11 +69,6 @@ private void ThenAddHeadersToRequestIsCalledCorrectly() .Verify(x => x.SetHeadersOnDownstreamRequest(_httpContext.Items.DownstreamRoute().AddHeadersToUpstream, _httpContext), Times.Once); } - private async Task WhenICallTheMiddleware() - { - await _middleware.Invoke(_httpContext); - } - private void GivenTheDownstreamRequestIs() { _httpContext.Items.UpsertDownstreamRequest(new DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "http://test.com"))); diff --git a/test/Ocelot.UnitTests/Headers/HttpResponseHeaderReplacerTests.cs b/test/Ocelot.UnitTests/Headers/HttpResponseHeaderReplacerTests.cs index 84b0c036a..8dc686b5c 100644 --- a/test/Ocelot.UnitTests/Headers/HttpResponseHeaderReplacerTests.cs +++ b/test/Ocelot.UnitTests/Headers/HttpResponseHeaderReplacerTests.cs @@ -31,206 +31,177 @@ public HttpResponseHeaderReplacerTests() } [Fact] - public void should_replace_headers() + public void Should_replace_headers() { - var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted, + // Arrange + _response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted, new List>> { new("test", new List {"test"}), }, string.Empty); + _headerFindAndReplaces = new List { new("test", "test", "chiken", 0) }; - var fAndRs = new List { new("test", "test", "chiken", 0) }; + // Act + WhenICallTheReplacer(); - this.Given(x => GivenTheHttpResponse(response)) - .And(x => GivenTheFollowingHeaderReplacements(fAndRs)) - .When(x => WhenICallTheReplacer()) - .Then(x => ThenTheHeadersAreReplaced()) - .BDDfy(); + // Assert + ThenTheHeadersAreReplaced(); } [Fact] - public void should_not_replace_headers() + public void Should_not_replace_headers() { - var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted, + // Arrange + _response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted, new List>> { new("test", new List {"test"}), }, string.Empty); + _headerFindAndReplaces = new List(); - var fAndRs = new List(); + // Act + WhenICallTheReplacer(); - this.Given(x => GivenTheHttpResponse(response)) - .And(x => GivenTheFollowingHeaderReplacements(fAndRs)) - .When(x => WhenICallTheReplacer()) - .Then(x => ThenTheHeadersAreNotReplaced()) - .BDDfy(); + // Assert + ThenTheHeadersAreNotReplaced(); } [Fact] - public void should_replace_downstream_base_url_with_ocelot_base_url() + public void Should_replace_downstream_base_url_with_ocelot_base_url() { + // Arrange const string downstreamUrl = "http://downstream.com/"; - - var request = - new HttpRequestMessage(HttpMethod.Get, "http://test.com") { RequestUri = new System.Uri(downstreamUrl) }; - - var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted, + _request = new DownstreamRequest(new(HttpMethod.Get, "http://test.com") { RequestUri = new Uri(downstreamUrl) }); + _response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted, new List>> { new("Location", new List {downstreamUrl}), }, string.Empty); - - var fAndRs = new List + _headerFindAndReplaces = new List { new("Location", "{DownstreamBaseUrl}", "http://ocelot.com/", 0), }; - this.Given(x => GivenTheHttpResponse(response)) - .And(x => GivenTheRequestIs(request)) - .And(x => GivenTheFollowingHeaderReplacements(fAndRs)) - .When(x => WhenICallTheReplacer()) - .Then(x => ThenTheHeaderShouldBe("Location", "http://ocelot.com/")) - .BDDfy(); + // Act + WhenICallTheReplacer(); + + // Assert + ThenTheHeaderShouldBe("Location", "http://ocelot.com/"); } [Fact] - public void should_replace_downstream_base_url_with_ocelot_base_url_with_port() + public void Should_replace_downstream_base_url_with_ocelot_base_url_with_port() { + // Arrange const string downstreamUrl = "http://downstream.com/"; - - var request = - new HttpRequestMessage(HttpMethod.Get, "http://test.com") { RequestUri = new System.Uri(downstreamUrl) }; - - var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted, + _request = new DownstreamRequest(new(HttpMethod.Get, "http://test.com") { RequestUri = new Uri(downstreamUrl) }); + _response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted, new List>> { new("Location", new List {downstreamUrl}), }, string.Empty); - - var fAndRs = new List + _headerFindAndReplaces = new List { new("Location", "{DownstreamBaseUrl}", "http://ocelot.com:123/", 0), }; - this.Given(x => GivenTheHttpResponse(response)) - .And(x => GivenTheRequestIs(request)) - .And(x => GivenTheFollowingHeaderReplacements(fAndRs)) - .When(x => WhenICallTheReplacer()) - .Then(x => ThenTheHeaderShouldBe("Location", "http://ocelot.com:123/")) - .BDDfy(); + // Act + WhenICallTheReplacer(); + + // Assert + ThenTheHeaderShouldBe("Location", "http://ocelot.com:123/"); } [Fact] - public void should_replace_downstream_base_url_with_ocelot_base_url_and_path() + public void Should_replace_downstream_base_url_with_ocelot_base_url_and_path() { + // Arrange const string downstreamUrl = "http://downstream.com/test/product"; - - var request = - new HttpRequestMessage(HttpMethod.Get, "http://test.com") { RequestUri = new System.Uri(downstreamUrl) }; - - var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted, + _request = new DownstreamRequest(new(HttpMethod.Get, "http://test.com") { RequestUri = new Uri(downstreamUrl) }); + _response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted, new List>> { new("Location", new List {downstreamUrl}), }, string.Empty); - - var fAndRs = new List + _headerFindAndReplaces = new List { new("Location", "{DownstreamBaseUrl}", "http://ocelot.com/", 0), }; - this.Given(x => GivenTheHttpResponse(response)) - .And(x => GivenTheRequestIs(request)) - .And(x => GivenTheFollowingHeaderReplacements(fAndRs)) - .When(x => WhenICallTheReplacer()) - .Then(x => ThenTheHeaderShouldBe("Location", "http://ocelot.com/test/product")) - .BDDfy(); + // Act + WhenICallTheReplacer(); + + // Assert + ThenTheHeaderShouldBe("Location", "http://ocelot.com/test/product"); } [Fact] - public void should_replace_downstream_base_url_with_ocelot_base_url_with_path_and_port() + public void Should_replace_downstream_base_url_with_ocelot_base_url_with_path_and_port() { + // Arrange const string downstreamUrl = "http://downstream.com/test/product"; - - var request = - new HttpRequestMessage(HttpMethod.Get, "http://test.com") { RequestUri = new System.Uri(downstreamUrl) }; - - var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted, + _request = new DownstreamRequest(new(HttpMethod.Get, "http://test.com") { RequestUri = new Uri(downstreamUrl) }); + _response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted, new List>> { new("Location", new List {downstreamUrl}), }, string.Empty); - - var fAndRs = new List + _headerFindAndReplaces = new List { new("Location", "{DownstreamBaseUrl}", "http://ocelot.com:123/", 0), }; - this.Given(x => GivenTheHttpResponse(response)) - .And(x => GivenTheRequestIs(request)) - .And(x => GivenTheFollowingHeaderReplacements(fAndRs)) - .When(x => WhenICallTheReplacer()) - .Then(x => ThenTheHeaderShouldBe("Location", "http://ocelot.com:123/test/product")) - .BDDfy(); + // Act + WhenICallTheReplacer(); + + // Assert + ThenTheHeaderShouldBe("Location", "http://ocelot.com:123/test/product"); } [Fact] - public void should_replace_downstream_base_url_and_port_with_ocelot_base_url() + public void Should_replace_downstream_base_url_and_port_with_ocelot_base_url() { + // Arrange const string downstreamUrl = "http://downstream.com:123/test/product"; - - var request = - new HttpRequestMessage(HttpMethod.Get, "http://test.com") { RequestUri = new System.Uri(downstreamUrl) }; - - var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted, + _request = new DownstreamRequest(new(HttpMethod.Get, "http://test.com") { RequestUri = new Uri(downstreamUrl) }); + _response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted, new List>> { new("Location", new List {downstreamUrl}), }, string.Empty); - - var fAndRs = new List + _headerFindAndReplaces = new List { new("Location", "{DownstreamBaseUrl}", "http://ocelot.com/", 0), }; - this.Given(x => GivenTheHttpResponse(response)) - .And(x => GivenTheRequestIs(request)) - .And(x => GivenTheFollowingHeaderReplacements(fAndRs)) - .When(x => WhenICallTheReplacer()) - .Then(x => ThenTheHeaderShouldBe("Location", "http://ocelot.com/test/product")) - .BDDfy(); + // Act + WhenICallTheReplacer(); + + // Assert + ThenTheHeaderShouldBe("Location", "http://ocelot.com/test/product"); } [Fact] - public void should_replace_downstream_base_url_and_port_with_ocelot_base_url_and_port() + public void Should_replace_downstream_base_url_and_port_with_ocelot_base_url_and_port() { + // Arrange const string downstreamUrl = "http://downstream.com:123/test/product"; - - var request = - new HttpRequestMessage(HttpMethod.Get, "http://test.com") { RequestUri = new System.Uri(downstreamUrl) }; - - var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted, + _request = new DownstreamRequest(new(HttpMethod.Get, "http://test.com") { RequestUri = new Uri(downstreamUrl) }); + _response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted, new List>> { new("Location", new List {downstreamUrl}), }, string.Empty); - - var fAndRs = new List + _headerFindAndReplaces = new List { new("Location", "{DownstreamBaseUrl}", "http://ocelot.com:321/", 0), }; - this.Given(x => GivenTheHttpResponse(response)) - .And(x => GivenTheRequestIs(request)) - .And(x => GivenTheFollowingHeaderReplacements(fAndRs)) - .When(x => WhenICallTheReplacer()) - .Then(x => ThenTheHeaderShouldBe("Location", "http://ocelot.com:321/test/product")) - .BDDfy(); - } + // Act + WhenICallTheReplacer(); - private void GivenTheRequestIs(HttpRequestMessage request) - { - _request = new DownstreamRequest(request); + // Assert + ThenTheHeaderShouldBe("Location", "http://ocelot.com:321/test/product"); } private void ThenTheHeadersAreNotReplaced() @@ -243,16 +214,6 @@ private void ThenTheHeadersAreNotReplaced() } } - private void GivenTheFollowingHeaderReplacements(List fAndRs) - { - _headerFindAndReplaces = fAndRs; - } - - private void GivenTheHttpResponse(DownstreamResponse response) - { - _response = response; - } - private void WhenICallTheReplacer() { var httpContext = new DefaultHttpContext(); diff --git a/test/Ocelot.UnitTests/Headers/RemoveHeadersTests.cs b/test/Ocelot.UnitTests/Headers/RemoveHeadersTests.cs index 44bd5f2f6..a7719d78e 100644 --- a/test/Ocelot.UnitTests/Headers/RemoveHeadersTests.cs +++ b/test/Ocelot.UnitTests/Headers/RemoveHeadersTests.cs @@ -1,47 +1,27 @@ using Ocelot.Middleware; -using Ocelot.Responses; +using Ocelot.Headers; namespace Ocelot.UnitTests.Headers; public class RemoveHeadersTests : UnitTest { - private List
_headers; - private readonly Ocelot.Headers.RemoveOutputHeaders _removeOutputHeaders; - private Response _result; - - public RemoveHeadersTests() - { - _removeOutputHeaders = new Ocelot.Headers.RemoveOutputHeaders(); - } + private readonly RemoveOutputHeaders _removeOutputHeaders = new(); [Fact] - public void should_remove_header() + public void Should_remove_header() { + // Arrange var headers = new List
{ new("Transfer-Encoding", new List {"chunked"}), }; - this.Given(x => x.GivenAHttpContext(headers)) - .When(x => x.WhenIRemoveTheHeaders()) - .Then(x => x.TheHeaderIsNoLongerInTheContext()) - .BDDfy(); - } + // Act + var result = _removeOutputHeaders.Remove(headers); - private void GivenAHttpContext(List
headers) - { - _headers = headers; - } - - private void WhenIRemoveTheHeaders() - { - _result = _removeOutputHeaders.Remove(_headers); - } - - private void TheHeaderIsNoLongerInTheContext() - { - _result.IsError.ShouldBeFalse(); - _headers.ShouldNotContain(x => x.Key == "Transfer-Encoding"); - _headers.ShouldNotContain(x => x.Key == "transfer-encoding"); + // Assert + result.IsError.ShouldBeFalse(); + headers.ShouldNotContain(x => x.Key == "Transfer-Encoding"); + headers.ShouldNotContain(x => x.Key == "transfer-encoding"); } } diff --git a/test/Ocelot.UnitTests/Infrastructure/ClaimParserTests.cs b/test/Ocelot.UnitTests/Infrastructure/ClaimParserTests.cs index d738cb46b..c2df4bfbb 100644 --- a/test/Ocelot.UnitTests/Infrastructure/ClaimParserTests.cs +++ b/test/Ocelot.UnitTests/Infrastructure/ClaimParserTests.cs @@ -7,112 +7,101 @@ namespace Ocelot.UnitTests.Infrastructure; public class ClaimParserTests : UnitTest { - private readonly IClaimsParser _claimsParser; + private readonly ClaimsParser _claimsParser; private readonly List _claims; - private string _key; - private Response _result; - private string _delimiter; - private int _index; public ClaimParserTests() { - _claims = new List(); - _claimsParser = new ClaimsParser(); + _claimsParser = new(); + _claims = new(); } [Fact] - public void can_parse_claims_dictionary_access_string_returning_value_to_function() + public void Can_parse_claims_dictionary_access_string_returning_value_to_function() { - this.Given(x => x.GivenAClaimOf(new Claim("CustomerId", "1234"))) - .And(x => x.GivenTheKeyIs("CustomerId")) - .When(x => x.WhenICallTheParser()) - .Then(x => x.ThenTheResultIs(new OkResponse("1234"))) - .BDDfy(); - } + // Arrange + const string key = "CustomerId"; + _claims.Add(new Claim(key, "1234")); - [Fact] - public void should_return_error_response_when_cannot_find_requested_claim() - { - this.Given(x => x.GivenAClaimOf(new Claim("BallsId", "1234"))) - .And(x => x.GivenTheKeyIs("CustomerId")) - .When(x => x.WhenICallTheParser()) - .Then(x => x.ThenTheResultIs(new ErrorResponse(new List - { - new CannotFindClaimError($"Cannot find claim for key: {_key}"), - }))) - .BDDfy(); + // Act + var result = _claimsParser.GetValue(_claims, key, default, default); + + // Assert + ThenTheResultIs(result, new OkResponse("1234")); } [Fact] - public void can_parse_claims_dictionary_access_string_using_delimiter_and_retuning_at_correct_index() + public void Should_return_error_response_when_cannot_find_requested_claim() { - this.Given(x => x.GivenAClaimOf(new Claim("Subject", "registered|4321"))) - .And(x => x.GivenTheDelimiterIs("|")) - .And(x => x.GivenTheIndexIs(1)) - .And(x => x.GivenTheKeyIs("Subject")) - .When(x => x.WhenICallTheParser()) - .Then(x => x.ThenTheResultIs(new OkResponse("4321"))) - .BDDfy(); + // Arrange + const string key = "CustomerId"; + _claims.Add(new Claim("BallsId", "1234")); + + // Act + var result = _claimsParser.GetValue(_claims, key, default, default); + + // Assert + ThenTheResultIs(result, new ErrorResponse(new List + { + new CannotFindClaimError($"Cannot find claim for key: {key}"), + })); } [Fact] - public void should_return_error_response_if_index_too_large() + public void Can_parse_claims_dictionary_access_string_using_delimiter_and_retuning_at_correct_index() { - this.Given(x => x.GivenAClaimOf(new Claim("Subject", "registered|4321"))) - .And(x => x.GivenTheDelimiterIs("|")) - .And(x => x.GivenTheIndexIs(24)) - .And(x => x.GivenTheKeyIs("Subject")) - .When(x => x.WhenICallTheParser()) - .Then(x => x.ThenTheResultIs(new ErrorResponse(new List - { - new CannotFindClaimError($"Cannot find claim for key: {_key}, delimiter: {_delimiter}, index: {_index}"), - }))) - .BDDfy(); + // Arrange + const string key = "Subject"; + _claims.Add(new Claim("Subject", "registered|4321")); + + // Act + var result = _claimsParser.GetValue(_claims, key, "|", 1); + + // Assert + ThenTheResultIs(result, new OkResponse("4321")); } [Fact] - public void should_return_error_response_if_index_too_small() + public void Should_return_error_response_if_index_too_large() { - this.Given(x => x.GivenAClaimOf(new Claim("Subject", "registered|4321"))) - .And(x => x.GivenTheDelimiterIs("|")) - .And(x => x.GivenTheIndexIs(-1)) - .And(x => x.GivenTheKeyIs("Subject")) - .When(x => x.WhenICallTheParser()) - .Then(x => x.ThenTheResultIs(new ErrorResponse(new List - { - new CannotFindClaimError($"Cannot find claim for key: {_key}, delimiter: {_delimiter}, index: {_index}"), - }))) - .BDDfy(); - } + // Arrange + const string key = "Subject"; + const string delimiter = "|"; + const int index = 24; + _claims.Add(new Claim("Subject", "registered|4321")); - private void GivenTheIndexIs(int index) - { - _index = index; - } + // Act + var result = _claimsParser.GetValue(_claims, key, delimiter, index); - private void GivenTheDelimiterIs(string delimiter) - { - _delimiter = delimiter; + // Assert + ThenTheResultIs(result, new ErrorResponse(new List + { + new CannotFindClaimError($"Cannot find claim for key: {key}, delimiter: {delimiter}, index: {index}"), + })); } - private void GivenAClaimOf(Claim claim) + [Fact] + public void Should_return_error_response_if_index_too_small() { - _claims.Add(claim); - } + // Arrange + const string key = "Subject"; + const string delimiter = "|"; + const int index = -1; + _claims.Add(new Claim("Subject", "registered|4321")); - private void GivenTheKeyIs(string key) - { - _key = key; - } + // Act + var result = _claimsParser.GetValue(_claims, key, delimiter, index); - private void WhenICallTheParser() - { - _result = _claimsParser.GetValue(_claims, _key, _delimiter, _index); + // Assert + ThenTheResultIs(result, new ErrorResponse(new List + { + new CannotFindClaimError($"Cannot find claim for key: {key}, delimiter: {delimiter}, index: {index}"), + })); } - private void ThenTheResultIs(Response expected) + private static void ThenTheResultIs(Response actual, Response expected) { - _result.Data.ShouldBe(expected.Data); - _result.IsError.ShouldBe(expected.IsError); + actual.Data.ShouldBe(expected.Data); + actual.IsError.ShouldBe(expected.IsError); } } diff --git a/test/Ocelot.UnitTests/Infrastructure/ConfigAwarePlaceholdersTests.cs b/test/Ocelot.UnitTests/Infrastructure/ConfigAwarePlaceholdersTests.cs index 55ee9a06e..8ac9c9963 100644 --- a/test/Ocelot.UnitTests/Infrastructure/ConfigAwarePlaceholdersTests.cs +++ b/test/Ocelot.UnitTests/Infrastructure/ConfigAwarePlaceholdersTests.cs @@ -6,7 +6,7 @@ namespace Ocelot.UnitTests.Infrastructure; public class ConfigAwarePlaceholdersTests { - private readonly IPlaceholders _placeholders; + private readonly ConfigAwarePlaceholders _placeholders; private readonly Mock _basePlaceholders; public ConfigAwarePlaceholdersTests() @@ -20,53 +20,75 @@ public ConfigAwarePlaceholdersTests() } [Fact] - public void should_return_value_from_underlying_placeholders() + public void Should_return_value_from_underlying_placeholders() { + // Arrange var baseUrl = "http://www.bbc.co.uk"; const string key = "{BaseUrl}"; - _basePlaceholders.Setup(x => x.Get(key)).Returns(new OkResponse(baseUrl)); + + // Act var result = _placeholders.Get(key); + + // Assert result.Data.ShouldBe(baseUrl); } [Fact] - public void should_return_value_from_config_with_same_name_as_placeholder_if_underlying_placeholder_not_found() + public void Should_return_value_from_config_with_same_name_as_placeholder_if_underlying_placeholder_not_found() { + // Arrange const string expected = "http://foo-bar.co.uk"; const string key = "{BaseUrl}"; - _basePlaceholders.Setup(x => x.Get(key)).Returns(new ErrorResponse(new FakeError())); + + // Act var result = _placeholders.Get(key); + + // Assert result.Data.ShouldBe(expected); } [Theory] [InlineData("{TestConfig}")] [InlineData("{TestConfigNested:Child}")] - public void should_return_value_from_config(string key) + public void Should_return_value_from_config(string key) { + // Arrange const string expected = "foo"; - _basePlaceholders.Setup(x => x.Get(key)).Returns(new ErrorResponse(new FakeError())); + + // Act var result = _placeholders.Get(key); + + // Assert result.Data.ShouldBe(expected); } [Fact] - public void should_call_underyling_when_added() + public void Should_call_underyling_when_added() { + // Arrange const string key = "{Test}"; Func> func = () => new OkResponse("test)"); + + // Act _placeholders.Add(key, func); + + // Assert _basePlaceholders.Verify(p => p.Add(key, func), Times.Once); } [Fact] - public void should_call_underyling_when_removed() + public void Should_call_underyling_when_removed() { + // Arrange const string key = "{Test}"; + + // Act _placeholders.Remove(key); + + // Assert _basePlaceholders.Verify(p => p.Remove(key), Times.Once); } } diff --git a/test/Ocelot.UnitTests/Infrastructure/HttpDataRepositoryTests.cs b/test/Ocelot.UnitTests/Infrastructure/HttpDataRepositoryTests.cs index 9cbc2ad1d..34ad1f49a 100644 --- a/test/Ocelot.UnitTests/Infrastructure/HttpDataRepositoryTests.cs +++ b/test/Ocelot.UnitTests/Infrastructure/HttpDataRepositoryTests.cs @@ -6,70 +6,66 @@ namespace Ocelot.UnitTests.Infrastructure; public class HttpDataRepositoryTests : UnitTest { - private readonly HttpContext _httpContext; + private readonly DefaultHttpContext _httpContext; private readonly IHttpContextAccessor _httpContextAccessor; - private readonly HttpDataRepository _httpDataRepository; + private readonly HttpDataRepository _repository; private object _result; public HttpDataRepositoryTests() { _httpContext = new DefaultHttpContext(); _httpContextAccessor = new HttpContextAccessor { HttpContext = _httpContext }; - _httpDataRepository = new HttpDataRepository(_httpContextAccessor); + _repository = new HttpDataRepository(_httpContextAccessor); } /* TODO - Additional tests -> Type mistmatch aka Add string, request int TODO - Additional tests -> HttpContent null. This should never happen */ - [Fact] - public void get_returns_correct_key_from_http_context() + public void Get_returns_correct_key_from_http_context() { - this.Given(x => x.GivenAHttpContextContaining("key", "string")) - .When(x => x.GetIsCalledWithKey("key")) - .Then(x => x.ThenTheResultIsAnOkResponse("string")) - .BDDfy(); - } + // Arrange + _httpContext.Items.Add("key", "string"); - [Fact] - public void get_returns_error_response_if_the_key_is_not_found() //Therefore does not return null - { - this.Given(x => x.GivenAHttpContextContaining("key", "string")) - .When(x => x.GetIsCalledWithKey("keyDoesNotExist")) - .Then(x => x.ThenTheResultIsAnErrorReposnse("string1")) - .BDDfy(); + // Act + _result = _repository.Get("key"); + + // Assert + ThenTheResultIsAnOkResponse("string"); } [Fact] - public void should_update() + public void Get_returns_error_response_if_the_key_is_not_found() //Therefore does not return null { - this.Given(x => x.GivenAHttpContextContaining("key", "string")) - .And(x => x.UpdateIsCalledWith("key", "new string")) - .When(x => x.GetIsCalledWithKey("key")) - .Then(x => x.ThenTheResultIsAnOkResponse("new string")) - .BDDfy(); - } + // Arrange + _httpContext.Items.Add("key", "string"); - private void UpdateIsCalledWith(string key, string value) - { - _httpDataRepository.Update(key, value); - } + // Act + _result = _repository.Get("keyDoesNotExist"); - private void GivenAHttpContextContaining(string key, object o) - { - _httpContext.Items.Add(key, o); + // Assert + ThenTheResultIsAnErrorReposnse(); } - private void GetIsCalledWithKey(string key) + [Fact] + public void Should_update() { - _result = _httpDataRepository.Get(key); + // Arrange + _httpContext.Items.Add("key", "string"); + _repository.Update("key", "new string"); + + // Act + _result = _repository.Get("key"); + + // Assert + ThenTheResultIsAnOkResponse("new string"); } - private void ThenTheResultIsAnErrorReposnse(object resultValue) + private void ThenTheResultIsAnErrorReposnse() { _result.ShouldBeOfType>(); - ((ErrorResponse)_result).Data.ShouldBe(default(T)); + ((ErrorResponse)_result).Data.ShouldBe(default); ((ErrorResponse)_result).IsError.ShouldBe(true); ((ErrorResponse)_result).Errors.ShouldHaveSingleItem() .ShouldBeOfType() diff --git a/test/Ocelot.UnitTests/Infrastructure/InMemoryBusTests.cs b/test/Ocelot.UnitTests/Infrastructure/InMemoryBusTests.cs index c484ff58c..bc0f485f8 100644 --- a/test/Ocelot.UnitTests/Infrastructure/InMemoryBusTests.cs +++ b/test/Ocelot.UnitTests/Infrastructure/InMemoryBusTests.cs @@ -4,35 +4,34 @@ namespace Ocelot.UnitTests.Infrastructure; public class InMemoryBusTests { - private readonly InMemoryBus _bus; - - public InMemoryBusTests() - { - _bus = new InMemoryBus(); - } + private readonly InMemoryBus _bus = new(); [Fact] - public async Task should_publish_with_delay() + public async Task Should_publish_with_delay() { + // Arrange var called = false; - _bus.Subscribe(x => - { - called = true; - }); + _bus.Subscribe(x => called = true); + + // Act _bus.Publish(new object(), 1); await Task.Delay(100); + + // Assert called.ShouldBeTrue(); } [Fact] - public void should_not_be_publish_yet_as_no_delay_in_caller() + public void Should_not_be_publish_yet_as_no_delay_in_caller() { + // Arrange var called = false; - _bus.Subscribe(x => - { - called = true; - }); + _bus.Subscribe(x => called = true); + + // Act _bus.Publish(new object(), 1); + + // Assert called.ShouldBeFalse(); } } diff --git a/test/Ocelot.UnitTests/Infrastructure/PlaceholdersTests.cs b/test/Ocelot.UnitTests/Infrastructure/PlaceholdersTests.cs index 15e3704a3..e755d57f7 100644 --- a/test/Ocelot.UnitTests/Infrastructure/PlaceholdersTests.cs +++ b/test/Ocelot.UnitTests/Infrastructure/PlaceholdersTests.cs @@ -9,7 +9,7 @@ namespace Ocelot.UnitTests.Infrastructure; public class PlaceholdersTests { - private readonly IPlaceholders _placeholders; + private readonly Placeholders _placeholders; private readonly Mock _finder; private readonly Mock _repo; private readonly Mock _accessor; @@ -23,126 +23,190 @@ public PlaceholdersTests() } [Fact] - public void should_return_base_url() + public void Should_return_base_url() { + // Arrange var baseUrl = "http://www.bbc.co.uk"; _finder.Setup(x => x.Find()).Returns(baseUrl); + + // Act var result = _placeholders.Get("{BaseUrl}"); + + // Assert result.Data.ShouldBe(baseUrl); } [Fact] - public void should_return_remote_ip_address() + public void Should_return_remote_ip_address() { + // Arrange var httpContext = new DefaultHttpContext { Connection = { RemoteIpAddress = IPAddress.Any } }; _accessor.Setup(x => x.HttpContext).Returns(httpContext); + + // Act var result = _placeholders.Get("{RemoteIpAddress}"); + + // Assert result.Data.ShouldBe(httpContext.Connection.RemoteIpAddress.ToString()); } [Fact] - public void should_return_key_does_not_exist() + public void Should_return_key_does_not_exist() { + // Arrange, Act var result = _placeholders.Get("{Test}"); + + // Assert result.IsError.ShouldBeTrue(); result.Errors[0].Message.ShouldBe("Unable to find placeholder called {Test}"); } [Fact] - public void should_return_downstream_base_url_when_port_is_not_80_or_443() + public void Should_return_downstream_base_url_when_port_is_not_80_or_443() { + // Arrange var httpRequest = new HttpRequestMessage(); httpRequest.RequestUri = new Uri("http://www.bbc.co.uk"); var request = new DownstreamRequest(httpRequest); + + // Act var result = _placeholders.Get("{DownstreamBaseUrl}", request); + + // Assert result.Data.ShouldBe("http://www.bbc.co.uk/"); } [Fact] - public void should_return_downstream_base_url_when_port_is_80_or_443() + public void Should_return_downstream_base_url_when_port_is_80_or_443() { + // Arrange var httpRequest = new HttpRequestMessage(); httpRequest.RequestUri = new Uri("http://www.bbc.co.uk:123"); var request = new DownstreamRequest(httpRequest); + + // Act var result = _placeholders.Get("{DownstreamBaseUrl}", request); + + // Assert result.Data.ShouldBe("http://www.bbc.co.uk:123/"); } [Fact] - public void should_return_key_does_not_exist_for_http_request_message() + public void Should_return_key_does_not_exist_for_http_request_message() { + // Arrange var request = new DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "http://west.com")); + + // Act var result = _placeholders.Get("{Test}", request); + + // Assert result.IsError.ShouldBeTrue(); result.Errors[0].Message.ShouldBe("Unable to find placeholder called {Test}"); } [Fact] - public void should_return_trace_id() + public void Should_return_trace_id() { + // Arrange var traceId = "123"; _repo.Setup(x => x.Get("TraceId")).Returns(new OkResponse(traceId)); + + // Act var result = _placeholders.Get("{TraceId}"); + + // Assert result.Data.ShouldBe(traceId); } [Fact] - public void should_return_ok_when_added() + public void Should_return_ok_when_added() { + // Arrange, Act var result = _placeholders.Add("{Test}", () => new OkResponse("test")); + + // Assert result.IsError.ShouldBeFalse(); } [Fact] - public void should_return_ok_when_removed() + public void Should_return_ok_when_removed() { + // Arrange var result = _placeholders.Add("{Test}", () => new OkResponse("test")); + + // Act result = _placeholders.Remove("{Test}"); + + // Assert result.IsError.ShouldBeFalse(); } [Fact] - public void should_return_error_when_added() + public void Should_return_error_when_added() { + // Arrange var result = _placeholders.Add("{Test}", () => new OkResponse("test")); + + // Act result = _placeholders.Add("{Test}", () => new OkResponse("test")); + + // Assert result.IsError.ShouldBeTrue(); result.Errors[0].Message.ShouldBe("Unable to add placeholder: {Test}, placeholder already exists"); } [Fact] - public void should_return_error_when_removed() + public void Should_return_error_when_removed() { + // Arrange, Act var result = _placeholders.Remove("{Test}"); + + // Assert result.IsError.ShouldBeTrue(); result.Errors[0].Message.ShouldBe("Unable to remove placeholder: {Test}, placeholder does not exists"); } [Fact] - public void should_return_upstreamHost() + public void Should_return_upstreamHost() { + // Arrange var upstreamHost = "UpstreamHostA"; var httpContext = new DefaultHttpContext(); httpContext.Request.Headers.Append("Host", upstreamHost); _accessor.Setup(x => x.HttpContext).Returns(httpContext); + + // Act var result = _placeholders.Get("{UpstreamHost}"); + + // Assert result.Data.ShouldBe(upstreamHost); } [Fact] - public void should_return_error_when_finding_upstbecause_Host_not_set() + public void Should_return_error_when_finding_upstbecause_Host_not_set() { + // Arrange var httpContext = new DefaultHttpContext(); _accessor.Setup(x => x.HttpContext).Returns(httpContext); + + // Act var result = _placeholders.Get("{UpstreamHost}"); + + // Assert result.IsError.ShouldBeTrue(); } [Fact] - public void should_return_error_when_finding_upstream_host_because_exception_thrown() + public void Should_return_error_when_finding_upstream_host_because_exception_thrown() { + // Arrange _accessor.Setup(x => x.HttpContext).Throws(new Exception()); + + // Act var result = _placeholders.Get("{UpstreamHost}"); + + // Assert result.IsError.ShouldBeTrue(); } } diff --git a/test/Ocelot.UnitTests/Infrastructure/ScopesAuthorizerTests.cs b/test/Ocelot.UnitTests/Infrastructure/ScopesAuthorizerTests.cs index e8f251e64..e7c709e82 100644 --- a/test/Ocelot.UnitTests/Infrastructure/ScopesAuthorizerTests.cs +++ b/test/Ocelot.UnitTests/Infrastructure/ScopesAuthorizerTests.cs @@ -10,9 +10,6 @@ public class ScopesAuthorizerTests : UnitTest { private readonly ScopesAuthorizer _authorizer; public Mock _parser; - private ClaimsPrincipal _principal; - private List _allowedScopes; - private Response _result; public ScopesAuthorizerTests() { @@ -21,65 +18,79 @@ public ScopesAuthorizerTests() } [Fact] - public void should_return_ok_if_no_allowed_scopes() + public void Should_return_ok_if_no_allowed_scopes() { - this.Given(_ => GivenTheFollowing(new ClaimsPrincipal())) - .And(_ => GivenTheFollowing(new List())) - .When(_ => WhenIAuthorize()) - .Then(_ => ThenTheFollowingIsReturned(new OkResponse(true))) - .BDDfy(); + // Arrange + var principal = new ClaimsPrincipal(); + var allowedScopes = new List(); + + // Act + var result = _authorizer.Authorize(principal, allowedScopes); + + // Assert + ThenTheFollowingIsReturned(result, new OkResponse(true)); } [Fact] - public void should_return_ok_if_null_allowed_scopes() + public void Should_return_ok_if_null_allowed_scopes() { - this.Given(_ => GivenTheFollowing(new ClaimsPrincipal())) - .And(_ => GivenTheFollowing((List)null)) - .When(_ => WhenIAuthorize()) - .Then(_ => ThenTheFollowingIsReturned(new OkResponse(true))) - .BDDfy(); + // Arrange + var principal = new ClaimsPrincipal(); + var allowedScopes = (List)null; + + // Act + var result = _authorizer.Authorize(principal, allowedScopes); + + // Assert + ThenTheFollowingIsReturned(result, new OkResponse(true)); } [Fact] - public void should_return_error_if_claims_parser_returns_error() + public void Should_return_error_if_claims_parser_returns_error() { + // Arrange var fakeError = new FakeError(); - this.Given(_ => GivenTheFollowing(new ClaimsPrincipal())) - .And(_ => GivenTheParserReturns(new ErrorResponse>(fakeError))) - .And(_ => GivenTheFollowing(new List { "doesntmatter" })) - .When(_ => WhenIAuthorize()) - .Then(_ => ThenTheFollowingIsReturned(new ErrorResponse(fakeError))) - .BDDfy(); + var principal = new ClaimsPrincipal(); + GivenTheParserReturns(new ErrorResponse>(fakeError)); + var allowedScopes = new List { "doesntmatter" }; + + // Act + var result = _authorizer.Authorize(principal, allowedScopes); + + // Assert + ThenTheFollowingIsReturned(result, new ErrorResponse(fakeError)); } [Fact] - public void should_match_scopes_and_return_ok_result() + public void Should_match_scopes_and_return_ok_result() { - var claimsPrincipal = new ClaimsPrincipal(); + // Arrange + var principal = new ClaimsPrincipal(); var allowedScopes = new List { "someScope" }; + GivenTheParserReturns(new OkResponse>(allowedScopes)); + + // Act + var result = _authorizer.Authorize(principal, allowedScopes); - this.Given(_ => GivenTheFollowing(claimsPrincipal)) - .And(_ => GivenTheParserReturns(new OkResponse>(allowedScopes))) - .And(_ => GivenTheFollowing(allowedScopes)) - .When(_ => WhenIAuthorize()) - .Then(_ => ThenTheFollowingIsReturned(new OkResponse(true))) - .BDDfy(); + // Assert + ThenTheFollowingIsReturned(result, new OkResponse(true)); } [Fact] - public void should_not_match_scopes_and_return_error_result() + public void Should_not_match_scopes_and_return_error_result() { + // Arrange var fakeError = new FakeError(); - var claimsPrincipal = new ClaimsPrincipal(); + var principal = new ClaimsPrincipal(); var allowedScopes = new List { "someScope" }; var userScopes = new List { "anotherScope" }; + GivenTheParserReturns(new OkResponse>(userScopes)); - this.Given(_ => GivenTheFollowing(claimsPrincipal)) - .And(_ => GivenTheParserReturns(new OkResponse>(userScopes))) - .And(_ => GivenTheFollowing(allowedScopes)) - .When(_ => WhenIAuthorize()) - .Then(_ => ThenTheFollowingIsReturned(new ErrorResponse(fakeError))) - .BDDfy(); + // Act + var result = _authorizer.Authorize(principal, allowedScopes); + + // Assert + ThenTheFollowingIsReturned(result, new ErrorResponse(fakeError)); } private void GivenTheParserReturns(Response> response) @@ -87,25 +98,10 @@ private void GivenTheParserReturns(Response> response) _parser.Setup(x => x.GetValuesByClaimType(It.IsAny>(), It.IsAny())).Returns(response); } - private void GivenTheFollowing(ClaimsPrincipal principal) - { - _principal = principal; - } - - private void GivenTheFollowing(List allowedScopes) - { - _allowedScopes = allowedScopes; - } - - private void WhenIAuthorize() - { - _result = _authorizer.Authorize(_principal, _allowedScopes); - } - - private void ThenTheFollowingIsReturned(Response expected) + private static void ThenTheFollowingIsReturned(Response actual, Response expected) { - _result.Data.ShouldBe(expected.Data); - _result.IsError.ShouldBe(expected.IsError); + actual.Data.ShouldBe(expected.Data); + actual.IsError.ShouldBe(expected.IsError); } } diff --git a/test/Ocelot.UnitTests/Kubernetes/PollKubeTests.cs b/test/Ocelot.UnitTests/Kubernetes/PollKubeTests.cs index e7910708a..d52cfa98e 100644 --- a/test/Ocelot.UnitTests/Kubernetes/PollKubeTests.cs +++ b/test/Ocelot.UnitTests/Kubernetes/PollKubeTests.cs @@ -30,23 +30,16 @@ public PollKubeTests() [Trait("Feat", "345")] public void Should_return_service_from_kube() { + // Arrange var service = new Service(string.Empty, new ServiceHostAndPort(string.Empty, 0), string.Empty, string.Empty, new List()); - - this.Given(x => GivenKubeReturns(service)) - .When(x => WhenIGetTheServices(1)) - .Then(x => ThenTheCountIs(1)) - .BDDfy(); - } - - private void GivenKubeReturns(Service service) - { _services.Add(service); _kubeServiceDiscoveryProvider.Setup(x => x.GetAsync()).ReturnsAsync(_services); - } - private void ThenTheCountIs(int count) - { - _result.Count.ShouldBe(count); + // Act + WhenIGetTheServices(1); + + // Assert + _result.Count.ShouldBe(1); } private void WhenIGetTheServices(int expected) diff --git a/test/Ocelot.UnitTests/LoadBalancer/CookieStickySessionsCreatorTests.cs b/test/Ocelot.UnitTests/LoadBalancer/CookieStickySessionsCreatorTests.cs index 130b4f18b..e1acea0e9 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/CookieStickySessionsCreatorTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/CookieStickySessionsCreatorTests.cs @@ -1,7 +1,6 @@ using Ocelot.Configuration; using Ocelot.Configuration.Builder; using Ocelot.LoadBalancer.LoadBalancers; -using Ocelot.Responses; using Ocelot.ServiceDiscovery.Providers; namespace Ocelot.UnitTests.LoadBalancer; @@ -10,60 +9,32 @@ public class CookieStickySessionsCreatorTests : UnitTest { private readonly CookieStickySessionsCreator _creator; private readonly Mock _serviceProvider; - private DownstreamRoute _route; - private Response _loadBalancer; - private string _typeName; public CookieStickySessionsCreatorTests() { - _creator = new CookieStickySessionsCreator(); - _serviceProvider = new Mock(); + _creator = new(); + _serviceProvider = new(); } [Fact] - public void should_return_instance_of_expected_load_balancer_type() + public void Should_return_instance_of_expected_load_balancer_type() { + // Arrange var route = new DownstreamRouteBuilder() .WithLoadBalancerOptions(new LoadBalancerOptions("myType", "myKey", 1000)) .Build(); - this.Given(x => x.GivenARoute(route)) - .When(x => x.WhenIGetTheLoadBalancer()) - .Then(x => x.ThenTheLoadBalancerIsReturned()) - .BDDfy(); - } - - [Fact] - public void should_return_expected_name() - { - this.When(x => x.WhenIGetTheLoadBalancerTypeName()) - .Then(x => x.ThenTheLoadBalancerTypeIs("CookieStickySessions")) - .BDDfy(); - } - - private void GivenARoute(DownstreamRoute route) - { - _route = route; - } + // Act + var loadBalancer = _creator.Create(route, _serviceProvider.Object); - private void WhenIGetTheLoadBalancer() - { - _loadBalancer = _creator.Create(_route, _serviceProvider.Object); + // Assert + loadBalancer.Data.ShouldBeOfType(); } - private void WhenIGetTheLoadBalancerTypeName() - { - _typeName = _creator.Type; - } - - private void ThenTheLoadBalancerIsReturned() - where T : ILoadBalancer - { - _loadBalancer.Data.ShouldBeOfType(); - } - - private void ThenTheLoadBalancerTypeIs(string type) + [Fact] + public void Should_return_expected_name() { - _typeName.ShouldBe(type); + // Arrange, Act, Assert + _creator.Type.ShouldBe(nameof(CookieStickySessions)); } } diff --git a/test/Ocelot.UnitTests/LoadBalancer/CookieStickySessionsTests.cs b/test/Ocelot.UnitTests/LoadBalancer/CookieStickySessionsTests.cs index c2c95f921..f09992018 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/CookieStickySessionsTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/CookieStickySessionsTests.cs @@ -16,11 +16,8 @@ public sealed class CookieStickySessionsTests : UnitTest private readonly CookieStickySessions _stickySessions; private readonly Mock _loadBalancer; private readonly int _defaultExpiryInMs; - private Response _result; - private Response _firstHostAndPort; - private Response _secondHostAndPort; private readonly FakeBus _bus; - private readonly HttpContext _httpContext; + private readonly DefaultHttpContext _httpContext; public CookieStickySessionsTests() { @@ -46,9 +43,13 @@ public async Task Should_expire_sticky_session() GivenTheLoadBalancerReturns(); GivenTheDownstreamRequestHasSessionId("321"); GivenIHackAMessageInWithAPastExpiry(); - await WhenILease(); - WhenTheMessagesAreProcessed(); - ThenTheLoadBalancerIsCalled(); + + // Act + var result = await _stickySessions.LeaseAsync(_httpContext); + _bus.Process(); + + // Assert + _loadBalancer.Verify(x => x.Release(It.IsAny()), Times.Once); } [Fact] @@ -57,8 +58,12 @@ public async Task Should_return_host_and_port() Arrange(); GivenTheLoadBalancerReturns(); GivenTheDownstreamRequestHasSessionId("321"); - await WhenILease(); - ThenTheHostAndPortIsNotNull(); + + // Act + var result = await _stickySessions.LeaseAsync(_httpContext); + + // Assert + result.Data.ShouldNotBeNull(); } [Fact] @@ -67,9 +72,15 @@ public async Task Should_return_same_host_and_port() Arrange(); GivenTheLoadBalancerReturnsSequence(); GivenTheDownstreamRequestHasSessionId("321"); - await WhenILeaseTwiceInARow(); - ThenTheFirstAndSecondResponseAreTheSame(); - ThenTheStickySessionWillTimeout(); + + // Act + var firstHostAndPort = await _stickySessions.LeaseAsync(_httpContext); + var secondHostAndPort = await _stickySessions.LeaseAsync(_httpContext); + + // Assert + firstHostAndPort.Data.DownstreamHost.ShouldBe(secondHostAndPort.Data.DownstreamHost); + firstHostAndPort.Data.DownstreamPort.ShouldBe(secondHostAndPort.Data.DownstreamPort); + _bus.Messages.Count.ShouldBe(2); } [Fact] @@ -77,82 +88,61 @@ public async Task Should_return_different_host_and_port_if_load_balancer_does() { Arrange(); GivenTheLoadBalancerReturnsSequence(); - await WhenIMakeTwoRequetsWithDifferentSessionValues(); - ThenADifferentHostAndPortIsReturned(); + + // When I Make Two Requets With Different Session Values + var contextOne = new DefaultHttpContext(); + var cookiesOne = new FakeCookies(); + cookiesOne.AddCookie("sessionid", "321"); + contextOne.Request.Cookies = cookiesOne; + var route = new DownstreamRouteBuilder() + .WithLoadBalancerKey(nameof(Should_return_different_host_and_port_if_load_balancer_does)) + .Build(); + contextOne.Items.UpsertDownstreamRoute(route); + + var contextTwo = new DefaultHttpContext(); + var cookiesTwo = new FakeCookies(); + cookiesTwo.AddCookie("sessionid", "123"); + contextTwo.Request.Cookies = cookiesTwo; + contextTwo.Items.UpsertDownstreamRoute(route); + + // Act + var firstHostAndPort = await _stickySessions.LeaseAsync(contextOne); + var secondHostAndPort = await _stickySessions.LeaseAsync(contextTwo); + + // Assert + firstHostAndPort.Data.DownstreamHost.ShouldBe("one"); + firstHostAndPort.Data.DownstreamPort.ShouldBe(80); + secondHostAndPort.Data.DownstreamHost.ShouldBe("two"); + secondHostAndPort.Data.DownstreamPort.ShouldBe(80); } [Fact] public async Task Should_return_error() { Arrange(); - GivenTheLoadBalancerReturnsError(); - await WhenILease(); - ThenAnErrorIsReturned(); + _loadBalancer.Setup(x => x.LeaseAsync(It.IsAny())) + .ReturnsAsync(new ErrorResponse(new AnyError())); + + // Act + var result = await _stickySessions.LeaseAsync(_httpContext); + + // Assert + result.IsError.ShouldBeTrue(); } [Fact] public void Should_release() { + // Arrange, Act, Assert _stickySessions.Release(new ServiceHostAndPort(string.Empty, 0)); } - private void ThenTheLoadBalancerIsCalled() - { - _loadBalancer.Verify(x => x.Release(It.IsAny()), Times.Once); - } - - private void WhenTheMessagesAreProcessed() - { - _bus.Process(); - } - private void GivenIHackAMessageInWithAPastExpiry() { var hostAndPort = new ServiceHostAndPort("999", 999); _bus.Publish(new StickySession(hostAndPort, DateTime.UtcNow.AddDays(-1), "321"), 0); } - private void ThenAnErrorIsReturned() - { - _result.IsError.ShouldBeTrue(); - } - - private void GivenTheLoadBalancerReturnsError() - { - _loadBalancer - .Setup(x => x.LeaseAsync(It.IsAny())) - .ReturnsAsync(new ErrorResponse(new AnyError())); - } - - private void ThenADifferentHostAndPortIsReturned() - { - _firstHostAndPort.Data.DownstreamHost.ShouldBe("one"); - _firstHostAndPort.Data.DownstreamPort.ShouldBe(80); - _secondHostAndPort.Data.DownstreamHost.ShouldBe("two"); - _secondHostAndPort.Data.DownstreamPort.ShouldBe(80); - } - - private async Task WhenIMakeTwoRequetsWithDifferentSessionValues([CallerMemberName] string serviceName = null) - { - var contextOne = new DefaultHttpContext(); - var cookiesOne = new FakeCookies(); - cookiesOne.AddCookie("sessionid", "321"); - contextOne.Request.Cookies = cookiesOne; - var route = new DownstreamRouteBuilder() - .WithLoadBalancerKey(serviceName) - .Build(); - contextOne.Items.UpsertDownstreamRoute(route); - - var contextTwo = new DefaultHttpContext(); - var cookiesTwo = new FakeCookies(); - cookiesTwo.AddCookie("sessionid", "123"); - contextTwo.Request.Cookies = cookiesTwo; - contextTwo.Items.UpsertDownstreamRoute(route); - - _firstHostAndPort = await _stickySessions.LeaseAsync(contextOne); - _secondHostAndPort = await _stickySessions.LeaseAsync(contextTwo); - } - private void GivenTheLoadBalancerReturnsSequence() { _loadBalancer @@ -161,18 +151,6 @@ private void GivenTheLoadBalancerReturnsSequence() .ReturnsAsync(new OkResponse(new ServiceHostAndPort("two", 80))); } - private void ThenTheFirstAndSecondResponseAreTheSame() - { - _firstHostAndPort.Data.DownstreamHost.ShouldBe(_secondHostAndPort.Data.DownstreamHost); - _firstHostAndPort.Data.DownstreamPort.ShouldBe(_secondHostAndPort.Data.DownstreamPort); - } - - private async Task WhenILeaseTwiceInARow() - { - _firstHostAndPort = await _stickySessions.LeaseAsync(_httpContext); - _secondHostAndPort = await _stickySessions.LeaseAsync(_httpContext); - } - private void GivenTheDownstreamRequestHasSessionId(string value) { var cookies = new FakeCookies(); @@ -186,57 +164,19 @@ private void GivenTheLoadBalancerReturns() .Setup(x => x.LeaseAsync(It.IsAny())) .ReturnsAsync(new OkResponse(new ServiceHostAndPort(string.Empty, 80))); } - - private async Task WhenILease() - { - _result = await _stickySessions.LeaseAsync(_httpContext); - } - - private void ThenTheHostAndPortIsNotNull() - { - _result.Data.ShouldNotBeNull(); - } - - private void ThenTheStickySessionWillTimeout() - { - _bus.Messages.Count.ShouldBe(2); - } } internal class FakeCookies : IRequestCookieCollection { private readonly Dictionary _cookies = new(); - public string this[string key] => _cookies[key]; - public int Count => _cookies.Count; - public ICollection Keys => _cookies.Keys; - - public void AddCookie(string key, string value) - { - _cookies[key] = value; - } - - public bool ContainsKey(string key) - { - return _cookies.ContainsKey(key); - } - - public IEnumerator> GetEnumerator() - { - return _cookies.GetEnumerator(); - } - - public bool TryGetValue(string key, out string value) - { - return _cookies.TryGetValue(key, out value); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return _cookies.GetEnumerator(); - } + public void AddCookie(string key, string value) => _cookies[key] = value; + public bool ContainsKey(string key) => _cookies.ContainsKey(key); + public IEnumerator> GetEnumerator() => _cookies.GetEnumerator(); + public bool TryGetValue(string key, out string value) => _cookies.TryGetValue(key, out value); + IEnumerator IEnumerable.GetEnumerator() => _cookies.GetEnumerator(); } internal class FakeBus : IBus @@ -250,15 +190,8 @@ public FakeBus() public List Messages { get; } public List> Subscriptions { get; } - public void Subscribe(Action action) - { - Subscriptions.Add(action); - } - - public void Publish(T message, int delay) - { - Messages.Add(message); - } + public void Subscribe(Action action) => Subscriptions.Add(action); + public void Publish(T message, int delay) => Messages.Add(message); public void Process() { diff --git a/test/Ocelot.UnitTests/LoadBalancer/DelegateInvokingLoadBalancerCreatorTests.cs b/test/Ocelot.UnitTests/LoadBalancer/DelegateInvokingLoadBalancerCreatorTests.cs index 2de9125c3..da135bb32 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/DelegateInvokingLoadBalancerCreatorTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/DelegateInvokingLoadBalancerCreatorTests.cs @@ -13,9 +13,6 @@ public class DelegateInvokingLoadBalancerCreatorTests : UnitTest private DelegateInvokingLoadBalancerCreator _creator; private Func _creatorFunc; private readonly Mock _serviceProvider; - private DownstreamRoute _route; - private Response _loadBalancer; - private string _typeName; public DelegateInvokingLoadBalancerCreatorTests() { @@ -26,74 +23,44 @@ public DelegateInvokingLoadBalancerCreatorTests() } [Fact] - public void should_return_expected_name() + public void Should_return_expected_name() { - this.When(x => x.WhenIGetTheLoadBalancerTypeName()) - .Then(x => x.ThenTheLoadBalancerTypeIs("FakeLoadBalancer")) - .BDDfy(); - } + // Arrange + var route = new DownstreamRouteBuilder().Build(); - [Fact] - public void should_return_result_of_specified_creator_func() - { - var route = new DownstreamRouteBuilder() - .Build(); + // Act + var loadBalancer = _creator.Create(route, _serviceProvider.Object); - this.Given(x => x.GivenARoute(route)) - .When(x => x.WhenIGetTheLoadBalancer()) - .Then(x => x.ThenTheLoadBalancerIsReturned()) - .BDDfy(); + // Assert + loadBalancer.Data.Type.ShouldBe(nameof(FakeLoadBalancer)); } [Fact] - public void should_return_error() + public void Should_return_result_of_specified_creator_func() { - var route = new DownstreamRouteBuilder() - .Build(); + // Arrange + var route = new DownstreamRouteBuilder().Build(); - this.Given(x => x.GivenARoute(route)) - .And(x => x.GivenTheCreatorFuncThrows()) - .When(x => x.WhenIGetTheLoadBalancer()) - .Then(x => x.ThenAnErrorIsReturned()) - .BDDfy(); + // Act + var loadBalancer = _creator.Create(route, _serviceProvider.Object); + + // Assert + loadBalancer.Data.ShouldBeOfType(); } - private void GivenTheCreatorFuncThrows() + [Fact] + public void Should_return_error() { + // Arrange + var route = new DownstreamRouteBuilder().Build(); _creatorFunc = (route, serviceDiscoveryProvider) => throw new Exception(); - _creator = new DelegateInvokingLoadBalancerCreator(_creatorFunc); - } - private void ThenAnErrorIsReturned() - { - _loadBalancer.IsError.ShouldBeTrue(); - } + // Act + var loadBalancer = _creator.Create(route, _serviceProvider.Object); - private void GivenARoute(DownstreamRoute route) - { - _route = route; - } - - private void WhenIGetTheLoadBalancer() - { - _loadBalancer = _creator.Create(_route, _serviceProvider.Object); - } - - private void WhenIGetTheLoadBalancerTypeName() - { - _typeName = _creator.Type; - } - - private void ThenTheLoadBalancerIsReturned() - where T : ILoadBalancer - { - _loadBalancer.Data.ShouldBeOfType(); - } - - private void ThenTheLoadBalancerTypeIs(string type) - { - _typeName.ShouldBe(type); + // Assert + loadBalancer.IsError.ShouldBeTrue(); } private class FakeLoadBalancer : ILoadBalancer @@ -106,7 +73,6 @@ public FakeLoadBalancer(DownstreamRoute downstreamRoute, IServiceDiscoveryProvid public DownstreamRoute DownstreamRoute { get; } public IServiceDiscoveryProvider ServiceDiscoveryProvider { get; } - public string Type => nameof(FakeLoadBalancer); public Task> LeaseAsync(HttpContext httpContext) => throw new NotImplementedException(); public void Release(ServiceHostAndPort hostAndPort) => throw new NotImplementedException(); diff --git a/test/Ocelot.UnitTests/LoadBalancer/LeastConnectionCreatorTests.cs b/test/Ocelot.UnitTests/LoadBalancer/LeastConnectionCreatorTests.cs index b545b0d24..e546301be 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/LeastConnectionCreatorTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/LeastConnectionCreatorTests.cs @@ -1,7 +1,5 @@ -using Ocelot.Configuration; -using Ocelot.Configuration.Builder; +using Ocelot.Configuration.Builder; using Ocelot.LoadBalancer.LoadBalancers; -using Ocelot.Responses; using Ocelot.ServiceDiscovery.Providers; namespace Ocelot.UnitTests.LoadBalancer; @@ -10,60 +8,32 @@ public class LeastConnectionCreatorTests : UnitTest { private readonly LeastConnectionCreator _creator; private readonly Mock _serviceProvider; - private DownstreamRoute _route; - private Response _loadBalancer; - private string _typeName; public LeastConnectionCreatorTests() { - _creator = new LeastConnectionCreator(); - _serviceProvider = new Mock(); + _creator = new(); + _serviceProvider = new(); } [Fact] - public void should_return_instance_of_expected_load_balancer_type() + public void Should_return_instance_of_expected_load_balancer_type() { + // Arrange var route = new DownstreamRouteBuilder() .WithServiceName("myService") .Build(); - this.Given(x => x.GivenARoute(route)) - .When(x => x.WhenIGetTheLoadBalancer()) - .Then(x => x.ThenTheLoadBalancerIsReturned()) - .BDDfy(); - } - - [Fact] - public void should_return_expected_name() - { - this.When(x => x.WhenIGetTheLoadBalancerTypeName()) - .Then(x => x.ThenTheLoadBalancerTypeIs("LeastConnection")) - .BDDfy(); - } - - private void GivenARoute(DownstreamRoute route) - { - _route = route; - } + // Act + var loadBalancer = _creator.Create(route, _serviceProvider.Object); - private void WhenIGetTheLoadBalancer() - { - _loadBalancer = _creator.Create(_route, _serviceProvider.Object); + // Assert + loadBalancer.Data.ShouldBeOfType(); } - private void WhenIGetTheLoadBalancerTypeName() - { - _typeName = _creator.Type; - } - - private void ThenTheLoadBalancerIsReturned() - where T : ILoadBalancer - { - _loadBalancer.Data.ShouldBeOfType(); - } - - private void ThenTheLoadBalancerTypeIs(string type) + [Fact] + public void Should_return_expected_name() { - _typeName.ShouldBe(type); + // Arrange, Act, Assert + _creator.Type.ShouldBe(nameof(LeastConnection)); } } diff --git a/test/Ocelot.UnitTests/LoadBalancer/LeastConnectionTests.cs b/test/Ocelot.UnitTests/LoadBalancer/LeastConnectionTests.cs index 4d048a730..b2f5bc384 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/LeastConnectionTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/LeastConnectionTests.cs @@ -1,42 +1,33 @@ using Microsoft.AspNetCore.Http; -using Ocelot.Errors; using Ocelot.LoadBalancer.LoadBalancers; -using Ocelot.Responses; using Ocelot.Values; namespace Ocelot.UnitTests.LoadBalancer; public class LeastConnectionTests : UnitTest { - private ServiceHostAndPort _hostAndPort; - private Response _result; private LeastConnection _leastConnection; - private List _services; private readonly Random _random; - private readonly HttpContext _httpContext; + private readonly DefaultHttpContext _httpContext; public LeastConnectionTests() { - _httpContext = new DefaultHttpContext(); - _random = new Random(); + _httpContext = new(); + _random = new(); } [Fact] public async Task Should_be_able_to_lease_and_release_concurrently() { - var serviceName = "products"; - + const string ServiceName = "products"; var availableServices = new List { - new(serviceName, new ServiceHostAndPort("127.0.0.1", 80), string.Empty, string.Empty, Array.Empty()), - new(serviceName, new ServiceHostAndPort("127.0.0.2", 80), string.Empty, string.Empty, Array.Empty()), + new(ServiceName, new ServiceHostAndPort("127.0.0.1", 80), string.Empty, string.Empty, Array.Empty()), + new(ServiceName, new ServiceHostAndPort("127.0.0.2", 80), string.Empty, string.Empty, Array.Empty()), }; - - _services = availableServices; - _leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName); + _leastConnection = new LeastConnection(() => Task.FromResult(availableServices), ServiceName); var tasks = new Task[100]; - for (var i = 0; i < tasks.Length; i++) { tasks[i] = LeaseDelayAndRelease(); @@ -48,15 +39,15 @@ public async Task Should_be_able_to_lease_and_release_concurrently() [Fact] public async Task Should_handle_service_returning_to_available() { - var serviceName = "products"; + const string ServiceName = "products"; var availableServices = new List { - new(serviceName, new ServiceHostAndPort("127.0.0.1", 80), string.Empty, string.Empty, Array.Empty()), - new(serviceName, new ServiceHostAndPort("127.0.0.2", 80), string.Empty, string.Empty, Array.Empty()), + new(ServiceName, new ServiceHostAndPort("127.0.0.1", 80), string.Empty, string.Empty, Array.Empty()), + new(ServiceName, new ServiceHostAndPort("127.0.0.2", 80), string.Empty, string.Empty, Array.Empty()), }; - _leastConnection = new LeastConnection(() => Task.FromResult(availableServices), serviceName); + _leastConnection = new LeastConnection(() => Task.FromResult(availableServices), ServiceName); var hostAndPortOne = await _leastConnection.LeaseAsync(_httpContext); hostAndPortOne.Data.DownstreamHost.ShouldBe("127.0.0.1"); @@ -67,7 +58,7 @@ public async Task Should_handle_service_returning_to_available() availableServices = new List { - new(serviceName, new ServiceHostAndPort("127.0.0.1", 80), string.Empty, string.Empty, Array.Empty()), + new(ServiceName, new ServiceHostAndPort("127.0.0.1", 80), string.Empty, string.Empty, Array.Empty()), }; hostAndPortOne = await _leastConnection.LeaseAsync(_httpContext); @@ -79,8 +70,8 @@ public async Task Should_handle_service_returning_to_available() availableServices = new List { - new(serviceName, new ServiceHostAndPort("127.0.0.1", 80), string.Empty, string.Empty, Array.Empty()), - new(serviceName, new ServiceHostAndPort("127.0.0.2", 80), string.Empty, string.Empty, Array.Empty()), + new(ServiceName, new ServiceHostAndPort("127.0.0.1", 80), string.Empty, string.Empty, Array.Empty()), + new(ServiceName, new ServiceHostAndPort("127.0.0.2", 80), string.Empty, string.Empty, Array.Empty()), }; hostAndPortOne = await _leastConnection.LeaseAsync(_httpContext); @@ -99,38 +90,37 @@ private async Task LeaseDelayAndRelease() } [Fact] - public void Should_get_next_url() + public async Task Should_get_next_url() { - var serviceName = "products"; - + // Arrange + const string ServiceName = "products"; var hostAndPort = new ServiceHostAndPort("localhost", 80); - var availableServices = new List { - new(serviceName, hostAndPort, string.Empty, string.Empty, Array.Empty()), + new(ServiceName, hostAndPort, string.Empty, string.Empty, Array.Empty()), }; + _leastConnection = new LeastConnection(() => Task.FromResult(availableServices), ServiceName); + + // Act + var result = await _leastConnection.LeaseAsync(_httpContext); - this.Given(x => x.GivenAHostAndPort(hostAndPort)) - .And(x => x.GivenTheLoadBalancerStarts(availableServices, serviceName)) - .When(x => x.WhenIGetTheNextHostAndPort()) - .Then(x => x.ThenTheNextHostAndPortIsReturned()) - .BDDfy(); + // Assert + result.Data.DownstreamHost.ShouldBe(hostAndPort.DownstreamHost); + result.Data.DownstreamPort.ShouldBe(hostAndPort.DownstreamPort); } [Fact] public async Task Should_serve_from_service_with_least_connections() { - var serviceName = "products"; - + const string ServiceName = "products"; var availableServices = new List { - new(serviceName, new ServiceHostAndPort("127.0.0.1", 80), string.Empty, string.Empty, Array.Empty()), - new(serviceName, new ServiceHostAndPort("127.0.0.2", 80), string.Empty, string.Empty, Array.Empty()), - new(serviceName, new ServiceHostAndPort("127.0.0.3", 80), string.Empty, string.Empty, Array.Empty()), + new(ServiceName, new ServiceHostAndPort("127.0.0.1", 80), string.Empty, string.Empty, Array.Empty()), + new(ServiceName, new ServiceHostAndPort("127.0.0.2", 80), string.Empty, string.Empty, Array.Empty()), + new(ServiceName, new ServiceHostAndPort("127.0.0.3", 80), string.Empty, string.Empty, Array.Empty()), }; - _services = availableServices; - _leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName); + _leastConnection = new LeastConnection(() => Task.FromResult(availableServices), ServiceName); var response = await _leastConnection.LeaseAsync(_httpContext); @@ -148,16 +138,14 @@ public async Task Should_serve_from_service_with_least_connections() [Fact] public async Task Should_build_connections_per_service() { - var serviceName = "products"; - + const string ServiceName = "products"; var availableServices = new List { - new(serviceName, new ServiceHostAndPort("127.0.0.1", 80), string.Empty, string.Empty, Array.Empty()), - new(serviceName, new ServiceHostAndPort("127.0.0.2", 80), string.Empty, string.Empty, Array.Empty()), + new(ServiceName, new ServiceHostAndPort("127.0.0.1", 80), string.Empty, string.Empty, Array.Empty()), + new(ServiceName, new ServiceHostAndPort("127.0.0.2", 80), string.Empty, string.Empty, Array.Empty()), }; - _services = availableServices; - _leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName); + _leastConnection = new LeastConnection(() => Task.FromResult(availableServices), ServiceName); var response = await _leastConnection.LeaseAsync(_httpContext); @@ -179,16 +167,14 @@ public async Task Should_build_connections_per_service() [Fact] public async Task Should_release_connection() { - var serviceName = "products"; - + const string ServiceName = "products"; var availableServices = new List { - new(serviceName, new ServiceHostAndPort("127.0.0.1", 80), string.Empty, string.Empty, Array.Empty()), - new(serviceName, new ServiceHostAndPort("127.0.0.2", 80), string.Empty, string.Empty, Array.Empty()), + new(ServiceName, new ServiceHostAndPort("127.0.0.1", 80), string.Empty, string.Empty, Array.Empty()), + new(ServiceName, new ServiceHostAndPort("127.0.0.2", 80), string.Empty, string.Empty, Array.Empty()), }; - _services = availableServices; - _leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName); + _leastConnection = new LeastConnection(() => Task.FromResult(availableServices), ServiceName); var response = await _leastConnection.LeaseAsync(_httpContext); @@ -215,57 +201,34 @@ public async Task Should_release_connection() } [Fact] - public void Should_return_error_if_services_are_null() - { - var serviceName = "products"; - - var hostAndPort = new ServiceHostAndPort("localhost", 80); - this.Given(x => x.GivenAHostAndPort(hostAndPort)) - .And(x => x.GivenTheLoadBalancerStarts(null, serviceName)) - .When(x => x.WhenIGetTheNextHostAndPort()) - .Then(x => x.ThenErrorIsReturned()) - .BDDfy(); - } - - [Fact] - public void Should_return_error_if_services_are_empty() + public async Task Should_return_error_if_services_are_null() { - var serviceName = "products"; - + // Arrange + const string ServiceName = "products"; var hostAndPort = new ServiceHostAndPort("localhost", 80); - this.Given(x => x.GivenAHostAndPort(hostAndPort)) - .And(x => x.GivenTheLoadBalancerStarts(new List(), serviceName)) - .When(x => x.WhenIGetTheNextHostAndPort()) - .Then(x => x.ThenErrorIsReturned()) - .BDDfy(); - } + _leastConnection = new LeastConnection(() => Task.FromResult((List)null), ServiceName); - private void ThenErrorIsReturned() - where TError : Error - { - _result.IsError.ShouldBeTrue(); - _result.Errors[0].ShouldBeOfType(); - } + // Act + var result = await _leastConnection.LeaseAsync(_httpContext); - private void GivenTheLoadBalancerStarts(List services, string serviceName) - { - _services = services; - _leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName); + // Assert + result.IsError.ShouldBeTrue(); + result.Errors[0].ShouldBeOfType(); } - private void GivenAHostAndPort(ServiceHostAndPort hostAndPort) + [Fact] + public async Task Should_return_error_if_services_are_empty() { - _hostAndPort = hostAndPort; - } + // Arrange + const string ServiceName = "products"; + var hostAndPort = new ServiceHostAndPort("localhost", 80); + _leastConnection = new LeastConnection(() => Task.FromResult(new List()), ServiceName); - private async Task WhenIGetTheNextHostAndPort() - { - _result = await _leastConnection.LeaseAsync(_httpContext); - } + // Act + var result = await _leastConnection.LeaseAsync(_httpContext); - private void ThenTheNextHostAndPortIsReturned() - { - _result.Data.DownstreamHost.ShouldBe(_hostAndPort.DownstreamHost); - _result.Data.DownstreamPort.ShouldBe(_hostAndPort.DownstreamPort); + // Assert + result.IsError.ShouldBeTrue(); + result.Errors[0].ShouldBeOfType(); } } diff --git a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerFactoryTests.cs b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerFactoryTests.cs index 308abc0b5..dbd046216 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerFactoryTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerFactoryTests.cs @@ -12,13 +12,10 @@ namespace Ocelot.UnitTests.LoadBalancer; public class LoadBalancerFactoryTests : UnitTest { - private DownstreamRoute _route; private readonly LoadBalancerFactory _factory; - private Response _result; private readonly Mock _serviceProviderFactory; private readonly IEnumerable _loadBalancerCreators; private readonly Mock _serviceProvider; - private ServiceProviderConfiguration _serviceProviderConfig; public LoadBalancerFactoryTests() { @@ -35,104 +32,111 @@ public LoadBalancerFactoryTests() } [Fact] - public void should_return_no_load_balancer_by_default() + public void Should_return_no_load_balancer_by_default() { + // Arrange var route = new DownstreamRouteBuilder() - .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamHttpMethod(new() { HttpMethods.Get }) .Build(); + var config = new ServiceProviderConfigurationBuilder().Build(); + GivenTheServiceProviderFactoryReturns(); - this.Given(x => x.GivenARoute(route)) - .And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build())) - .And(x => x.GivenTheServiceProviderFactoryReturns()) - .When(x => x.WhenIGetTheLoadBalancer()) - .Then(x => x.ThenTheLoadBalancerIsReturned()) - .BDDfy(); + // Act + var result = _factory.Get(route, config); + + // Assert + result.Data.ShouldBeOfType(); } [Fact] - public void should_return_matching_load_balancer() + public void Should_return_matching_load_balancer() { + // Arrange var route = new DownstreamRouteBuilder() - .WithLoadBalancerOptions(new LoadBalancerOptions("FakeLoadBalancerTwo", string.Empty, 0)) - .WithUpstreamHttpMethod(new List { "Get" }) + .WithLoadBalancerOptions(new LoadBalancerOptions(nameof(FakeLoadBalancerTwo), string.Empty, 0)) + .WithUpstreamHttpMethod(new() { HttpMethods.Get }) .Build(); + var config = new ServiceProviderConfigurationBuilder().Build(); + GivenTheServiceProviderFactoryReturns(); + + // Act + var result = _factory.Get(route, config); - this.Given(x => x.GivenARoute(route)) - .And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build())) - .And(x => x.GivenTheServiceProviderFactoryReturns()) - .When(x => x.WhenIGetTheLoadBalancer()) - .Then(x => x.ThenTheLoadBalancerIsReturned()) - .BDDfy(); + // Assert + result.Data.ShouldBeOfType(); } [Fact] - public void should_return_error_response_if_cannot_find_load_balancer_creator() + public void Should_return_error_response_if_cannot_find_load_balancer_creator() { + // Arrange var route = new DownstreamRouteBuilder() .WithLoadBalancerOptions(new LoadBalancerOptions("DoesntExistLoadBalancer", string.Empty, 0)) - .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamHttpMethod(new() { HttpMethods.Get }) .Build(); + var config = new ServiceProviderConfigurationBuilder().Build(); + GivenTheServiceProviderFactoryReturns(); - this.Given(x => x.GivenARoute(route)) - .And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build())) - .And(x => x.GivenTheServiceProviderFactoryReturns()) - .When(x => x.WhenIGetTheLoadBalancer()) - .Then(x => x.ThenAnErrorResponseIsReturned()) - .And(x => x.ThenTheErrorMessageIsCorrect()) - .BDDfy(); + // Act + var result = _factory.Get(route, config); + + // Assert + result.IsError.ShouldBeTrue(); + result.Errors[0].Message.ShouldBe("Could not find load balancer creator for Type: DoesntExistLoadBalancer, please check your config specified the correct load balancer and that you have registered a class with the same name."); } [Fact] - public void should_return_error_response_if_creator_errors() + public void Should_return_error_response_if_creator_errors() { + // Arrange var route = new DownstreamRouteBuilder() - .WithLoadBalancerOptions(new LoadBalancerOptions("BrokenLoadBalancer", string.Empty, 0)) - .WithUpstreamHttpMethod(new List { "Get" }) + .WithLoadBalancerOptions(new LoadBalancerOptions(nameof(BrokenLoadBalancer), string.Empty, 0)) + .WithUpstreamHttpMethod(new() { HttpMethods.Get }) .Build(); + var config = new ServiceProviderConfigurationBuilder().Build(); + GivenTheServiceProviderFactoryReturns(); + + // Act + var result = _factory.Get(route, config); - this.Given(x => x.GivenARoute(route)) - .And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build())) - .And(x => x.GivenTheServiceProviderFactoryReturns()) - .When(x => x.WhenIGetTheLoadBalancer()) - .Then(x => x.ThenAnErrorResponseIsReturned()) - .BDDfy(); + // Assert + result.IsError.ShouldBeTrue(); } [Fact] - public void should_call_service_provider() + public void Should_call_service_provider() { + // Arrange var route = new DownstreamRouteBuilder() - .WithLoadBalancerOptions(new LoadBalancerOptions("FakeLoadBalancerOne", string.Empty, 0)) - .WithUpstreamHttpMethod(new List { "Get" }) + .WithLoadBalancerOptions(new LoadBalancerOptions(nameof(FakeLoadBalancerOne), string.Empty, 0)) + .WithUpstreamHttpMethod(new() { HttpMethods.Get }) .Build(); + var config = new ServiceProviderConfigurationBuilder().Build(); + GivenTheServiceProviderFactoryReturns(); - this.Given(x => x.GivenARoute(route)) - .And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build())) - .And(x => x.GivenTheServiceProviderFactoryReturns()) - .When(x => x.WhenIGetTheLoadBalancer()) - .Then(x => x.ThenTheServiceProviderIsCalledCorrectly()) - .BDDfy(); + // Act + var result = _factory.Get(route, config); + + // Assert + ThenTheServiceProviderIsCalledCorrectly(); } [Fact] - public void should_return_error_response_when_call_to_service_provider_fails() + public void Should_return_error_response_when_call_to_service_provider_fails() { + // Arrange var route = new DownstreamRouteBuilder() - .WithLoadBalancerOptions(new LoadBalancerOptions("FakeLoadBalancerOne", string.Empty, 0)) - .WithUpstreamHttpMethod(new List { "Get" }) + .WithLoadBalancerOptions(new LoadBalancerOptions(nameof(FakeLoadBalancerOne), string.Empty, 0)) + .WithUpstreamHttpMethod(new() { HttpMethods.Get }) .Build(); + var config = new ServiceProviderConfigurationBuilder().Build(); + GivenTheServiceProviderFactoryFails(); - this.Given(x => x.GivenARoute(route)) - .And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build())) - .And(x => x.GivenTheServiceProviderFactoryFails()) - .When(x => x.WhenIGetTheLoadBalancer()) - .Then(x => x.ThenAnErrorResponseIsReturned()) - .BDDfy(); - } + // Act + var result = _factory.Get(route, config); - private void GivenAServiceProviderConfig(ServiceProviderConfiguration serviceProviderConfig) - { - _serviceProviderConfig = serviceProviderConfig; + // Assert + result.IsError.ShouldBeTrue(); } private void GivenTheServiceProviderFactoryReturns() @@ -155,65 +159,20 @@ private void ThenTheServiceProviderIsCalledCorrectly() .Verify(x => x.Get(It.IsAny(), It.IsAny()), Times.Once); } - private void GivenARoute(DownstreamRoute route) - { - _route = route; - } - - private void WhenIGetTheLoadBalancer() - { - _result = _factory.Get(_route, _serviceProviderConfig); - } - - private void ThenTheLoadBalancerIsReturned() - { - _result.Data.ShouldBeOfType(); - } - - private void ThenAnErrorResponseIsReturned() - { - _result.IsError.ShouldBeTrue(); - } - - private void ThenTheErrorMessageIsCorrect() - { - _result.Errors[0].Message.ShouldBe("Could not find load balancer creator for Type: DoesntExistLoadBalancer, please check your config specified the correct load balancer and that you have registered a class with the same name."); - } - private class FakeLoadBalancerCreator : ILoadBalancerCreator where T : ILoadBalancer, new() { - public FakeLoadBalancerCreator() - { - Type = typeof(T).Name; - } - - public FakeLoadBalancerCreator(string type) - { - Type = type; - } - - public Response Create(DownstreamRoute route, IServiceDiscoveryProvider serviceProvider) - { - return new OkResponse(new T()); - } - + public FakeLoadBalancerCreator() => Type = typeof(T).Name; + public FakeLoadBalancerCreator(string type) => Type = type; + public Response Create(DownstreamRoute route, IServiceDiscoveryProvider serviceProvider) => new OkResponse(new T()); public string Type { get; } } private class BrokenLoadBalancerCreator : ILoadBalancerCreator where T : ILoadBalancer, new() { - public BrokenLoadBalancerCreator() - { - Type = typeof(T).Name; - } - - public Response Create(DownstreamRoute route, IServiceDiscoveryProvider serviceProvider) - { - return new ErrorResponse(new ErrorInvokingLoadBalancerCreator(new Exception())); - } - + public BrokenLoadBalancerCreator() => Type = typeof(T).Name; + public Response Create(DownstreamRoute route, IServiceDiscoveryProvider serviceProvider) => new ErrorResponse(new ErrorInvokingLoadBalancerCreator(new Exception())); public string Type { get; } } diff --git a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerHouseTests.cs b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerHouseTests.cs index 4ba9ca74a..fcb397948 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerHouseTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerHouseTests.cs @@ -9,142 +9,119 @@ namespace Ocelot.UnitTests.LoadBalancer; public class LoadBalancerHouseTests : UnitTest { - private DownstreamRoute _route; - private ILoadBalancer _loadBalancer; - private readonly LoadBalancerHouse _loadBalancerHouse; - private Response _getResult; + private readonly LoadBalancerHouse _house; private readonly Mock _factory; private readonly ServiceProviderConfiguration _serviceProviderConfig; public LoadBalancerHouseTests() { _factory = new Mock(); - _loadBalancerHouse = new LoadBalancerHouse(_factory.Object); + _house = new LoadBalancerHouse(_factory.Object); _serviceProviderConfig = new ServiceProviderConfiguration("myType", "myScheme", "myHost", 123, string.Empty, "configKey", 0); } [Fact] - public void should_store_load_balancer_on_first_request() + public void Should_store_load_balancer_on_first_request() { + // Arrange var route = new DownstreamRouteBuilder() .WithLoadBalancerKey("test") .Build(); + var loadBalancer = new FakeLoadBalancer(); + _factory.Setup(x => x.Get(route, _serviceProviderConfig)).Returns(new OkResponse(loadBalancer)); - this.Given(x => x.GivenThereIsALoadBalancer(route, new FakeLoadBalancer())) - .Then(x => x.ThenItIsAdded()) - .BDDfy(); + // Act + var result = _house.Get(route, _serviceProviderConfig); + + // Assert: Then It Is Added + result.IsError.ShouldBe(false); + result.ShouldBeOfType>(); + result.Data.ShouldBe(loadBalancer); + _factory.Verify(x => x.Get(route, _serviceProviderConfig), Times.Once); } [Fact] - public void should_not_store_load_balancer_on_second_request() + public void Should_not_store_load_balancer_on_second_request() { + // Arrange var route = new DownstreamRouteBuilder() - .WithLoadBalancerOptions(new LoadBalancerOptions("FakeLoadBalancer", string.Empty, 0)) + .WithLoadBalancerOptions(new LoadBalancerOptions(nameof(FakeLoadBalancer), string.Empty, 0)) .WithLoadBalancerKey("test") .Build(); + var loadBalancer = new FakeLoadBalancer(); + _factory.Setup(x => x.Get(route, _serviceProviderConfig)).Returns(new OkResponse(loadBalancer)); + + // Act + var result = _house.Get(route, _serviceProviderConfig); - this.Given(x => x.GivenThereIsALoadBalancer(route, new FakeLoadBalancer())) - .When(x => x.WhenWeGetTheLoadBalancer(route)) - .Then(x => x.ThenItIsReturned()) - .BDDfy(); + // Assert + result.Data.ShouldBe(loadBalancer); + _factory.Verify(x => x.Get(route, _serviceProviderConfig), Times.Once); } [Fact] - public void should_store_load_balancers_by_key() + public void Should_store_load_balancers_by_key() { + // Arrange var route = new DownstreamRouteBuilder() - .WithLoadBalancerOptions(new LoadBalancerOptions("FakeLoadBalancer", string.Empty, 0)) + .WithLoadBalancerOptions(new LoadBalancerOptions(nameof(FakeLoadBalancer), string.Empty, 0)) .WithLoadBalancerKey("test") .Build(); - - var routeTwo = new DownstreamRouteBuilder() - .WithLoadBalancerOptions(new LoadBalancerOptions("FakeRoundRobinLoadBalancer", string.Empty, 0)) + var route2 = new DownstreamRouteBuilder() + .WithLoadBalancerOptions(new LoadBalancerOptions(nameof(FakeRoundRobinLoadBalancer), string.Empty, 0)) .WithLoadBalancerKey("testtwo") .Build(); - - this.Given(x => x.GivenThereIsALoadBalancer(route, new FakeLoadBalancer())) - .And(x => x.GivenThereIsALoadBalancer(routeTwo, new FakeRoundRobinLoadBalancer())) - .When(x => x.WhenWeGetTheLoadBalancer(route)) - .Then(x => x.ThenTheLoadBalancerIs()) - .When(x => x.WhenWeGetTheLoadBalancer(routeTwo)) - .Then(x => x.ThenTheLoadBalancerIs()) - .BDDfy(); + var loadBalancer = new FakeLoadBalancer(); + var loadBalancer2 = new FakeRoundRobinLoadBalancer(); + _factory.Setup(x => x.Get(route, _serviceProviderConfig)).Returns(new OkResponse(loadBalancer)); + _factory.Setup(x => x.Get(route2, _serviceProviderConfig)).Returns(new OkResponse(loadBalancer2)); + + // Act, Assert + var result = _house.Get(route, _serviceProviderConfig); + result.Data.ShouldBeOfType(); + + // Act, Assert + result = _house.Get(route2, _serviceProviderConfig); + result.Data.ShouldBeOfType(); } [Fact] - public void should_return_error_if_exception() + public void Should_return_error_if_exception() { + // Arrange var route = new DownstreamRouteBuilder().Build(); - this.When(x => x.WhenWeGetTheLoadBalancer(route)) - .Then(x => x.ThenAnErrorIsReturned()) - .BDDfy(); + // Act + var result = _house.Get(route, _serviceProviderConfig); + + // Assert + result.IsError.ShouldBeTrue(); + result.Errors[0].ShouldBeOfType(); } [Fact] - public void should_get_new_load_balancer_if_route_load_balancer_has_changed() + public void Should_get_new_load_balancer_if_route_load_balancer_has_changed() { + // Arrange var route = new DownstreamRouteBuilder() - .WithLoadBalancerOptions(new LoadBalancerOptions("FakeLoadBalancer", string.Empty, 0)) + .WithLoadBalancerOptions(new LoadBalancerOptions(nameof(FakeLoadBalancer), string.Empty, 0)) .WithLoadBalancerKey("test") .Build(); - - var routeTwo = new DownstreamRouteBuilder() - .WithLoadBalancerOptions(new LoadBalancerOptions("LeastConnection", string.Empty, 0)) + var route2 = new DownstreamRouteBuilder() + .WithLoadBalancerOptions(new LoadBalancerOptions(nameof(LeastConnection), string.Empty, 0)) .WithLoadBalancerKey("test") .Build(); + var loadBalancer = new FakeLoadBalancer(); + _factory.Setup(x => x.Get(route, _serviceProviderConfig)).Returns(new OkResponse(loadBalancer)); - this.Given(x => x.GivenThereIsALoadBalancer(route, new FakeLoadBalancer())) - .When(x => x.WhenWeGetTheLoadBalancer(route)) - .Then(x => x.ThenTheLoadBalancerIs()) - .When(x => x.WhenIGetTheRouteWithTheSameKeyButDifferentLoadBalancer(routeTwo)) - .Then(x => x.ThenTheLoadBalancerIs()) - .BDDfy(); - } - - private void WhenIGetTheRouteWithTheSameKeyButDifferentLoadBalancer(DownstreamRoute route) - { - _route = route; - _factory.Setup(x => x.Get(_route, _serviceProviderConfig)).Returns(new OkResponse(new LeastConnection(null, null))); - _getResult = _loadBalancerHouse.Get(_route, _serviceProviderConfig); - } - - private void ThenAnErrorIsReturned() - { - _getResult.IsError.ShouldBeTrue(); - _getResult.Errors[0].ShouldBeOfType(); - } - - private void ThenTheLoadBalancerIs() - { - _getResult.Data.ShouldBeOfType(); - } + // Act, Assert + var result = _house.Get(route, _serviceProviderConfig); + result.Data.ShouldBeOfType(); + _factory.Setup(x => x.Get(route2, _serviceProviderConfig)).Returns(new OkResponse(new LeastConnection(null, null))); - private void ThenItIsAdded() - { - _getResult.IsError.ShouldBe(false); - _getResult.ShouldBeOfType>(); - _getResult.Data.ShouldBe(_loadBalancer); - _factory.Verify(x => x.Get(_route, _serviceProviderConfig), Times.Once); - } - - private void GivenThereIsALoadBalancer(DownstreamRoute route, ILoadBalancer loadBalancer) - { - _route = route; - _loadBalancer = loadBalancer; - _factory.Setup(x => x.Get(_route, _serviceProviderConfig)).Returns(new OkResponse(loadBalancer)); - _getResult = _loadBalancerHouse.Get(route, _serviceProviderConfig); - } - - private void WhenWeGetTheLoadBalancer(DownstreamRoute route) - { - _getResult = _loadBalancerHouse.Get(route, _serviceProviderConfig); - } - - private void ThenItIsReturned() - { - _getResult.Data.ShouldBe(_loadBalancer); - _factory.Verify(x => x.Get(_route, _serviceProviderConfig), Times.Once); + // Act, Assert + result = _house.Get(route2, _serviceProviderConfig); + result.Data.ShouldBeOfType(); } private class FakeLoadBalancer : ILoadBalancer diff --git a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs index 64d46b179..a9bc8b376 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs @@ -1,8 +1,8 @@ using Microsoft.AspNetCore.Http; using Ocelot.Configuration; using Ocelot.Configuration.Builder; +using Ocelot.DownstreamRouteFinder.UrlMatcher; using Ocelot.Errors; -using Ocelot.Infrastructure.RequestData; using Ocelot.LoadBalancer.LoadBalancers; using Ocelot.LoadBalancer.Middleware; using Ocelot.Logging; @@ -21,19 +21,15 @@ public class LoadBalancerMiddlewareTests : UnitTest private ErrorResponse _getLoadBalancerHouseError; private ErrorResponse _getHostAndPortError; private readonly HttpRequestMessage _downstreamRequest; - private ServiceProviderConfiguration _config; private readonly Mock _loggerFactory; private readonly Mock _logger; private LoadBalancingMiddleware _middleware; private readonly RequestDelegate _next; - private readonly HttpContext _httpContext; - private Mock _repo; + private readonly DefaultHttpContext _httpContext; public LoadBalancerMiddlewareTests() { - _repo = new Mock(); _httpContext = new DefaultHttpContext(); - _loadBalancerHouse = new Mock(); _loadBalancer = new Mock(); _loadBalancerHouse = new Mock(); _downstreamRequest = new HttpRequestMessage(HttpMethod.Get, "http://test.com/"); @@ -41,96 +37,123 @@ public LoadBalancerMiddlewareTests() _logger = new Mock(); _loggerFactory.Setup(x => x.CreateLogger()).Returns(_logger.Object); _next = context => Task.CompletedTask; + + _loadBalancerHouse.Setup(x => x.Get(It.IsAny(), It.IsAny())) + .Returns(new OkResponse(_loadBalancer.Object)); } [Fact] - public void should_call_scoped_data_repository_correctly() + public async Task Should_call_scoped_data_repository_correctly() { + // Arrange var downstreamRoute = new DownstreamRouteBuilder() - .WithUpstreamHttpMethod(new List { "Get" }) - .Build(); - + .WithUpstreamHttpMethod(new() { HttpMethods.Get }) + .Build(); var serviceProviderConfig = new ServiceProviderConfigurationBuilder() .Build(); + GivenTheDownStreamUrlIs("http://my.url/abc?q=123"); + GivenTheConfigurationIs(serviceProviderConfig); + GivenTheDownStreamRouteIs(downstreamRoute, new List()); + + // Arrange: Given The Load Balancer Returns + _hostAndPort = new ServiceHostAndPort("127.0.0.1", 80); + _loadBalancer.Setup(x => x.LeaseAsync(It.IsAny())) + .ReturnsAsync(new OkResponse(_hostAndPort)); + + // Act + _middleware = new LoadBalancingMiddleware(_next, _loggerFactory.Object, _loadBalancerHouse.Object); + await _middleware.Invoke(_httpContext); - this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123")) - .And(x => GivenTheConfigurationIs(serviceProviderConfig)) - .And(x => x.GivenTheDownStreamRouteIs(downstreamRoute, new List())) - .And(x => x.GivenTheLoadBalancerHouseReturns()) - .And(x => x.GivenTheLoadBalancerReturns()) - .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.ThenTheDownstreamUrlIsReplacedWith("http://127.0.0.1:80/abc?q=123")) - .BDDfy(); + // Assert + _httpContext.Items.DownstreamRequest().ToHttpRequestMessage().RequestUri.OriginalString.ShouldBe("http://127.0.0.1:80/abc?q=123"); } [Fact] - public void should_set_pipeline_error_if_cannot_get_load_balancer() + public async Task Should_set_pipeline_error_if_cannot_get_load_balancer() { + // Arrange var downstreamRoute = new DownstreamRouteBuilder() - .WithUpstreamHttpMethod(new List { "Get" }) - .Build(); - + .WithUpstreamHttpMethod(new() { HttpMethods.Get }) + .Build(); var serviceProviderConfig = new ServiceProviderConfigurationBuilder() .Build(); + GivenTheDownStreamUrlIs("http://my.url/abc?q=123"); + GivenTheConfigurationIs(serviceProviderConfig); + GivenTheDownStreamRouteIs(downstreamRoute, new List()); - this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123")) - .And(x => GivenTheConfigurationIs(serviceProviderConfig)) - .And(x => x.GivenTheDownStreamRouteIs(downstreamRoute, new List())) - .And(x => x.GivenTheLoadBalancerHouseReturnsAnError()) - .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.ThenAnErrorStatingLoadBalancerCouldNotBeFoundIsSetOnPipeline()) - .BDDfy(); + // Arrange: Given The Load Balancer House Returns An Error + _getLoadBalancerHouseError = new ErrorResponse(new List + { + new UnableToFindLoadBalancerError("unabe to find load balancer for bah"), + }); + _loadBalancerHouse.Setup(x => x.Get(It.IsAny(), It.IsAny())) + .Returns(_getLoadBalancerHouseError); + + // Act + _middleware = new LoadBalancingMiddleware(_next, _loggerFactory.Object, _loadBalancerHouse.Object); + await _middleware.Invoke(_httpContext); + + // Assert + _httpContext.Items.Errors().Count.ShouldBeGreaterThan(0); + _httpContext.Items.Errors().ShouldBe(_getLoadBalancerHouseError.Errors); } [Fact] - public void should_set_pipeline_error_if_cannot_get_least() + public async Task Should_set_pipeline_error_if_cannot_get_least() { + // Arrange var downstreamRoute = new DownstreamRouteBuilder() - .WithUpstreamHttpMethod(new List { "Get" }) - .Build(); - + .WithUpstreamHttpMethod(new() { HttpMethods.Get }) + .Build(); var serviceProviderConfig = new ServiceProviderConfigurationBuilder() .Build(); + GivenTheDownStreamUrlIs("http://my.url/abc?q=123"); + GivenTheConfigurationIs(serviceProviderConfig); + GivenTheDownStreamRouteIs(downstreamRoute, new List()); + + // Arrange: Given The Load Balancer Returns An Error + _getHostAndPortError = new ErrorResponse(new List { new ServicesAreNullError("services were null for bah") }); + _loadBalancer.Setup(x => x.LeaseAsync(It.IsAny())) + .ReturnsAsync(_getHostAndPortError); - this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123")) - .And(x => GivenTheConfigurationIs(serviceProviderConfig)) - .And(x => x.GivenTheDownStreamRouteIs(downstreamRoute, new List())) - .And(x => x.GivenTheLoadBalancerHouseReturns()) - .And(x => x.GivenTheLoadBalancerReturnsAnError()) - .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.ThenAnErrorStatingHostAndPortCouldNotBeFoundIsSetOnPipeline()) - .BDDfy(); + // Act + _middleware = new LoadBalancingMiddleware(_next, _loggerFactory.Object, _loadBalancerHouse.Object); + await _middleware.Invoke(_httpContext); + + // Assert + _httpContext.Items.Errors().Count.ShouldBeGreaterThan(0); + _httpContext.Items.Errors().ShouldBe(_getHostAndPortError.Errors); } [Fact] - public void should_set_scheme() + public async Task Should_set_scheme() { + // Arrange var downstreamRoute = new DownstreamRouteBuilder() - .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamHttpMethod(new() { HttpMethods.Get }) .Build(); - var serviceProviderConfig = new ServiceProviderConfigurationBuilder() .Build(); + GivenTheDownStreamUrlIs("http://my.url/abc?q=123"); + GivenTheConfigurationIs(serviceProviderConfig); + GivenTheDownStreamRouteIs(downstreamRoute, new List()); - this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123")) - .And(x => GivenTheConfigurationIs(serviceProviderConfig)) - .And(x => x.GivenTheDownStreamRouteIs(downstreamRoute, new List())) - .And(x => x.GivenTheLoadBalancerHouseReturns()) - .And(x => x.GivenTheLoadBalancerReturnsOk()) - .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.ThenAnHostAndPortIsSetOnPipeline()) - .BDDfy(); - } + // Arrange: Given The Load Balancer Returns Ok + _loadBalancer.Setup(x => x.LeaseAsync(It.IsAny())) + .ReturnsAsync(new OkResponse(new ServiceHostAndPort("abc", 123, "https"))); - private async Task WhenICallTheMiddleware() - { + // Act _middleware = new LoadBalancingMiddleware(_next, _loggerFactory.Object, _loadBalancerHouse.Object); await _middleware.Invoke(_httpContext); + + // Assert + _httpContext.Items.DownstreamRequest().Host.ShouldBeEquivalentTo("abc"); + _httpContext.Items.DownstreamRequest().Port.ShouldBeEquivalentTo(123); + _httpContext.Items.DownstreamRequest().Scheme.ShouldBeEquivalentTo("https"); } private void GivenTheConfigurationIs(ServiceProviderConfiguration config) { - _config = config; var configuration = new InternalConfiguration(null, null, config, null, null, null, null, null, null, null); _httpContext.Items.SetIInternalConfiguration(configuration); } @@ -141,81 +164,9 @@ private void GivenTheDownStreamUrlIs(string downstreamUrl) _httpContext.Items.UpsertDownstreamRequest(new DownstreamRequest(_downstreamRequest)); } - private void GivenTheLoadBalancerReturnsAnError() - { - _getHostAndPortError = new ErrorResponse(new List { new ServicesAreNullError("services were null for bah") }); - _loadBalancer - .Setup(x => x.LeaseAsync(It.IsAny())) - .ReturnsAsync(_getHostAndPortError); - } - - private void GivenTheLoadBalancerReturnsOk() - { - _loadBalancer - .Setup(x => x.LeaseAsync(It.IsAny())) - .ReturnsAsync(new OkResponse(new ServiceHostAndPort("abc", 123, "https"))); - } - - private void GivenTheLoadBalancerReturns() - { - _hostAndPort = new ServiceHostAndPort("127.0.0.1", 80); - _loadBalancer - .Setup(x => x.LeaseAsync(It.IsAny())) - .ReturnsAsync(new OkResponse(_hostAndPort)); - } - - private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute, List placeholder) + private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute, List placeholder) { _httpContext.Items.UpsertTemplatePlaceholderNameAndValues(placeholder); _httpContext.Items.UpsertDownstreamRoute(downstreamRoute); } - - private void GivenTheLoadBalancerHouseReturns() - { - _loadBalancerHouse - .Setup(x => x.Get(It.IsAny(), It.IsAny())) - .Returns(new OkResponse(_loadBalancer.Object)); - } - - private void GivenTheLoadBalancerHouseReturnsAnError() - { - _getLoadBalancerHouseError = new ErrorResponse(new List - { - new UnableToFindLoadBalancerError("unabe to find load balancer for bah"), - }); - - _loadBalancerHouse - .Setup(x => x.Get(It.IsAny(), It.IsAny())) - .Returns(_getLoadBalancerHouseError); - } - - private void ThenAnErrorStatingLoadBalancerCouldNotBeFoundIsSetOnPipeline() - { - _httpContext.Items.Errors().Count.ShouldBeGreaterThan(0); - _httpContext.Items.Errors().ShouldBe(_getLoadBalancerHouseError.Errors); - } - - private void ThenAnErrorSayingReleaseFailedIsSetOnThePipeline() - { - _httpContext.Items.Errors().Count.ShouldBeGreaterThan(0); - _httpContext.Items.Errors().ShouldBe(It.IsAny>()); - } - - private void ThenAnErrorStatingHostAndPortCouldNotBeFoundIsSetOnPipeline() - { - _httpContext.Items.Errors().Count.ShouldBeGreaterThan(0); - _httpContext.Items.Errors().ShouldBe(_getHostAndPortError.Errors); - } - - private void ThenAnHostAndPortIsSetOnPipeline() - { - _httpContext.Items.DownstreamRequest().Host.ShouldBeEquivalentTo("abc"); - _httpContext.Items.DownstreamRequest().Port.ShouldBeEquivalentTo(123); - _httpContext.Items.DownstreamRequest().Scheme.ShouldBeEquivalentTo("https"); - } - - private void ThenTheDownstreamUrlIsReplacedWith(string expectedUri) - { - _httpContext.Items.DownstreamRequest().ToHttpRequestMessage().RequestUri.OriginalString.ShouldBe(expectedUri); - } } diff --git a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerOptionsTests.cs b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerOptionsTests.cs index 806c1c3b1..ba131cbac 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerOptionsTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerOptionsTests.cs @@ -6,9 +6,12 @@ namespace Ocelot.UnitTests.LoadBalancer; public class LoadBalancerOptionsTests { [Fact] - public void should_default_to_no_load_balancer() + public void Should_default_to_no_load_balancer() { + // Arrange, Act var options = new LoadBalancerOptionsBuilder().Build(); + + // Assert options.Type.ShouldBe(nameof(NoLoadBalancer)); } } diff --git a/test/Ocelot.UnitTests/LoadBalancer/NoLoadBalancerCreatorTests.cs b/test/Ocelot.UnitTests/LoadBalancer/NoLoadBalancerCreatorTests.cs index 6e626644b..bd0a6c10d 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/NoLoadBalancerCreatorTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/NoLoadBalancerCreatorTests.cs @@ -1,7 +1,5 @@ -using Ocelot.Configuration; -using Ocelot.Configuration.Builder; +using Ocelot.Configuration.Builder; using Ocelot.LoadBalancer.LoadBalancers; -using Ocelot.Responses; using Ocelot.ServiceDiscovery.Providers; namespace Ocelot.UnitTests.LoadBalancer; @@ -10,9 +8,6 @@ public class NoLoadBalancerCreatorTests : UnitTest { private readonly NoLoadBalancerCreator _creator; private readonly Mock _serviceProvider; - private DownstreamRoute _route; - private Response _loadBalancer; - private string _typeName; public NoLoadBalancerCreatorTests() { @@ -21,48 +16,22 @@ public NoLoadBalancerCreatorTests() } [Fact] - public void should_return_instance_of_expected_load_balancer_type() + public void Should_return_instance_of_expected_load_balancer_type() { - var route = new DownstreamRouteBuilder() - .Build(); + // Arrange + var route = new DownstreamRouteBuilder().Build(); - this.Given(x => x.GivenARoute(route)) - .When(x => x.WhenIGetTheLoadBalancer()) - .Then(x => x.ThenTheLoadBalancerIsReturned()) - .BDDfy(); - } - - [Fact] - public void should_return_expected_name() - { - this.When(x => x.WhenIGetTheLoadBalancerTypeName()) - .Then(x => x.ThenTheLoadBalancerTypeIs("NoLoadBalancer")) - .BDDfy(); - } - - private void GivenARoute(DownstreamRoute route) - { - _route = route; - } + // Act + var loadBalancer = _creator.Create(route, _serviceProvider.Object); - private void WhenIGetTheLoadBalancer() - { - _loadBalancer = _creator.Create(_route, _serviceProvider.Object); + // Assert + loadBalancer.Data.ShouldBeOfType(); } - private void WhenIGetTheLoadBalancerTypeName() - { - _typeName = _creator.Type; - } - - private void ThenTheLoadBalancerIsReturned() - where T : ILoadBalancer - { - _loadBalancer.Data.ShouldBeOfType(); - } - - private void ThenTheLoadBalancerTypeIs(string type) + [Fact] + public void Should_return_expected_name() { - _typeName.ShouldBe(type); + // Arrange, Act, Assert + _creator.Type.ShouldBe(nameof(NoLoadBalancer)); } } diff --git a/test/Ocelot.UnitTests/LoadBalancer/NoLoadBalancerTests.cs b/test/Ocelot.UnitTests/LoadBalancer/NoLoadBalancerTests.cs index 3e3279eb7..278f3f105 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/NoLoadBalancerTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/NoLoadBalancerTests.cs @@ -18,32 +18,37 @@ public NoLoadBalancerTests() } [Fact] - public void should_return_host_and_port() + public async Task Should_return_host_and_port() { + // Arrange var hostAndPort = new ServiceHostAndPort("127.0.0.1", 80); - var services = new List { new("product", hostAndPort, string.Empty, string.Empty, Array.Empty()), }; + _services.AddRange(services); + + // Act + _result = await _loadBalancer.LeaseAsync(new DefaultHttpContext()); - this.Given(x => x.GivenServices(services)) - .When(x => x.WhenIGetTheNextHostAndPort()) - .Then(x => x.ThenTheHostAndPortIs(hostAndPort)) - .BDDfy(); + // Assert + _result.Data.ShouldBe(hostAndPort); } [Fact] - public void should_return_error_if_no_services() + public async Task Should_return_error_if_no_services() { - this.When(x => x.WhenIGetTheNextHostAndPort()) - .Then(x => x.ThenThereIsAnError()) - .BDDfy(); + // Arrange, Act + _result = await _loadBalancer.LeaseAsync(new DefaultHttpContext()); + + // Assert + _result.IsError.ShouldBeTrue(); } [Fact] - public void should_return_error_if_no_services_then_when_services_available_return_host_and_port() + public async Task Should_return_error_if_no_services_then_when_services_available_return_host_and_port() { + // Arrange var hostAndPort = new ServiceHostAndPort("127.0.0.1", 80); var services = new List @@ -51,45 +56,26 @@ public void should_return_error_if_no_services_then_when_services_available_retu new("product", hostAndPort, string.Empty, string.Empty, Array.Empty()), }; - this.Given(_ => WhenIGetTheNextHostAndPort()) - .And(_ => ThenThereIsAnError()) - .And(_ => GivenServices(services)) - .When(_ => WhenIGetTheNextHostAndPort()) - .Then(_ => ThenTheHostAndPortIs(hostAndPort)) - .BDDfy(); - } + // Act, Assert + _result = await _loadBalancer.LeaseAsync(new DefaultHttpContext()); + _result.IsError.ShouldBeTrue(); + _services.AddRange(services); - [Fact] - public void should_return_error_if_null_services() - { - this.Given(x => x.GivenServicesAreNull()) - .When(x => x.WhenIGetTheNextHostAndPort()) - .Then(x => x.ThenThereIsAnError()) - .BDDfy(); + // Act, Assert + _result = await _loadBalancer.LeaseAsync(new DefaultHttpContext()); + _result.Data.ShouldBe(hostAndPort); } - private void GivenServicesAreNull() + [Fact] + public async Task Should_return_error_if_null_services() { + // Arrange _loadBalancer = new NoLoadBalancer(() => Task.FromResult((List)null)); - } - - private void ThenThereIsAnError() - { - _result.IsError.ShouldBeTrue(); - } - - private void GivenServices(List services) - { - _services.AddRange(services); - } - private async Task WhenIGetTheNextHostAndPort() - { + // Act _result = await _loadBalancer.LeaseAsync(new DefaultHttpContext()); - } - private void ThenTheHostAndPortIs(ServiceHostAndPort expected) - { - _result.Data.ShouldBe(expected); + // Assert + _result.IsError.ShouldBeTrue(); } } diff --git a/test/Ocelot.UnitTests/LoadBalancer/RoundRobinCreatorTests.cs b/test/Ocelot.UnitTests/LoadBalancer/RoundRobinCreatorTests.cs index e50b96aaf..f9bbad03f 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/RoundRobinCreatorTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/RoundRobinCreatorTests.cs @@ -1,5 +1,4 @@ -using Ocelot.Configuration; -using Ocelot.Configuration.Builder; +using Ocelot.Configuration.Builder; using Ocelot.LoadBalancer.LoadBalancers; using Ocelot.Responses; using Ocelot.ServiceDiscovery.Providers; @@ -10,9 +9,6 @@ public class RoundRobinCreatorTests : UnitTest { private readonly RoundRobinCreator _creator; private readonly Mock _serviceProvider; - private DownstreamRoute _route; - private Response _loadBalancer; - private string _typeName; public RoundRobinCreatorTests() { @@ -21,48 +17,22 @@ public RoundRobinCreatorTests() } [Fact] - public void should_return_instance_of_expected_load_balancer_type() + public void Should_return_instance_of_expected_load_balancer_type() { - var route = new DownstreamRouteBuilder() - .Build(); + // Arrange + var route = new DownstreamRouteBuilder().Build(); - this.Given(x => x.GivenARoute(route)) - .When(x => x.WhenIGetTheLoadBalancer()) - .Then(x => x.ThenTheLoadBalancerIsReturned()) - .BDDfy(); - } - - [Fact] - public void should_return_expected_name() - { - this.When(x => x.WhenIGetTheLoadBalancerTypeName()) - .Then(x => x.ThenTheLoadBalancerTypeIs("RoundRobin")) - .BDDfy(); - } - - private void GivenARoute(DownstreamRoute route) - { - _route = route; - } + // Act + var loadBalancer = _creator.Create(route, _serviceProvider.Object); - private void WhenIGetTheLoadBalancer() - { - _loadBalancer = _creator.Create(_route, _serviceProvider.Object); + // Assert + loadBalancer.Data.ShouldBeOfType(); } - private void WhenIGetTheLoadBalancerTypeName() - { - _typeName = _creator.Type; - } - - private void ThenTheLoadBalancerIsReturned() - where T : ILoadBalancer - { - _loadBalancer.Data.ShouldBeOfType(); - } - - private void ThenTheLoadBalancerTypeIs(string type) + [Fact] + public void Should_return_expected_name() { - _typeName.ShouldBe(type); + // Arrange, Act, Assert + _creator.Type.ShouldBe(nameof(RoundRobin)); } } diff --git a/test/Ocelot.UnitTests/LoadBalancer/RoundRobinTests.cs b/test/Ocelot.UnitTests/LoadBalancer/RoundRobinTests.cs index 80c6b767c..09c543ec7 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/RoundRobinTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/RoundRobinTests.cs @@ -9,23 +9,21 @@ namespace Ocelot.UnitTests.LoadBalancer; public class RoundRobinTests : UnitTest { - private readonly HttpContext _httpContext; - - public RoundRobinTests() - { - _httpContext = new DefaultHttpContext(); - } + private readonly DefaultHttpContext _httpContext = new(); [Fact] public async Task Lease_LoopThroughIndexRangeOnce_ShouldGetNextAddress() { + // Arrange var services = GivenServices(); var roundRobin = GivenLoadBalancer(services); - var response0 = await WhenIGetTheNextAddressAsync(roundRobin); - var response1 = await WhenIGetTheNextAddressAsync(roundRobin); - var response2 = await WhenIGetTheNextAddressAsync(roundRobin); + // Act + var response0 = await roundRobin.LeaseAsync(_httpContext); + var response1 = await roundRobin.LeaseAsync(_httpContext); + var response2 = await roundRobin.LeaseAsync(_httpContext); + // Assert response0.Data.ShouldNotBeNull().ShouldBe(services[0].HostAndPort); response1.Data.ShouldNotBeNull().ShouldBe(services[1].HostAndPort); response2.Data.ShouldNotBeNull().ShouldBe(services[2].HostAndPort); @@ -35,15 +33,18 @@ public async Task Lease_LoopThroughIndexRangeOnce_ShouldGetNextAddress() [Trait("Feat", "336")] public async Task Lease_LoopThroughIndexRangeIndefinitelyButOneSecond_ShouldGoBackToFirstAddressAfterFinishedLast() { + // Arrange var services = GivenServices(); var roundRobin = GivenLoadBalancer(services); var stopWatch = Stopwatch.StartNew(); while (stopWatch.ElapsedMilliseconds < 1000) { - var response0 = await WhenIGetTheNextAddressAsync(roundRobin); - var response1 = await WhenIGetTheNextAddressAsync(roundRobin); - var response2 = await WhenIGetTheNextAddressAsync(roundRobin); + // Act + var response0 = await roundRobin.LeaseAsync(_httpContext); + var response1 = await roundRobin.LeaseAsync(_httpContext); + var response2 = await roundRobin.LeaseAsync(_httpContext); + // Assert response0.Data.ShouldNotBeNull().ShouldBe(services[0].HostAndPort); response1.Data.ShouldNotBeNull().ShouldBe(services[1].HostAndPort); response2.Data.ShouldNotBeNull().ShouldBe(services[2].HostAndPort); @@ -54,10 +55,17 @@ public async Task Lease_LoopThroughIndexRangeIndefinitelyButOneSecond_ShouldGoBa [Trait("Bug", "2110")] public async Task Lease_SelectedServiceIsNull_ShouldReturnError() { + // Arrange var invalidServices = new List { null }; var roundRobin = GivenLoadBalancer(invalidServices); - var response = await WhenIGetTheNextAddressAsync(roundRobin); - ThenServicesAreNullErrorIsReturned(response); + + // Act + var response = await roundRobin.LeaseAsync(_httpContext); + + // Assert: Then ServicesAreNullError Is Returned + response.ShouldNotBeNull().Data.ShouldBeNull(); + response.IsError.ShouldBeTrue(); + response.Errors[0].ShouldBeOfType(); } //[InlineData(1, 10)] @@ -123,7 +131,7 @@ private Response[] WhenICallLeaseFromMultipleThreads(RoundRo private async Task GetParallelResponse(Response[] responses, RoundRobin roundRobin, int threadIndex) { - responses[threadIndex] = await WhenIGetTheNextAddressAsync(roundRobin); + responses[threadIndex] = await roundRobin.LeaseAsync(_httpContext); } private static List GivenServices(int total = 3, [CallerMemberName] string serviceName = null) @@ -148,14 +156,4 @@ private static RoundRobin GivenLoadBalancer(List services, bool immedia }, serviceName); } - - private Task> WhenIGetTheNextAddressAsync(RoundRobin roundRobin) - => roundRobin.LeaseAsync(_httpContext); - - private static void ThenServicesAreNullErrorIsReturned(Response response) - { - response.ShouldNotBeNull().Data.ShouldBeNull(); - response.IsError.ShouldBeTrue(); - response.Errors[0].ShouldBeOfType(); - } } diff --git a/test/Ocelot.UnitTests/Logging/OcelotDiagnosticListenerTests.cs b/test/Ocelot.UnitTests/Logging/OcelotDiagnosticListenerTests.cs index edb4e26ba..938a6eb38 100644 --- a/test/Ocelot.UnitTests/Logging/OcelotDiagnosticListenerTests.cs +++ b/test/Ocelot.UnitTests/Logging/OcelotDiagnosticListenerTests.cs @@ -11,9 +11,7 @@ public class OcelotDiagnosticListenerTests : UnitTest private readonly Mock _logger; private readonly IServiceCollection _serviceCollection; private readonly IServiceProvider _serviceProvider; - private string _name; - private Exception _exception; - private readonly HttpContext _httpContext; + private readonly DefaultHttpContext _httpContext; public OcelotDiagnosticListenerTests() { @@ -27,61 +25,47 @@ public OcelotDiagnosticListenerTests() } [Fact] - public void should_trace_middleware_started() + public void Should_trace_middleware_started() { - this.Given(_ => GivenAMiddlewareName()) - .When(_ => WhenMiddlewareStartedCalled()) - .Then(_ => ThenTheLogIs($"MiddlewareStarting: {_name}; {_httpContext.Request.Path}")) - .BDDfy(); - } + // Arrange + const string name = "name"; - [Fact] - public void should_trace_middleware_finished() - { - this.Given(_ => GivenAMiddlewareName()) - .When(_ => WhenMiddlewareFinishedCalled()) - .Then(_ => ThenTheLogIs($"MiddlewareFinished: {_name}; {_httpContext.Response.StatusCode}")) - .BDDfy(); + // Act + _listener.OnMiddlewareStarting(_httpContext, name); + + // Assert + ThenTheLogIs($"MiddlewareStarting: {name}; {_httpContext.Request.Path}"); } [Fact] - public void should_trace_middleware_exception() + public void Should_trace_middleware_finished() { - this.Given(_ => GivenAMiddlewareName()) - .And(_ => GivenAException(new Exception("oh no"))) - .When(_ => WhenMiddlewareExceptionCalled()) - .Then(_ => ThenTheLogIs($"MiddlewareException: {_name}; {_exception.Message};")) - .BDDfy(); - } + // Arrange + const string name = "name"; - private void GivenAException(Exception exception) - { - _exception = exception; - } + // Act + _listener.OnMiddlewareFinished(_httpContext, name); - private void WhenMiddlewareStartedCalled() - { - _listener.OnMiddlewareStarting(_httpContext, _name); + // Assert + ThenTheLogIs($"MiddlewareFinished: {name}; {_httpContext.Response.StatusCode}"); } - private void WhenMiddlewareFinishedCalled() + [Fact] + public void Should_trace_middleware_exception() { - _listener.OnMiddlewareFinished(_httpContext, _name); - } + // Arrange + const string name = "name"; + var exception = new Exception("oh no"); - private void WhenMiddlewareExceptionCalled() - { - _listener.OnMiddlewareException(_exception, _name); - } + // Act + _listener.OnMiddlewareException(exception, name); - private void GivenAMiddlewareName() - { - _name = "name"; + // Assert + ThenTheLogIs($"MiddlewareException: {name}; {exception.Message};"); } private void ThenTheLogIs(string expected) { - _logger.Verify( - x => x.LogTrace(It.Is>(c => c.Invoke() == expected))); + _logger.Verify(x => x.LogTrace(It.Is>(c => c.Invoke() == expected))); } } diff --git a/test/Ocelot.UnitTests/Logging/OcelotLoggerTests.cs b/test/Ocelot.UnitTests/Logging/OcelotLoggerTests.cs index 0895e276e..d93e43cae 100644 --- a/test/Ocelot.UnitTests/Logging/OcelotLoggerTests.cs +++ b/test/Ocelot.UnitTests/Logging/OcelotLoggerTests.cs @@ -8,15 +8,13 @@ public class OcelotLoggerTests { private readonly Mock> _coreLogger; private readonly OcelotLogger _logger; - private readonly string _b; - private readonly string _a; - private readonly Exception _ex; + + private static readonly string _a = "Tom"; + private static readonly string _b = "Laura"; + private static readonly Exception _ex = new("oh no"); public OcelotLoggerTests() { - _a = "tom"; - _b = "laura"; - _ex = new Exception("oh no"); _coreLogger = new Mock>(); _coreLogger.Setup(x => x.IsEnabled(It.IsAny())).Returns(true); var repo = new Mock(); @@ -26,50 +24,60 @@ public OcelotLoggerTests() [Fact] public void Should_log_trace() { + // Arrange, Act _logger.LogTrace(() => $"a message from {_a} to {_b}"); + // Assert ThenLevelIsLogged( - "requestId: No RequestId, previousRequestId: No PreviousRequestId, message: 'a message from tom to laura'", + "requestId: No RequestId, previousRequestId: No PreviousRequestId, message: 'a message from Tom to Laura'", LogLevel.Trace); } [Fact] public void Should_log_info() { + // Arrange, Act _logger.LogInformation(() => $"a message from {_a} to {_b}"); + // Assert ThenLevelIsLogged( - "requestId: No RequestId, previousRequestId: No PreviousRequestId, message: 'a message from tom to laura'", + "requestId: No RequestId, previousRequestId: No PreviousRequestId, message: 'a message from Tom to Laura'", LogLevel.Information); } [Fact] public void Should_log_warning() { + // Arrange, Act _logger.LogWarning(() => $"a message from {_a} to {_b}"); + // Assert ThenLevelIsLogged( - "requestId: No RequestId, previousRequestId: No PreviousRequestId, message: 'a message from tom to laura'", + "requestId: No RequestId, previousRequestId: No PreviousRequestId, message: 'a message from Tom to Laura'", LogLevel.Warning); } [Fact] public void Should_log_error() { + // Arrange, Act _logger.LogError(() => $"a message from {_a} to {_b}", _ex); + // Assert ThenLevelIsLogged( - "requestId: No RequestId, previousRequestId: No PreviousRequestId, message: 'a message from tom to laura'", + "requestId: No RequestId, previousRequestId: No PreviousRequestId, message: 'a message from Tom to Laura'", LogLevel.Error, _ex); } [Fact] public void Should_log_critical() { + // Arrange, Act _logger.LogCritical(() => $"a message from {_a} to {_b}", _ex); + // Assert ThenLevelIsLogged( - "requestId: No RequestId, previousRequestId: No PreviousRequestId, message: 'a message from tom to laura'", + "requestId: No RequestId, previousRequestId: No PreviousRequestId, message: 'a message from Tom to Laura'", LogLevel.Critical, _ex); } @@ -112,7 +120,7 @@ public void If_minimum_log_level_not_set_then_log_is_called_for_information_and_ var currentLogger = new OcelotLogger(mockedILogger.Object, repo.Object); currentLogger.LogDebug(() => $"a message from {_a} to {_b}"); - var expected = "requestId: No RequestId, previousRequestId: No PreviousRequestId, message: 'a message from tom to laura'"; + var expected = "requestId: No RequestId, previousRequestId: No PreviousRequestId, message: 'a message from Tom to Laura'"; ThenLevelIsNotLogged(mockedILogger, expected, LogLevel.Debug); @@ -149,7 +157,7 @@ public void If_minimum_log_level_set_to_none_then_log_method_is_never_called() var currentLogger = new OcelotLogger(mockedILogger.Object, repo.Object); currentLogger.LogDebug(() => $"a message from {_a} to {_b}"); - var expected = "requestId: No RequestId, previousRequestId: No PreviousRequestId, message: 'a message from tom to laura'"; + var expected = "requestId: No RequestId, previousRequestId: No PreviousRequestId, message: 'a message from Tom to Laura'"; ThenLevelIsNotLogged(mockedILogger, expected, LogLevel.Debug); @@ -186,7 +194,7 @@ public void If_minimum_log_level_set_to_trace_then_log_is_called_for_trace_and_a var currentLogger = new OcelotLogger(mockedILogger.Object, repo.Object); currentLogger.LogDebug(() => $"a message from {_a} to {_b}"); - var expected = "requestId: No RequestId, previousRequestId: No PreviousRequestId, message: 'a message from tom to laura'"; + var expected = "requestId: No RequestId, previousRequestId: No PreviousRequestId, message: 'a message from Tom to Laura'"; ThenLevelIsLogged(mockedILogger, expected, LogLevel.Debug); @@ -216,28 +224,34 @@ public void If_minimum_log_level_set_to_trace_then_log_is_called_for_trace_and_a [Fact] public void String_func_is_never_called_when_log_level_is_disabled() { + // Arrange var mockedFunc = new Mock>(); mockedFunc.Setup(x => x.Invoke()).Returns("test").Verifiable(); var mockedILogger = MockLogger(LogLevel.None); var repo = new Mock(); var currentLogger = new OcelotLogger(mockedILogger.Object, repo.Object); + // Act currentLogger.LogTrace(mockedFunc.Object); + // Assert mockedFunc.Verify(x => x.Invoke(), Times.Never); } [Fact] public void String_func_is_called_once_when_log_level_is_enabled() { + // Arrange var mockedFunc = new Mock>(); mockedFunc.Setup(x => x.Invoke()).Returns("test").Verifiable(); var mockedILogger = MockLogger(LogLevel.Information); var repo = new Mock(); var currentLogger = new OcelotLogger(mockedILogger.Object, repo.Object); + // Act currentLogger.LogInformation(mockedFunc.Object); + // Assert mockedFunc.Verify(x => x.Invoke(), Times.Once); } @@ -251,7 +265,7 @@ public void If_minimum_log_level_set_to_debug_then_log_is_called_for_debug_and_a var currentLogger = new OcelotLogger(mockedILogger.Object, repo.Object); currentLogger.LogDebug(() => $"a message from {_a} to {_b}"); - var expected = "requestId: No RequestId, previousRequestId: No PreviousRequestId, message: 'a message from tom to laura'"; + var expected = "requestId: No RequestId, previousRequestId: No PreviousRequestId, message: 'a message from Tom to Laura'"; ThenLevelIsLogged(mockedILogger, expected, LogLevel.Debug); @@ -288,7 +302,7 @@ public void If_minimum_log_level_set_to_warning_then_log_is_called_for_warning_a var currentLogger = new OcelotLogger(mockedILogger.Object, repo.Object); currentLogger.LogDebug(() => $"a message from {_a} to {_b}"); - var expected = "requestId: No RequestId, previousRequestId: No PreviousRequestId, message: 'a message from tom to laura'"; + var expected = "requestId: No RequestId, previousRequestId: No PreviousRequestId, message: 'a message from Tom to Laura'"; ThenLevelIsNotLogged(mockedILogger, expected, LogLevel.Debug); @@ -325,7 +339,7 @@ public void If_minimum_log_level_set_to_error_then_log_is_called_for_error_and_a var currentLogger = new OcelotLogger(mockedILogger.Object, repo.Object); currentLogger.LogDebug(() => $"a message from {_a} to {_b}"); - var expected = "requestId: No RequestId, previousRequestId: No PreviousRequestId, message: 'a message from tom to laura'"; + var expected = "requestId: No RequestId, previousRequestId: No PreviousRequestId, message: 'a message from Tom to Laura'"; ThenLevelIsNotLogged(mockedILogger, expected, LogLevel.Debug); @@ -362,7 +376,7 @@ public void If_minimum_log_level_set_to_critical_then_log_is_called_for_critical var currentLogger = new OcelotLogger(mockedILogger.Object, repo.Object); currentLogger.LogDebug(() => $"a message from {_a} to {_b}"); - var expected = "requestId: No RequestId, previousRequestId: No PreviousRequestId, message: 'a message from tom to laura'"; + var expected = "requestId: No RequestId, previousRequestId: No PreviousRequestId, message: 'a message from Tom to Laura'"; ThenLevelIsNotLogged(mockedILogger, expected, LogLevel.Debug); diff --git a/test/Ocelot.UnitTests/Middleware/BaseUrlFinderTests.cs b/test/Ocelot.UnitTests/Middleware/BaseUrlFinderTests.cs index 9caa84b33..29081f761 100644 --- a/test/Ocelot.UnitTests/Middleware/BaseUrlFinderTests.cs +++ b/test/Ocelot.UnitTests/Middleware/BaseUrlFinderTests.cs @@ -9,7 +9,6 @@ public class BaseUrlFinderTests : UnitTest private BaseUrlFinder _baseUrlFinder; private IConfiguration _config; private readonly List> _data; - private string _result; public BaseUrlFinderTests() { @@ -17,30 +16,27 @@ public BaseUrlFinderTests() } [Fact] - public void should_use_default_base_url() + public void Should_use_default_base_url() { - this.When(x => WhenIFindTheUrl()) - .Then(x => ThenTheUrlIs("http://localhost:5000")) - .BDDfy(); + var result = WhenIFindTheUrl(); + result.ShouldBe("http://localhost:5000"); } [Fact] - public void should_use_memory_config_base_url() + public void Should_use_memory_config_base_url() { - this.Given(x => GivenTheMemoryBaseUrlIs("http://baseurlfromconfig.com:5181")) - .When(x => WhenIFindTheUrl()) - .Then(x => ThenTheUrlIs("http://baseurlfromconfig.com:5181")) - .BDDfy(); + GivenTheMemoryBaseUrlIs("http://baseurlfromconfig.com:5181"); + var result = WhenIFindTheUrl(); + result.ShouldBe("http://baseurlfromconfig.com:5181"); } [Fact] - public void should_use_file_config_base_url() + public void Should_use_file_config_base_url() { - this.Given(x => GivenTheMemoryBaseUrlIs("http://localhost:7000")) - .And(x => GivenTheFileBaseUrlIs("http://baseurlfromconfig.com:5181")) - .When(x => WhenIFindTheUrl()) - .Then(x => ThenTheUrlIs("http://baseurlfromconfig.com:5181")) - .BDDfy(); + GivenTheMemoryBaseUrlIs("http://localhost:7000"); + GivenTheFileBaseUrlIs("http://baseurlfromconfig.com:5181"); + var result = WhenIFindTheUrl(); + result.ShouldBe("http://baseurlfromconfig.com:5181"); } private void GivenTheMemoryBaseUrlIs(string configValue) @@ -53,7 +49,7 @@ private void GivenTheFileBaseUrlIs(string configValue) _data.Add(new KeyValuePair("GlobalConfiguration:BaseUrl", configValue)); } - private void WhenIFindTheUrl() + private string WhenIFindTheUrl() { var source = new MemoryConfigurationSource { @@ -65,11 +61,6 @@ private void WhenIFindTheUrl() provider, }); _baseUrlFinder = new BaseUrlFinder(_config); - _result = _baseUrlFinder.Find(); - } - - private void ThenTheUrlIs(string expected) - { - _result.ShouldBe(expected); + return _baseUrlFinder.Find(); } } diff --git a/test/Ocelot.UnitTests/Middleware/OcelotPipelineExtensionsTests.cs b/test/Ocelot.UnitTests/Middleware/OcelotPipelineExtensionsTests.cs index 49c50a4ab..2afa7603c 100644 --- a/test/Ocelot.UnitTests/Middleware/OcelotPipelineExtensionsTests.cs +++ b/test/Ocelot.UnitTests/Middleware/OcelotPipelineExtensionsTests.cs @@ -18,35 +18,23 @@ public class OcelotPipelineExtensionsTests : UnitTest private RequestDelegate _handlers; [Fact] - public void should_set_up_pipeline() + public void Should_set_up_pipeline() { - this.Given(_ => GivenTheDepedenciesAreSetUp()) - .When(_ => WhenIBuild()) - .Then(_ => ThenThePipelineIsBuilt()) - .BDDfy(); - } + // Arrange + GivenTheDepedenciesAreSetUp(); - [Fact] - public void should_expand_pipeline() - { - this.Given(_ => GivenTheDepedenciesAreSetUp()) - .When(_ => WhenIExpandBuild()) - .Then(_ => ThenThePipelineIsBuilt()) - .BDDfy(); - } + // Act + _handlers = _builder.BuildOcelotPipeline(new OcelotPipelineConfiguration()); - private void ThenThePipelineIsBuilt() - { + // Assert _handlers.ShouldNotBeNull(); } - private void WhenIBuild() - { - _handlers = _builder.BuildOcelotPipeline(new OcelotPipelineConfiguration()); - } - - private void WhenIExpandBuild() + [Fact] + public void Should_expand_pipeline() { + // Arrange + GivenTheDepedenciesAreSetUp(); var configuration = new OcelotPipelineConfiguration(); configuration.MapWhenOcelotPipeline.Add((httpContext) => httpContext.WebSockets.IsWebSocketRequest, app => { @@ -56,13 +44,17 @@ private void WhenIExpandBuild() app.UseDownstreamUrlCreatorMiddleware(); app.UseWebSocketsProxyMiddleware(); }); + + // Act _handlers = _builder.BuildOcelotPipeline(new OcelotPipelineConfiguration()); + + // Assert + _handlers.ShouldNotBeNull(); } private void GivenTheDepedenciesAreSetUp() { - IConfigurationBuilder test = new ConfigurationBuilder(); - var root = test.Build(); + var root = new ConfigurationBuilder().Build(); var services = new ServiceCollection(); services.AddSingleton(root); services.AddOcelot(); diff --git a/test/Ocelot.UnitTests/Middleware/OcelotPiplineBuilderTests.cs b/test/Ocelot.UnitTests/Middleware/OcelotPiplineBuilderTests.cs index a1996a4ca..a4ffa3196 100644 --- a/test/Ocelot.UnitTests/Middleware/OcelotPiplineBuilderTests.cs +++ b/test/Ocelot.UnitTests/Middleware/OcelotPiplineBuilderTests.cs @@ -16,7 +16,7 @@ public class OcelotPiplineBuilderTests : UnitTest private readonly IServiceCollection _services; private readonly IConfiguration _configRoot; private int _counter; - private readonly HttpContext _httpContext; + private readonly DefaultHttpContext _httpContext; public OcelotPiplineBuilderTests() { @@ -39,37 +39,25 @@ private static IWebHostEnvironment GetHostingEnvironment() } [Fact] - public void should_build_generic() - { - this.When(x => WhenIUseAGeneric()) - .Then(x => ThenTheGenericIsInThePipeline()) - .BDDfy(); - } - - [Fact] - public void should_build_func() - { - this.When(x => WhenIUseAFunc()) - .Then(x => ThenTheFuncIsInThePipeline()) - .BDDfy(); - } - - private void WhenIUseAGeneric() + public void Should_build_generic() { + // Arrange var provider = _services.BuildServiceProvider(true); IApplicationBuilder builder = new ApplicationBuilder(provider); builder = builder.UseMiddleware(); + + // Act var del = builder.Build(); del.Invoke(_httpContext); - } - private void ThenTheGenericIsInThePipeline() - { + // Assert _httpContext.Response.StatusCode.ShouldBe(500); } - private void WhenIUseAFunc() + [Fact] + public void Should_build_func() { + // Arrange _counter = 0; var provider = _services.BuildServiceProvider(true); IApplicationBuilder builder = new ApplicationBuilder(provider); @@ -78,12 +66,12 @@ private void WhenIUseAFunc() _counter++; await next.Invoke(); }); + + // Act var del = builder.Build(); del.Invoke(_httpContext); - } - private void ThenTheFuncIsInThePipeline() - { + // Assert _counter.ShouldBe(1); _httpContext.Response.StatusCode.ShouldBe(404); } @@ -91,53 +79,40 @@ private void ThenTheFuncIsInThePipeline() [Fact] public void Middleware_Multi_Parameters_Invoke() { + // Arrange var provider = _services.BuildServiceProvider(true); IApplicationBuilder builder = new ApplicationBuilder(provider); builder = builder.UseMiddleware(); + + // Act, Assert var del = builder.Build(); del.Invoke(_httpContext); } private class MultiParametersInvokeMiddleware : OcelotMiddleware { - private readonly RequestDelegate _next; - +#pragma warning disable IDE0060 // Remove unused parameter public MultiParametersInvokeMiddleware(RequestDelegate next) - : base(new FakeLogger()) - { - _next = next; - } - - public Task Invoke(HttpContext context, IServiceProvider serviceProvider) - { - return Task.CompletedTask; - } + : base(new FakeLogger()) { } +#pragma warning disable CA1822 // Mark members as static + public Task Invoke(HttpContext context, IServiceProvider serviceProvider) => Task.CompletedTask; +#pragma warning restore CA1822 // Mark members as static +#pragma warning restore IDE0060 // Remove unused parameter } } internal class FakeLogger : IOcelotLogger { public void LogCritical(string message, Exception exception) { } - public void LogCritical(Func messageFactory, Exception exception) { } - public void LogError(string message, Exception exception) { } - public void LogError(Func messageFactory, Exception exception) { } - public void LogDebug(string message) { } - public void LogDebug(Func messageFactory) { } - public void LogInformation(string message) { } - public void LogInformation(Func messageFactory) { } - public void LogWarning(string message) { } - public void LogTrace(string message) { } - public void LogTrace(Func messageFactory) { } - public void LogWarning(Func messageFactory) { } } diff --git a/test/Ocelot.UnitTests/Multiplexing/DefinedAggregatorProviderTests.cs b/test/Ocelot.UnitTests/Multiplexing/DefinedAggregatorProviderTests.cs index 8e9b7a816..d929b1079 100644 --- a/test/Ocelot.UnitTests/Multiplexing/DefinedAggregatorProviderTests.cs +++ b/test/Ocelot.UnitTests/Multiplexing/DefinedAggregatorProviderTests.cs @@ -1,8 +1,6 @@ using Microsoft.Extensions.DependencyInjection; -using Ocelot.Configuration; using Ocelot.Configuration.Builder; using Ocelot.Multiplexer; -using Ocelot.Responses; using static Ocelot.UnitTests.Multiplexing.UserDefinedResponseAggregatorTests; namespace Ocelot.UnitTests.Multiplexing; @@ -10,73 +8,47 @@ namespace Ocelot.UnitTests.Multiplexing; public class DefinedAggregatorProviderTests : UnitTest { private ServiceLocatorDefinedAggregatorProvider _provider; - private Response _aggregator; - private Route _route; [Fact] - public void should_find_aggregator() + public void Should_find_aggregator() { + // Arrange var route = new RouteBuilder() .WithAggregator("TestDefinedAggregator") .Build(); + var serviceCollection = new ServiceCollection(); + serviceCollection.AddSingleton(); + var services = serviceCollection.BuildServiceProvider(true); + _provider = new ServiceLocatorDefinedAggregatorProvider(services); - this.Given(_ => GivenDefinedAggregator()) - .And(_ => GivenRoute(route)) - .When(_ => WhenIGet()) - .Then(_ => ThenTheAggregatorIsReturned()) - .BDDfy(); + // Act + var aggregator = _provider.Get(route); + + // Assert + aggregator.Data.ShouldNotBeNull(); + aggregator.Data.ShouldBeOfType(); + aggregator.IsError.ShouldBeFalse(); } [Fact] - public void should_not_find_aggregator() + public void Should_not_find_aggregator() { + // Arrange var route = new RouteBuilder() .WithAggregator("TestDefinedAggregator") .Build(); - this.Given(_ => GivenNoDefinedAggregator()) - .And(_ => GivenRoute(route)) - .When(_ => WhenIGet()) - .Then(_ => ThenAnErrorIsReturned()) - .BDDfy(); - } - - private void GivenDefinedAggregator() - { + // Arrange: Given No Defined Aggregator var serviceCollection = new ServiceCollection(); - serviceCollection.AddSingleton(); var services = serviceCollection.BuildServiceProvider(true); _provider = new ServiceLocatorDefinedAggregatorProvider(services); - } - private void ThenTheAggregatorIsReturned() - { - _aggregator.Data.ShouldNotBeNull(); - _aggregator.Data.ShouldBeOfType(); - _aggregator.IsError.ShouldBeFalse(); - } + // Act + var aggregator = _provider.Get(route); - private void GivenNoDefinedAggregator() - { - var serviceCollection = new ServiceCollection(); - var services = serviceCollection.BuildServiceProvider(true); - _provider = new ServiceLocatorDefinedAggregatorProvider(services); - } - - private void GivenRoute(Route route) - { - _route = route; - } - - private void WhenIGet() - { - _aggregator = _provider.Get(_route); - } - - private void ThenAnErrorIsReturned() - { - _aggregator.IsError.ShouldBeTrue(); - _aggregator.Errors[0].Message.ShouldBe("Could not find Aggregator: TestDefinedAggregator"); - _aggregator.Errors[0].ShouldBeOfType(); + // Assert + aggregator.IsError.ShouldBeTrue(); + aggregator.Errors[0].Message.ShouldBe("Could not find Aggregator: TestDefinedAggregator"); + aggregator.Errors[0].ShouldBeOfType(); } } diff --git a/test/Ocelot.UnitTests/Multiplexing/MultiplexingMiddlewareTests.cs b/test/Ocelot.UnitTests/Multiplexing/MultiplexingMiddlewareTests.cs index ec88fa995..c398da6ab 100644 --- a/test/Ocelot.UnitTests/Multiplexing/MultiplexingMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Multiplexing/MultiplexingMiddlewareTests.cs @@ -18,7 +18,7 @@ public class MultiplexingMiddlewareTests : UnitTest private MultiplexingMiddleware _middleware; private Ocelot.DownstreamRouteFinder.DownstreamRouteHolder _downstreamRoute; private int _count; - private readonly HttpContext _httpContext; + private readonly DefaultHttpContext _httpContext; private readonly Mock factory; private readonly Mock aggregator; private readonly Mock loggerFactory; @@ -39,24 +39,25 @@ public MultiplexingMiddlewareTests() private Task Next(HttpContext context) => Task.FromResult(_count++); [Fact] - public void should_multiplex() + public async Task Should_multiplex() { var route = GivenDefaultRoute(2); - this.Given(x => GivenTheFollowing(route)) - .When(x => WhenIMultiplex()) - .Then(x => ThePipelineIsCalled(2)) - .BDDfy(); + GivenTheFollowing(route); + + // Act + await _middleware.Invoke(_httpContext); + _count.ShouldBe(2); } [Fact] - public void should_not_multiplex() + public async Task Should_not_multiplex() { var route = new RouteBuilder().WithDownstreamRoute(new DownstreamRouteBuilder().Build()).Build(); - - this.Given(x => GivenTheFollowing(route)) - .When(x => WhenIMultiplex()) - .Then(x => ThePipelineIsCalled(1)) - .BDDfy(); + GivenTheFollowing(route); + + // Act + await _middleware.Invoke(_httpContext); + _count.ShouldBe(1); } [Fact] @@ -94,10 +95,10 @@ Task NextMe(HttpContext context) GivenTheFollowing(GivenDefaultRoute(2)); // Act - await WhenIMultiplex(); + await _middleware.Invoke(_httpContext); // Assert - ThePipelineIsCalled(2); + _count.ShouldBe(2); AssertUsers(actualContext); } @@ -117,10 +118,10 @@ Task NextMe(HttpContext context) GivenTheFollowing(GivenDefaultRoute(1)); // Act - await WhenIMultiplex(); + await _middleware.Invoke(_httpContext); // Assert - ThePipelineIsCalled(1); + _count.ShouldBe(1); } [Fact] @@ -136,7 +137,7 @@ public async Task Should_Call_ProcessSingleRoute_Once_If_One_Downstream_Route() GivenTheFollowing(GivenDefaultRoute(1)); // Act - await WhenIMultiplex(); + await _middleware.Invoke(_httpContext); // Assert mock.Protected().Verify("ProcessSingleRouteAsync", Times.Once(), @@ -159,7 +160,7 @@ public async Task Should_Not_Call_ProcessSingleRoute_If_More_Than_One_Downstream GivenTheFollowing(GivenDefaultRoute(routesCount)); // Act - await WhenIMultiplex(); + await _middleware.Invoke(_httpContext); // Assert mock.Protected().Verify("ProcessSingleRouteAsync", Times.Never(), @@ -182,7 +183,7 @@ public async Task Should_Create_As_Many_Contexts_As_Routes_And_Map_Is_Called_Onc GivenTheFollowing(GivenDefaultRoute(routesCount)); // Act - await WhenIMultiplex(); + await _middleware.Invoke(_httpContext); // Assert mock.Protected().Verify("MapAsync", Times.Once(), @@ -203,7 +204,7 @@ public async Task Should_Not_Call_ProcessSingleRoute_Or_Map_If_No_Route() GivenTheFollowing(GivenDefaultRoute(0)); // Act - await WhenIMultiplex(); + await _middleware.Invoke(_httpContext); // Assert mock.Protected().Verify("ProcessSingleRouteAsync", Times.Never(), @@ -230,7 +231,7 @@ public async Task Should_Call_CloneRequestBodyAsync_Each_Time_Per_Requests(int n GivenTheFollowing(GivenDefaultRoute(numberOfRoutes)); // Act - await WhenIMultiplex(); + await _middleware.Invoke(_httpContext); // Assert mock.Protected().Verify>("CloneRequestBodyAsync", @@ -251,7 +252,7 @@ public async Task If_Using_3_Routes_WithAggregator_ProcessSingleRoute_Is_Never_C GivenTheFollowing(GivenRoutesWithAggregator()); // Act - await WhenIMultiplex(); + await _middleware.Invoke(_httpContext); mock.Protected().Verify("ProcessSingleRouteAsync", Times.Never(), ItExpr.IsAny(), @@ -262,7 +263,7 @@ public async Task If_Using_3_Routes_WithAggregator_ProcessSingleRoute_Is_Never_C ItExpr.IsAny(), ItExpr.IsAny>()); - ThePipelineIsCalled(3); + _count.ShouldBe(3); } private RequestDelegate AggregateRequestDelegateFactory() @@ -360,14 +361,4 @@ private void GivenTheFollowing(Route route) _downstreamRoute = new Ocelot.DownstreamRouteFinder.DownstreamRouteHolder(new List(), route); _httpContext.Items.UpsertDownstreamRoute(_downstreamRoute); } - - private async Task WhenIMultiplex() - { - await _middleware.Invoke(_httpContext); - } - - private void ThePipelineIsCalled(int expected) - { - _count.ShouldBe(expected); - } } diff --git a/test/Ocelot.UnitTests/Multiplexing/ResponseAggregatorFactoryTests.cs b/test/Ocelot.UnitTests/Multiplexing/ResponseAggregatorFactoryTests.cs index 07ee3a3d9..0b6104c66 100644 --- a/test/Ocelot.UnitTests/Multiplexing/ResponseAggregatorFactoryTests.cs +++ b/test/Ocelot.UnitTests/Multiplexing/ResponseAggregatorFactoryTests.cs @@ -8,7 +8,6 @@ public class ResponseAggregatorFactoryTests : UnitTest { private readonly InMemoryResponseAggregatorFactory _factory; private readonly Mock _provider; - private Route _route; private IResponseAggregator _aggregator; public ResponseAggregatorFactoryTests() @@ -19,42 +18,30 @@ public ResponseAggregatorFactoryTests() } [Fact] - public void should_return_simple_json_aggregator() + public void Should_return_simple_json_aggregator() { - var route = new RouteBuilder() - .Build(); + // Arrange + var route = new RouteBuilder().Build(); + + // Act + _aggregator = _factory.Get(route); - this.Given(_ => GivenRoute(route)) - .When(_ => WhenIGet()) - .Then(_ => ThenTheAggregatorIs()) - .BDDfy(); + // Assert + _aggregator.ShouldBeOfType(); } [Fact] - public void should_return_user_defined_aggregator() + public void Should_return_user_defined_aggregator() { + // Arrange var route = new RouteBuilder() .WithAggregator("doesntmatter") .Build(); - this.Given(_ => GivenRoute(route)) - .When(_ => WhenIGet()) - .Then(_ => ThenTheAggregatorIs()) - .BDDfy(); - } + // Act + _aggregator = _factory.Get(route); - private void GivenRoute(Route route) - { - _route = route; - } - - private void WhenIGet() - { - _aggregator = _factory.Get(_route); - } - - private void ThenTheAggregatorIs() - { - _aggregator.ShouldBeOfType(); + // Assert + _aggregator.ShouldBeOfType(); } } diff --git a/test/Ocelot.UnitTests/Multiplexing/SimpleJsonResponseAggregatorTests.cs b/test/Ocelot.UnitTests/Multiplexing/SimpleJsonResponseAggregatorTests.cs index c4a8c429a..dec8996b6 100644 --- a/test/Ocelot.UnitTests/Multiplexing/SimpleJsonResponseAggregatorTests.cs +++ b/test/Ocelot.UnitTests/Multiplexing/SimpleJsonResponseAggregatorTests.cs @@ -14,9 +14,6 @@ namespace Ocelot.UnitTests.Multiplexing; public class SimpleJsonResponseAggregatorTests : UnitTest { private readonly SimpleJsonResponseAggregator _aggregator; - private List _downstreamContexts; - private HttpContext _upstreamContext; - private Route _route; public SimpleJsonResponseAggregatorTests() { @@ -24,7 +21,7 @@ public SimpleJsonResponseAggregatorTests() } [Fact] - public void should_aggregate_n_responses_and_set_response_content_on_upstream_context_withConfig() + public async Task Should_aggregate_n_responses_and_set_response_content_on_upstream_context_withConfig() { var commentsDownstreamRoute = new DownstreamRouteBuilder().WithKey("Comments").Build(); @@ -58,21 +55,20 @@ public void should_aggregate_n_responses_and_set_response_content_on_upstream_co userDetailsDownstreamContext.Items.UpsertDownstreamRoute(userDetailsDownstreamRoute); var downstreamContexts = new List { commentsDownstreamContext, userDetailsDownstreamContext }; - var expected = "{\"Comments\":" + commentsResponseContent + ",\"UserDetails\":" + userDetailsResponseContent + "}"; + var upstreamContext = new DefaultHttpContext(); + + // Act + await _aggregator.Aggregate(route, upstreamContext, downstreamContexts); - this.Given(x => GivenTheUpstreamContext(new DefaultHttpContext())) - .And(x => GivenTheRoute(route)) - .And(x => GivenTheDownstreamContext(downstreamContexts)) - .When(x => WhenIAggregate()) - .Then(x => ThenTheContentIs(expected)) - .And(x => ThenTheContentTypeIs("application/json")) - .And(x => ThenTheReasonPhraseIs("cannot return from aggregate..which reason phrase would you use?")) - .BDDfy(); + // Assert + await ThenTheContentIs(upstreamContext, expected); + ThenTheContentTypeIs(upstreamContext, "application/json"); + ThenTheReasonPhraseIs(upstreamContext, "cannot return from aggregate..which reason phrase would you use?"); } [Fact] - public void should_aggregate_n_responses_and_set_response_content_on_upstream_context() + public async Task Should_aggregate_n_responses_and_set_response_content_on_upstream_context() { var billDownstreamRoute = new DownstreamRouteBuilder().WithKey("Bill").Build(); @@ -97,21 +93,20 @@ public void should_aggregate_n_responses_and_set_response_content_on_upstream_co georgeDownstreamContext.Items.UpsertDownstreamRoute(georgeDownstreamRoute); var downstreamContexts = new List { billDownstreamContext, georgeDownstreamContext }; - var expected = "{\"Bill\":Bill says hi,\"George\":George says hi}"; + var upstreamContext = new DefaultHttpContext(); - this.Given(x => GivenTheUpstreamContext(new DefaultHttpContext())) - .And(x => GivenTheRoute(route)) - .And(x => GivenTheDownstreamContext(downstreamContexts)) - .When(x => WhenIAggregate()) - .Then(x => ThenTheContentIs(expected)) - .And(x => ThenTheContentTypeIs("application/json")) - .And(x => ThenTheReasonPhraseIs("cannot return from aggregate..which reason phrase would you use?")) - .BDDfy(); + // Act + await _aggregator.Aggregate(route, upstreamContext, downstreamContexts); + + // Assert + await ThenTheContentIs(upstreamContext, expected); + ThenTheContentTypeIs(upstreamContext, "application/json"); + ThenTheReasonPhraseIs(upstreamContext, "cannot return from aggregate..which reason phrase would you use?"); } [Fact] - public void should_return_error_if_any_downstreams_have_errored() + public async Task Should_return_error_if_any_downstreams_have_errored() { var billDownstreamRoute = new DownstreamRouteBuilder().WithKey("Bill").Build(); @@ -138,64 +133,36 @@ public void should_return_error_if_any_downstreams_have_errored() georgeDownstreamContext.Items.SetError(new AnyError()); var downstreamContexts = new List { billDownstreamContext, georgeDownstreamContext }; - var expected = "Error"; + var upstreamContext = new DefaultHttpContext(); - this.Given(x => GivenTheUpstreamContext(new DefaultHttpContext())) - .And(x => GivenTheRoute(route)) - .And(x => GivenTheDownstreamContext(downstreamContexts)) - .When(x => WhenIAggregate()) - .Then(x => ThenTheContentIs(expected)) - .And(x => ThenTheErrorIsMapped()) - .BDDfy(); - } + // Act + await _aggregator.Aggregate(route, upstreamContext, downstreamContexts); - private void ThenTheReasonPhraseIs(string expected) - { - _upstreamContext.Items.DownstreamResponse().ReasonPhrase.ShouldBe(expected); - } - - private void ThenTheErrorIsMapped() - { - _upstreamContext.Items.Errors().ShouldBe(_downstreamContexts[1].Items.Errors()); - _upstreamContext.Items.DownstreamResponse().ShouldBe(_downstreamContexts[1].Items.DownstreamResponse()); + // Assert + await ThenTheContentIs(upstreamContext, expected); + ThenTheErrorIsMapped(upstreamContext, downstreamContexts); } - private void GivenTheRoute(Route route) + private static void ThenTheReasonPhraseIs(DefaultHttpContext upstreamContext, string expected) { - _route = route; + upstreamContext.Items.DownstreamResponse().ReasonPhrase.ShouldBe(expected); } - private void GivenTheUpstreamContext(HttpContext upstreamContext) + private static void ThenTheErrorIsMapped(DefaultHttpContext upstreamContext, List downstreamContexts) { - _upstreamContext = upstreamContext; + upstreamContext.Items.Errors().ShouldBe(downstreamContexts[1].Items.Errors()); + upstreamContext.Items.DownstreamResponse().ShouldBe(downstreamContexts[1].Items.DownstreamResponse()); } - private void GivenTheDownstreamContext(List downstreamContexts) + private static async Task ThenTheContentIs(DefaultHttpContext upstreamContext, string expected) { - _downstreamContexts = downstreamContexts; - } - - private async Task WhenIAggregate() - { - await _aggregator.Aggregate(_route, _upstreamContext, _downstreamContexts); - } - - private async Task ThenTheContentIs(string expected) - { - var content = await _upstreamContext.Items.DownstreamResponse().Content.ReadAsStringAsync(); + var content = await upstreamContext.Items.DownstreamResponse().Content.ReadAsStringAsync(); content.ShouldBe(expected); } - private void ThenTheContentTypeIs(string expected) - { - _upstreamContext.Items.DownstreamResponse().Content.Headers.ContentType.MediaType.ShouldBe(expected); - } - - private void ThenTheUpstreamContextIsMappedForNonAggregate() + private static void ThenTheContentTypeIs(DefaultHttpContext upstreamContext, string expected) { - _upstreamContext.Items.DownstreamRequest().ShouldBe(_downstreamContexts[0].Items.DownstreamRequest()); - _upstreamContext.Items.DownstreamRequest().ShouldBe(_downstreamContexts[0].Items.DownstreamRequest()); - _upstreamContext.Items.Errors().ShouldBe(_downstreamContexts[0].Items.Errors()); + upstreamContext.Items.DownstreamResponse().Content.Headers.ContentType.MediaType.ShouldBe(expected); } } diff --git a/test/Ocelot.UnitTests/Multiplexing/UserDefinedResponseAggregatorTests.cs b/test/Ocelot.UnitTests/Multiplexing/UserDefinedResponseAggregatorTests.cs index e1e0dfb68..b9e8d38ee 100644 --- a/test/Ocelot.UnitTests/Multiplexing/UserDefinedResponseAggregatorTests.cs +++ b/test/Ocelot.UnitTests/Multiplexing/UserDefinedResponseAggregatorTests.cs @@ -12,9 +12,6 @@ public class UserDefinedResponseAggregatorTests : UnitTest { private readonly UserDefinedResponseAggregator _aggregator; private readonly Mock _provider; - private Route _route; - private List _contexts; - private HttpContext _context; public UserDefinedResponseAggregatorTests() { @@ -23,10 +20,10 @@ public UserDefinedResponseAggregatorTests() } [Fact] - public void should_call_aggregator() + public async Task Should_call_aggregator() { + // Arrange var route = new RouteBuilder().Build(); - var context = new DefaultHttpContext(); var contextA = new DefaultHttpContext(); @@ -41,21 +38,24 @@ public void should_call_aggregator() contextB, }; - this.Given(_ => GivenTheProviderReturnsAggregator()) - .And(_ => GivenRoute(route)) - .And(_ => GivenContexts(contexts)) - .And(_ => GivenContext(context)) - .When(_ => WhenIAggregate()) - .Then(_ => ThenTheProviderIsCalled()) - .And(_ => ThenTheContentIsCorrect()) - .BDDfy(); + // Arrange: Given The Provider Returns Aggregator + var aggregator = new TestDefinedAggregator(); + _provider.Setup(x => x.Get(It.IsAny())).Returns(new OkResponse(aggregator)); + + // Act + await _aggregator.Aggregate(route, context, contexts); + + // Assert + _provider.Verify(x => x.Get(route), Times.Once); + var content = await context.Items.DownstreamResponse().Content.ReadAsStringAsync(); + content.ShouldBe("Tom, Laura"); } [Fact] - public void should_not_find_aggregator() + public async Task Should_not_find_aggregator() { + // Arrange var route = new RouteBuilder().Build(); - var context = new DefaultHttpContext(); var contextA = new DefaultHttpContext(); @@ -70,62 +70,16 @@ public void should_not_find_aggregator() contextB, }; - this.Given(_ => GivenTheProviderReturnsError()) - .And(_ => GivenRoute(route)) - .And(_ => GivenContexts(contexts)) - .And(_ => GivenContext(context)) - .When(_ => WhenIAggregate()) - .Then(_ => ThenTheProviderIsCalled()) - .And(_ => ThenTheErrorIsReturned()) - .BDDfy(); - } - - private void ThenTheErrorIsReturned() - { - _context.Items.Errors().Count.ShouldBeGreaterThan(0); - _context.Items.Errors().Count.ShouldBe(1); - } - - private void GivenTheProviderReturnsError() - { + // Arrange: Given The Provider Returns Error _provider.Setup(x => x.Get(It.IsAny())).Returns(new ErrorResponse(new AnyError())); - } - private async Task ThenTheContentIsCorrect() - { - var content = await _context.Items.DownstreamResponse().Content.ReadAsStringAsync(); - content.ShouldBe("Tom, Laura"); - } + // Act + await _aggregator.Aggregate(route, context, contexts); - private void ThenTheProviderIsCalled() - { - _provider.Verify(x => x.Get(_route), Times.Once); - } - - private void GivenContext(HttpContext context) - { - _context = context; - } - - private void GivenContexts(List contexts) - { - _contexts = contexts; - } - - private async Task WhenIAggregate() - { - await _aggregator.Aggregate(_route, _context, _contexts); - } - - private void GivenTheProviderReturnsAggregator() - { - var aggregator = new TestDefinedAggregator(); - _provider.Setup(x => x.Get(It.IsAny())).Returns(new OkResponse(aggregator)); - } - - private void GivenRoute(Route route) - { - _route = route; + // Assert + _provider.Verify(x => x.Get(route), Times.Once); + context.Items.Errors().Count.ShouldBeGreaterThan(0); + context.Items.Errors().Count.ShouldBe(1); } public class TestDefinedAggregator : IDefinedAggregator diff --git a/test/Ocelot.UnitTests/Ocelot.UnitTests.csproj b/test/Ocelot.UnitTests/Ocelot.UnitTests.csproj index 1a8fca9db..21d6cef5b 100644 --- a/test/Ocelot.UnitTests/Ocelot.UnitTests.csproj +++ b/test/Ocelot.UnitTests/Ocelot.UnitTests.csproj @@ -67,10 +67,6 @@ - - - - diff --git a/test/Ocelot.UnitTests/Polly/OcelotBuilderExtensionsTests.cs b/test/Ocelot.UnitTests/Polly/OcelotBuilderExtensionsTests.cs index 17487f82f..6fae1427b 100644 --- a/test/Ocelot.UnitTests/Polly/OcelotBuilderExtensionsTests.cs +++ b/test/Ocelot.UnitTests/Polly/OcelotBuilderExtensionsTests.cs @@ -14,6 +14,7 @@ public class OcelotBuilderExtensionsTests [Fact] public void Should_build() { + // Arrange var loggerFactory = new Mock(); var contextAccessor = new Mock(); var services = new ServiceCollection(); @@ -33,10 +34,12 @@ public void Should_build() .AddPolly(); var provider = services.BuildServiceProvider(true); - var handler = provider.GetService(); - handler.ShouldNotBeNull(); + // Act, Assert + var del = provider.GetService(); + del.ShouldNotBeNull(); - var delgatingHandler = handler(route, contextAccessor.Object, loggerFactory.Object); - delgatingHandler.ShouldNotBeNull(); + // Act, Assert + var handler = del(route, contextAccessor.Object, loggerFactory.Object); + handler.ShouldNotBeNull(); } } diff --git a/test/Ocelot.UnitTests/Polly/PollyResiliencePipelineDelegatingHandlerTests.cs b/test/Ocelot.UnitTests/Polly/PollyResiliencePipelineDelegatingHandlerTests.cs index ec0da4286..15d4d226b 100644 --- a/test/Ocelot.UnitTests/Polly/PollyResiliencePipelineDelegatingHandlerTests.cs +++ b/test/Ocelot.UnitTests/Polly/PollyResiliencePipelineDelegatingHandlerTests.cs @@ -114,10 +114,9 @@ private static DownstreamRoute DownstreamRouteFactory() .WithPriority(1) .WithOriginalValue("/").Build(); - var route = new DownstreamRouteBuilder() + return new DownstreamRouteBuilder() .WithQosOptions(options) - .WithUpstreamPathTemplate(upstreamPath).Build(); - - return route; + .WithUpstreamPathTemplate(upstreamPath) + .Build(); } } diff --git a/test/Ocelot.UnitTests/QueryStrings/AddQueriesToRequestTests.cs b/test/Ocelot.UnitTests/QueryStrings/AddQueriesToRequestTests.cs index 8af110f51..6ec926287 100644 --- a/test/Ocelot.UnitTests/QueryStrings/AddQueriesToRequestTests.cs +++ b/test/Ocelot.UnitTests/QueryStrings/AddQueriesToRequestTests.cs @@ -13,10 +13,6 @@ public class AddQueriesToRequestTests : UnitTest private readonly AddQueriesToRequest _addQueriesToRequest; private DownstreamRequest _downstreamRequest; private readonly Mock _parser; - private List _configuration; - private List _claims; - private Response _result; - private Response _claimValue; private HttpRequestMessage _request; public AddQueriesToRequestTests() @@ -28,47 +24,49 @@ public AddQueriesToRequestTests() } [Fact] - public void should_add_new_queries_to_downstream_request() + public void Should_add_new_queries_to_downstream_request() { + // Arrange var claims = new List { new("test", "data"), }; + var configuration = new List + { + new("query-key", string.Empty, string.Empty, 0), + }; + var claimValue = GivenTheClaimParserReturns(new OkResponse("value")); - this.Given( - x => x.GivenAClaimToThing(new List - { - new("query-key", string.Empty, string.Empty, 0), - })) - .Given(x => x.GivenClaims(claims)) - .And(x => x.GivenTheClaimParserReturns(new OkResponse("value"))) - .When(x => x.WhenIAddQueriesToTheRequest()) - .Then(x => x.ThenTheResultIsSuccess()) - .And(x => x.ThenTheQueryIsAdded()) - .BDDfy(); + // Act + var result = _addQueriesToRequest.SetQueriesOnDownstreamRequest(configuration, claims, _downstreamRequest); + + // Assert + result.IsError.ShouldBeFalse(); + ThenTheQueryIsAdded(claimValue); } [Fact] - public void should_add_new_queries_to_downstream_request_and_preserve_other_queries() + public void Should_add_new_queries_to_downstream_request_and_preserve_other_queries() { + // Arrange var claims = new List { new("test", "data"), }; + var configuration = new List + { + new("query-key", string.Empty, string.Empty, 0), + }; + GivenTheDownstreamRequestHasQueryString("?test=1&test=2"); + var claimValue = GivenTheClaimParserReturns(new OkResponse("value")); + + // Act + var result = _addQueriesToRequest.SetQueriesOnDownstreamRequest(configuration, claims, _downstreamRequest); - this.Given( - x => x.GivenAClaimToThing(new List - { - new("query-key", string.Empty, string.Empty, 0), - })) - .Given(x => x.GivenClaims(claims)) - .And(x => GivenTheDownstreamRequestHasQueryString("?test=1&test=2")) - .And(x => x.GivenTheClaimParserReturns(new OkResponse("value"))) - .When(x => x.WhenIAddQueriesToTheRequest()) - .Then(x => x.ThenTheResultIsSuccess()) - .And(x => x.ThenTheQueryIsAdded()) - .And(x => TheTheQueryStringIs("?test=1&test=2&query-key=value")) - .BDDfy(); + // Assert + result.IsError.ShouldBeFalse(); + ThenTheQueryIsAdded(claimValue); + TheTheQueryStringIs("?test=1&test=2&query-key=value"); } private void TheTheQueryStringIs(string expected) @@ -77,60 +75,54 @@ private void TheTheQueryStringIs(string expected) } [Fact] - public void should_replace_existing_queries_on_downstream_request() + public void Should_replace_existing_queries_on_downstream_request() { + // Arrange var claims = new List { new("test", "data"), }; + var configuration = new List + { + new("query-key", string.Empty, string.Empty, 0), + }; + GivenTheDownstreamRequestHasQueryString("query-key", "initial"); + var claimValue = GivenTheClaimParserReturns(new OkResponse("value")); - this.Given( - x => x.GivenAClaimToThing(new List - { - new("query-key", string.Empty, string.Empty, 0), - })) - .And(x => x.GivenClaims(claims)) - .And(x => x.GivenTheDownstreamRequestHasQueryString("query-key", "initial")) - .And(x => x.GivenTheClaimParserReturns(new OkResponse("value"))) - .When(x => x.WhenIAddQueriesToTheRequest()) - .Then(x => x.ThenTheResultIsSuccess()) - .And(x => x.ThenTheQueryIsAdded()) - .BDDfy(); + // Act + var result = _addQueriesToRequest.SetQueriesOnDownstreamRequest(configuration, claims, _downstreamRequest); + + // Assert + result.IsError.ShouldBeFalse(); + ThenTheQueryIsAdded(claimValue); } [Fact] - public void should_return_error() + public void Should_return_error() { - this.Given( - x => x.GivenAClaimToThing(new List - { - new(string.Empty, string.Empty, string.Empty, 0), - })) - .Given(x => x.GivenClaims(new List())) - .And(x => x.GivenTheClaimParserReturns(new ErrorResponse(new List - { - new AnyError(), - }))) - .When(x => x.WhenIAddQueriesToTheRequest()) - .Then(x => x.ThenTheResultIsError()) - .BDDfy(); - } + // Arrange + var claims = new List(); + var configuration = new List + { + new(string.Empty, string.Empty, string.Empty, 0), + }; + _ = GivenTheClaimParserReturns(new ErrorResponse(new List + { + new AnyError(), + })); - private void ThenTheQueryIsAdded() - { - var queries = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(_downstreamRequest.ToHttpRequestMessage().RequestUri.OriginalString); - var query = queries.First(x => x.Key == "query-key"); - query.Value.First().ShouldBe(_claimValue.Data); - } + // Act + var result = _addQueriesToRequest.SetQueriesOnDownstreamRequest(configuration, claims, _downstreamRequest); - private void GivenAClaimToThing(List configuration) - { - _configuration = configuration; + // Assert + result.IsError.ShouldBeTrue(); } - private void GivenClaims(List claims) + private void ThenTheQueryIsAdded(Response claimValue) { - _claims = claims; + var queries = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(_downstreamRequest.ToHttpRequestMessage().RequestUri.OriginalString); + var query = queries.First(x => x.Key == "query-key"); + query.Value.First().ShouldBe(claimValue.Data); } private void GivenTheDownstreamRequestHasQueryString(string queryString) @@ -147,32 +139,11 @@ private void GivenTheDownstreamRequestHasQueryString(string key, string value) _request.RequestUri = new Uri(newUri); } - private void GivenTheClaimParserReturns(Response claimValue) - { - _claimValue = claimValue; - _parser - .Setup( - x => - x.GetValue(It.IsAny>(), - It.IsAny(), - It.IsAny(), - It.IsAny())) - .Returns(_claimValue); - } - - private void WhenIAddQueriesToTheRequest() - { - _result = _addQueriesToRequest.SetQueriesOnDownstreamRequest(_configuration, _claims, _downstreamRequest); - } - - private void ThenTheResultIsSuccess() - { - _result.IsError.ShouldBe(false); - } - - private void ThenTheResultIsError() + private Response GivenTheClaimParserReturns(Response claimValue) { - _result.IsError.ShouldBe(true); + _parser.Setup(x => x.GetValue(It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(claimValue); + return claimValue; } private class AnyError : Error diff --git a/test/Ocelot.UnitTests/QueryStrings/ClaimsToQueryStringMiddlewareTests.cs b/test/Ocelot.UnitTests/QueryStrings/ClaimsToQueryStringMiddlewareTests.cs index 21f831980..41d7a4145 100644 --- a/test/Ocelot.UnitTests/QueryStrings/ClaimsToQueryStringMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/QueryStrings/ClaimsToQueryStringMiddlewareTests.cs @@ -1,8 +1,7 @@ using Microsoft.AspNetCore.Http; using Ocelot.Configuration; using Ocelot.Configuration.Builder; -using Ocelot.DownstreamRouteFinder.UrlMatcher; -using Ocelot.Infrastructure.RequestData; +using Ocelot.DownstreamRouteFinder; using Ocelot.Logging; using Ocelot.Middleware; using Ocelot.QueryStrings; @@ -20,12 +19,10 @@ public class ClaimsToQueryStringMiddlewareTests : UnitTest private readonly Mock _logger; private readonly ClaimsToQueryStringMiddleware _middleware; private readonly RequestDelegate _next; - private readonly HttpContext _httpContext; - private Mock _repo; + private readonly DefaultHttpContext _httpContext; public ClaimsToQueryStringMiddlewareTests() { - _repo = new Mock(); _httpContext = new DefaultHttpContext(); _loggerFactory = new Mock(); _logger = new Mock(); @@ -37,9 +34,11 @@ public ClaimsToQueryStringMiddlewareTests() } [Fact] - public void should_call_add_queries_correctly() + public async Task Should_call_add_queries_correctly() { - var downstreamRoute = new Ocelot.DownstreamRouteFinder.DownstreamRouteHolder(new List(), + // Arrange + var downstreamRoute = new DownstreamRouteHolder( + new(), new RouteBuilder() .WithDownstreamRoute(new DownstreamRouteBuilder() .WithDownstreamPathTemplate("any old string") @@ -51,42 +50,16 @@ public void should_call_add_queries_correctly() .Build()) .WithUpstreamHttpMethod(new List { "Get" }) .Build()); - - this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) - .And(x => x.GivenTheAddHeadersToRequestReturnsOk()) - .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.ThenTheAddQueriesToRequestIsCalledCorrectly()) - .BDDfy(); - } - - private async Task WhenICallTheMiddleware() - { - await _middleware.Invoke(_httpContext); - } - - private void GivenTheAddHeadersToRequestReturnsOk() - { - _addQueries - .Setup(x => x.SetQueriesOnDownstreamRequest( - It.IsAny>(), - It.IsAny>(), - It.IsAny())) + _httpContext.Items.UpsertTemplatePlaceholderNameAndValues(downstreamRoute.TemplatePlaceholderNameAndValues); + _httpContext.Items.UpsertDownstreamRoute(downstreamRoute.Route.DownstreamRoute[0]); + _addQueries.Setup(x => x.SetQueriesOnDownstreamRequest(It.IsAny>(), It.IsAny>(), It.IsAny())) .Returns(new OkResponse()); - } - - private void ThenTheAddQueriesToRequestIsCalledCorrectly() - { - _addQueries - .Verify(x => x.SetQueriesOnDownstreamRequest( - It.IsAny>(), - It.IsAny>(), - _httpContext.Items.DownstreamRequest()), Times.Once); - } - private void GivenTheDownStreamRouteIs(Ocelot.DownstreamRouteFinder.DownstreamRouteHolder downstreamRoute) - { - _httpContext.Items.UpsertTemplatePlaceholderNameAndValues(downstreamRoute.TemplatePlaceholderNameAndValues); + // Act + await _middleware.Invoke(_httpContext); - _httpContext.Items.UpsertDownstreamRoute(downstreamRoute.Route.DownstreamRoute[0]); + // Assert + _addQueries.Verify(x => x.SetQueriesOnDownstreamRequest(It.IsAny>(), It.IsAny>(), _httpContext.Items.DownstreamRequest()), + Times.Once); } } diff --git a/test/Ocelot.UnitTests/RateLimiting/RateLimitingMiddlewareTests.cs b/test/Ocelot.UnitTests/RateLimiting/RateLimitingMiddlewareTests.cs index 809961a1d..7e3fa7c56 100644 --- a/test/Ocelot.UnitTests/RateLimiting/RateLimitingMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/RateLimiting/RateLimitingMiddlewareTests.cs @@ -163,7 +163,7 @@ public async Task MiddlewareInvoke_PeriodTimespanValueIsGreaterThanPeriod_Status contexts[0].Items.Errors().Single().HttpStatusCode.ShouldBe((int)HttpStatusCode.TooManyRequests); } - private async Task> WhenICallTheMiddlewareMultipleTimes(long times, _DownstreamRouteHolder_ downstreamRoute) + private async Task> WhenICallTheMiddlewareMultipleTimes(long times, _DownstreamRouteHolder_ holder) { var contexts = new List(); _downstreamResponses.Clear(); @@ -173,9 +173,9 @@ private async Task> WhenICallTheMiddlewareMultipleTimes(long t var stream = GetFakeStream($"{i}"); context.Response.Body = stream; context.Response.RegisterForDispose(stream); - context.Items.UpsertDownstreamRoute(downstreamRoute.Route.DownstreamRoute[0]); - context.Items.UpsertTemplatePlaceholderNameAndValues(downstreamRoute.TemplatePlaceholderNameAndValues); - context.Items.UpsertDownstreamRoute(downstreamRoute); + context.Items.UpsertDownstreamRoute(holder.Route.DownstreamRoute[0]); + context.Items.UpsertTemplatePlaceholderNameAndValues(holder.TemplatePlaceholderNameAndValues); + context.Items.UpsertDownstreamRoute(holder); var request = new HttpRequestMessage(new HttpMethod("GET"), _url); context.Items.UpsertDownstreamRequest(new DownstreamRequest(request)); context.Request.Headers.TryAdd("ClientId", "ocelotclient1"); @@ -189,13 +189,13 @@ private async Task> WhenICallTheMiddlewareMultipleTimes(long t return contexts; } - private static Stream GetFakeStream(string str) + private static MemoryStream GetFakeStream(string str) { byte[] data = Encoding.ASCII.GetBytes(str); return new MemoryStream(data, 0, data.Length); } - private async Task WhenICallTheMiddlewareWithWhiteClient(_DownstreamRouteHolder_ downstreamRoute) + private async Task WhenICallTheMiddlewareWithWhiteClient(_DownstreamRouteHolder_ holder) { const string ClientId = "ocelotclient2"; for (var i = 0; i < 10; i++) @@ -204,9 +204,9 @@ private async Task WhenICallTheMiddlewareWithWhiteClient(_DownstreamRouteHolder_ var stream = GetFakeStream($"{i}"); context.Response.Body = stream; context.Response.RegisterForDispose(stream); - context.Items.UpsertDownstreamRoute(downstreamRoute.Route.DownstreamRoute[0]); - context.Items.UpsertTemplatePlaceholderNameAndValues(downstreamRoute.TemplatePlaceholderNameAndValues); - context.Items.UpsertDownstreamRoute(downstreamRoute); + context.Items.UpsertDownstreamRoute(holder.Route.DownstreamRoute[0]); + context.Items.UpsertTemplatePlaceholderNameAndValues(holder.TemplatePlaceholderNameAndValues); + context.Items.UpsertDownstreamRoute(holder); var request = new HttpRequestMessage(new HttpMethod("GET"), _url); request.Headers.Add("ClientId", ClientId); context.Items.UpsertDownstreamRequest(new DownstreamRequest(request)); diff --git a/test/Ocelot.UnitTests/Repository/HttpDataRepositoryTests.cs b/test/Ocelot.UnitTests/Repository/HttpDataRepositoryTests.cs new file mode 100644 index 000000000..aa64be4d7 --- /dev/null +++ b/test/Ocelot.UnitTests/Repository/HttpDataRepositoryTests.cs @@ -0,0 +1,53 @@ +using Microsoft.AspNetCore.Http; +using Ocelot.Infrastructure.RequestData; + +namespace Ocelot.UnitTests.Repository; + +public class HttpDataRepositoryTests : UnitTest +{ + private readonly HttpDataRepository _repository; + private readonly HttpContextAccessor _contextAccesor; + + public HttpDataRepositoryTests() + { + _contextAccesor = new() + { + HttpContext = new DefaultHttpContext(), + }; + _repository = new HttpDataRepository(_contextAccesor); + } + + [Fact] + public void Should_add_item() + { + // Arrange + const string key = "blahh"; + var toAdd = new[] { 1, 2, 3, 4 }; + + // Act + _repository.Add(key, toAdd); + + // Assert + _contextAccesor.HttpContext.Items.TryGetValue(key, out var obj).ShouldBeTrue(); + obj.ShouldNotBeNull(); + var arr = (int[])obj; + arr.ShouldNotBeNull(); + arr.ShouldContain(4); + } + + [Fact] + public void Should_get_item() + { + // Arrange + const string key = "chest"; + var data = new[] { 5435345 }; + _contextAccesor.HttpContext.Items.Add(key, data); + + // Act + var result = _repository.Get(key); + + // Assert + result.IsError.ShouldBeFalse(); + result.Data.ShouldNotBeNull(); + } +} diff --git a/test/Ocelot.UnitTests/Repository/ScopedRequestDataRepositoryTests.cs b/test/Ocelot.UnitTests/Repository/ScopedRequestDataRepositoryTests.cs deleted file mode 100644 index 40881c010..000000000 --- a/test/Ocelot.UnitTests/Repository/ScopedRequestDataRepositoryTests.cs +++ /dev/null @@ -1,74 +0,0 @@ -using Microsoft.AspNetCore.Http; -using Ocelot.Infrastructure.RequestData; -using Ocelot.Responses; - -namespace Ocelot.UnitTests.Repository; - -public class ScopedRequestDataRepositoryTests : UnitTest -{ - private readonly IRequestScopedDataRepository _requestScopedDataRepository; - private readonly IHttpContextAccessor _httpContextAccesor; - private string _key; - private object _toAdd; - private Response _result; - - public ScopedRequestDataRepositoryTests() - { - _httpContextAccesor = new HttpContextAccessor(); - _httpContextAccesor.HttpContext = new DefaultHttpContext(); - _requestScopedDataRepository = new HttpDataRepository(_httpContextAccesor); - } - - [Fact] - public void should_add_item() - { - this.Given(x => x.GivenIHaveAnItemToAdd("blahh", new[] { 1, 2, 3, 4 })) - .When(x => x.WhenIAddTheItem()) - .Then(x => x.ThenTheItemIsAdded()) - .BDDfy(); - } - - [Fact] - public void should_get_item() - { - this.Given(x => x.GivenThereIsAnItemInTheContext("chest")) - .When(x => x.WhenIGetTheItem()) - .Then(x => x.ThenTheItemIsReturned()) - .BDDfy(); - } - - private void ThenTheItemIsReturned() - { - _result.IsError.ShouldBeFalse(); - _result.Data.ShouldNotBeNull(); - } - - private void WhenIGetTheItem() - { - _result = _requestScopedDataRepository.Get(_key); - } - - private void GivenThereIsAnItemInTheContext(string key) - { - _key = key; - var data = new[] { 5435345 }; - _httpContextAccesor.HttpContext.Items.Add(key, data); - } - - private void GivenIHaveAnItemToAdd(string key, object toAdd) - { - _key = key; - _toAdd = toAdd; - } - - private void WhenIAddTheItem() - { - _requestScopedDataRepository.Add(_key, _toAdd); - } - - private void ThenTheItemIsAdded() - { - object obj; - _httpContextAccesor.HttpContext.Items.TryGetValue(_key, out obj).ShouldBeTrue(); - } -} diff --git a/test/Ocelot.UnitTests/Request/Creator/DownstreamRequestCreatorTests.cs b/test/Ocelot.UnitTests/Request/Creator/DownstreamRequestCreatorTests.cs index 01a9d0e35..ffc96b73e 100644 --- a/test/Ocelot.UnitTests/Request/Creator/DownstreamRequestCreatorTests.cs +++ b/test/Ocelot.UnitTests/Request/Creator/DownstreamRequestCreatorTests.cs @@ -1,6 +1,5 @@ using Ocelot.Infrastructure; using Ocelot.Request.Creator; -using Ocelot.Request.Middleware; namespace Ocelot.UnitTests.Request.Creator; @@ -8,8 +7,6 @@ public class DownstreamRequestCreatorTests : UnitTest { private readonly Mock _framework; private readonly DownstreamRequestCreator _downstreamRequestCreator; - private HttpRequestMessage _request; - private DownstreamRequest _result; public DownstreamRequestCreatorTests() { @@ -18,22 +15,30 @@ public DownstreamRequestCreatorTests() } [Fact] - public void should_create_downstream_request() + public async Task Should_create_downstream_request() { + // Arrange var request = new HttpRequestMessage(HttpMethod.Get, "http://www.test.com"); var content = new StringContent("test"); request.Content = content; + _framework.Setup(x => x.Get()).Returns(string.Empty); - this.Given(_ => GivenTheFrameworkIs(string.Empty)) - .And(_ => GivenTheRequestIs(request)) - .When(_ => WhenICreate()) - .Then(_ => ThenTheDownstreamRequestHasABody()) - .BDDfy(); + // Act + var result = _downstreamRequestCreator.Create(request); + + // Assert: Then The Downstream Request Has A Body + result.ShouldNotBeNull(); + result.Method.ToLower().ShouldBe("get"); + result.Scheme.ToLower().ShouldBe("http"); + result.Host.ToLower().ShouldBe("www.test.com"); + var resultContent = await result.ToHttpRequestMessage().Content.ReadAsStringAsync(); + resultContent.ShouldBe("test"); } [Fact] - public void should_remove_body_for_http_methods() + public void Should_remove_body_for_http_methods() { + // Arrange var methods = new List { HttpMethod.Get, HttpMethod.Head, HttpMethod.Delete, HttpMethod.Trace }; var request = new HttpRequestMessage(HttpMethod.Get, "http://www.test.com"); var content = new StringContent("test"); @@ -41,45 +46,17 @@ public void should_remove_body_for_http_methods() methods.ForEach(m => { - this.Given(_ => GivenTheFrameworkIs(".NET Framework")) - .And(_ => GivenTheRequestIs(request)) - .When(_ => WhenICreate()) - .Then(_ => ThenTheDownstreamRequestDoesNotHaveABody()) - .BDDfy(); - }); - } - - private void GivenTheFrameworkIs(string framework) - { - _framework.Setup(x => x.Get()).Returns(framework); - } - - private void GivenTheRequestIs(HttpRequestMessage request) - { - _request = request; - } + _framework.Setup(x => x.Get()).Returns(".NET Framework"); - private void WhenICreate() - { - _result = _downstreamRequestCreator.Create(_request); - } + // Act + var result = _downstreamRequestCreator.Create(request); - private async Task ThenTheDownstreamRequestHasABody() - { - _result.ShouldNotBeNull(); - _result.Method.ToLower().ShouldBe("get"); - _result.Scheme.ToLower().ShouldBe("http"); - _result.Host.ToLower().ShouldBe("www.test.com"); - var resultContent = await _result.ToHttpRequestMessage().Content.ReadAsStringAsync(); - resultContent.ShouldBe("test"); - } - - private void ThenTheDownstreamRequestDoesNotHaveABody() - { - _result.ShouldNotBeNull(); - _result.Method.ToLower().ShouldBe("get"); - _result.Scheme.ToLower().ShouldBe("http"); - _result.Host.ToLower().ShouldBe("www.test.com"); - _result.ToHttpRequestMessage().Content.ShouldBeNull(); + // Assert: Then The Downstream Request Does Not Have A Body + result.ShouldNotBeNull(); + result.Method.ToLower().ShouldBe("get"); + result.Scheme.ToLower().ShouldBe("http"); + result.Host.ToLower().ShouldBe("www.test.com"); + result.ToHttpRequestMessage().Content.ShouldBeNull(); + }); } } diff --git a/test/Ocelot.UnitTests/Request/DownstreamRequestInitialiserMiddlewareTests.cs b/test/Ocelot.UnitTests/Request/DownstreamRequestInitialiserMiddlewareTests.cs index b91a5358a..117762799 100644 --- a/test/Ocelot.UnitTests/Request/DownstreamRequestInitialiserMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Request/DownstreamRequestInitialiserMiddlewareTests.cs @@ -13,7 +13,7 @@ namespace Ocelot.UnitTests.Request; public class DownstreamRequestInitialiserMiddlewareTests : UnitTest { private readonly DownstreamRequestInitialiserMiddleware _middleware; - private readonly HttpContext _httpContext; + private readonly DefaultHttpContext _httpContext; private readonly Mock _next; private readonly Mock _requestMapper; private HttpRequestMessage _mappedRequest; @@ -28,8 +28,7 @@ public DownstreamRequestInitialiserMiddlewareTests() _testException = new Exception("test exception"); var loggerFactory = new Mock(); - loggerFactory - .Setup(lf => lf.CreateLogger()) + loggerFactory.Setup(lf => lf.CreateLogger()) .Returns(logger.Object); _middleware = new DownstreamRequestInitialiserMiddleware( @@ -37,44 +36,58 @@ public DownstreamRequestInitialiserMiddlewareTests() loggerFactory.Object, _requestMapper.Object, new DownstreamRequestCreator(new FrameworkDescription())); + + _httpContext.Items.UpsertDownstreamRoute(new DownstreamRouteBuilder().Build()); } [Fact] - public void Should_handle_valid_httpRequest() + public async Task Should_handle_valid_httpRequest() { - this.Given(_ => GivenTheHttpContextContainsARequest()) - .And(_ => GivenTheMapperWillReturnAMappedRequest()) - .When(_ => WhenTheMiddlewareIsInvoked()) - .Then(_ => ThenTheContexRequestIsMappedToADownstreamRequest()) - .And(_ => ThenTheDownstreamRequestIsStored()) - .And(_ => ThenTheNextMiddlewareIsInvoked()) - .And(_ => ThenTheDownstreamRequestMethodIs("GET")) - .BDDfy(); + // Arrange + GivenTheMapperWillReturnAMappedRequest(); + + // Act + await _middleware.Invoke(_httpContext); + + // Assert + ThenTheContexRequestIsMappedToADownstreamRequest(); + ThenTheDownstreamRequestIsStored(); + ThenTheNextMiddlewareIsInvoked(); + ThenTheDownstreamRequestMethodIs("GET"); } [Fact] - public void Should_map_downstream_route_method_to_downstream_request() + public async Task Should_map_downstream_route_method_to_downstream_request() { - this.Given(_ => GivenTheHttpContextContainsARequest()) - .And(_ => GivenTheMapperWillReturnAMappedRequest()) - .When(_ => WhenTheMiddlewareIsInvoked()) - .Then(_ => ThenTheContexRequestIsMappedToADownstreamRequest()) - .And(_ => ThenTheDownstreamRequestIsStored()) - .And(_ => ThenTheNextMiddlewareIsInvoked()) - .And(_ => ThenTheDownstreamRequestMethodIs("GET")) - .BDDfy(); + // Arrange + GivenTheMapperWillReturnAMappedRequest(); + + // Act + await _middleware.Invoke(_httpContext); + + // Assert + ThenTheContexRequestIsMappedToADownstreamRequest(); + ThenTheDownstreamRequestIsStored(); + ThenTheNextMiddlewareIsInvoked(); + ThenTheDownstreamRequestMethodIs("GET"); } [Fact] - public void Should_handle_mapping_failure() + public async Task Should_handle_mapping_failure() { - this.Given(_ => GivenTheHttpContextContainsARequest()) - .And(_ => GivenTheMapperWillReturnAnError()) - .When(_ => WhenTheMiddlewareIsInvoked()) - .And(_ => ThenTheDownstreamRequestIsNotStored()) - .And(_ => ThenAPipelineErrorIsStored()) - .And(_ => ThenTheNextMiddlewareIsNotInvoked()) - .BDDfy(); + // Arrange + _requestMapper.Setup(rm => rm.Map(It.IsAny(), It.IsAny())) + .Throws(_testException); + + // Act + await _middleware.Invoke(_httpContext); + + // Assert + _httpContext.Items.DownstreamRequest().ShouldBeNull(); + _httpContext.Items.Errors().Count.ShouldBe(1); + _httpContext.Items.Errors().First().ShouldBeOfType(); + _httpContext.Items.Errors().First().Message.ShouldBe($"Error when parsing incoming request, exception: {_testException}"); + _next.Verify(n => n(It.IsAny()), Times.Never); } private void ThenTheDownstreamRequestMethodIs(string expected) @@ -82,11 +95,6 @@ private void ThenTheDownstreamRequestMethodIs(string expected) _httpContext.Items.DownstreamRequest().Method.ShouldBe(expected); } - private void GivenTheHttpContextContainsARequest() - { - _httpContext.Items.UpsertDownstreamRoute(new DownstreamRouteBuilder().Build()); - } - private void GivenTheMapperWillReturnAMappedRequest() { _mappedRequest = new HttpRequestMessage(HttpMethod.Get, "http://www.bbc.co.uk"); @@ -96,18 +104,6 @@ private void GivenTheMapperWillReturnAMappedRequest() .Returns(_mappedRequest); } - private void GivenTheMapperWillReturnAnError() - { - _requestMapper - .Setup(rm => rm.Map(It.IsAny(), It.IsAny())) - .Throws(_testException); - } - - private async Task WhenTheMiddlewareIsInvoked() - { - await _middleware.Invoke(_httpContext); - } - private void ThenTheContexRequestIsMappedToADownstreamRequest() { _requestMapper.Verify(rm => rm.Map(_httpContext.Request, _httpContext.Items.DownstreamRoute()), Times.Once); @@ -118,25 +114,8 @@ private void ThenTheDownstreamRequestIsStored() _httpContext.Items.DownstreamRequest().ShouldNotBeNull(); } - private void ThenTheDownstreamRequestIsNotStored() - { - _httpContext.Items.DownstreamRequest().ShouldBeNull(); - } - - private void ThenAPipelineErrorIsStored() - { - _httpContext.Items.Errors().Count.ShouldBe(1); - _httpContext.Items.Errors().First().ShouldBeOfType(); - _httpContext.Items.Errors().First().Message.ShouldBe($"Error when parsing incoming request, exception: {_testException}"); - } - private void ThenTheNextMiddlewareIsInvoked() { _next.Verify(n => n(_httpContext), Times.Once); } - - private void ThenTheNextMiddlewareIsNotInvoked() - { - _next.Verify(n => n(It.IsAny()), Times.Never); - } } diff --git a/test/Ocelot.UnitTests/Request/DownstreamRequestTests.cs b/test/Ocelot.UnitTests/Request/DownstreamRequestTests.cs index 0e2cd7cfb..b370188b4 100644 --- a/test/Ocelot.UnitTests/Request/DownstreamRequestTests.cs +++ b/test/Ocelot.UnitTests/Request/DownstreamRequestTests.cs @@ -5,12 +5,19 @@ namespace Ocelot.UnitTests.Request; public class DownstreamRequestTests { [Fact] - public void should_have_question_mark_with_question_mark_prefixed() + public void Should_have_question_mark_with_question_mark_prefixed() { - var httpRequestMessage = new HttpRequestMessage(); - httpRequestMessage.RequestUri = new Uri("https://example.com/a?b=c"); - var downstreamRequest = new DownstreamRequest(httpRequestMessage); + // Arrange + var requestMessage = new HttpRequestMessage + { + RequestUri = new Uri("https://example.com/a?b=c"), + }; + var downstreamRequest = new DownstreamRequest(requestMessage); + + // Act var result = downstreamRequest.ToHttpRequestMessage(); + + // Assert result.RequestUri.Query.ShouldBe("?b=c"); } } diff --git a/test/Ocelot.UnitTests/Request/Mapper/RequestMapperTests.cs b/test/Ocelot.UnitTests/Request/Mapper/RequestMapperTests.cs index dd81a1534..10edad23a 100644 --- a/test/Ocelot.UnitTests/Request/Mapper/RequestMapperTests.cs +++ b/test/Ocelot.UnitTests/Request/Mapper/RequestMapperTests.cs @@ -19,7 +19,7 @@ public class RequestMapperTests : UnitTest public RequestMapperTests() { - HttpContext httpContext = new DefaultHttpContext(); + var httpContext = new DefaultHttpContext(); _inputRequest = httpContext.Request; _requestMapper = new RequestMapper(); } @@ -31,31 +31,37 @@ public RequestMapperTests() [InlineData("http", "myusername:mypassword@abc.co.uk", null, null, "http://myusername:mypassword@abc.co.uk/")] [InlineData("http", "點看.com", null, null, "http://xn--c1yn36f.com/")] [InlineData("http", "xn--c1yn36f.com", null, null, "http://xn--c1yn36f.com/")] - public void Should_map_valid_request_uri(string scheme, string host, string path, string queryString, - string expectedUri) - { - this.Given(_ => GivenTheInputRequestHasMethod("GET")) - .And(_ => GivenTheInputRequestHasScheme(scheme)) - .And(_ => GivenTheInputRequestHasHost(host)) - .And(_ => GivenTheInputRequestHasPath(path)) - .And(_ => GivenTheInputRequestHasQueryString(queryString)) - .And(_ => GivenTheDownstreamRoute()) - .When(_ => WhenMapped()) - .And(_ => ThenTheMappedRequestHasUri(expectedUri)) - .BDDfy(); + public void Should_map_valid_request_uri(string scheme, string host, string path, string queryString, string expectedUri) + { + // Arrange + _inputRequest.Method = "GET"; + _inputRequest.Scheme = scheme; + GivenTheInputRequestHasHost(host); + GivenTheInputRequestHasPath(path); + GivenTheInputRequestHasQueryString(queryString); + GivenTheDownstreamRoute(); + + // Act + WhenMapped(); + + // Assert + Assert.NotNull(_mappedRequest.RequestUri); + _mappedRequest.RequestUri.OriginalString.ShouldBe(expectedUri); } [Theory] [InlineData("ftp", "google.com", "/abc/DEF", "?a=1&b=2")] public void Should_error_on_unsupported_request_uri(string scheme, string host, string path, string queryString) { - this.Given(_ => GivenTheInputRequestHasMethod("GET")) - .And(_ => GivenTheInputRequestHasScheme(scheme)) - .And(_ => GivenTheInputRequestHasHost(host)) - .And(_ => GivenTheInputRequestHasPath(path)) - .And(_ => GivenTheInputRequestHasQueryString(queryString)) - .Then(_ => ThenMapThrowsException()) - .BDDfy(); + // Arrange + _inputRequest.Method = "GET"; + _inputRequest.Scheme = scheme; + GivenTheInputRequestHasHost(host); + GivenTheInputRequestHasPath(path); + GivenTheInputRequestHasQueryString(queryString); + + // Act, Assert + Assert.Throws(() => _requestMapper.Map(_inputRequest, _downstreamRoute)); } [Theory] @@ -64,12 +70,16 @@ public void Should_error_on_unsupported_request_uri(string scheme, string host, [InlineData("WHATEVER")] public void Should_map_method(string method) { - this.Given(_ => GivenTheInputRequestHasMethod(method)) - .And(_ => GivenTheInputRequestHasAValidUri()) - .And(_ => GivenTheDownstreamRoute()) - .When(_ => WhenMapped()) - .And(_ => ThenTheMappedRequestHasMethod(method)) - .BDDfy(); + // Arrange + _inputRequest.Method = method; + GivenTheInputRequestHasAValidUri(); + GivenTheDownstreamRoute(); + + // Act + WhenMapped(); + + // Assert + _mappedRequest.Method.ToString().ShouldBe(method); } [Theory] @@ -78,200 +88,241 @@ public void Should_map_method(string method) [InlineData("POST", "POST")] public void Should_use_downstream_route_method_if_set(string input, string expected) { - this.Given(_ => GivenTheInputRequestHasMethod("GET")) - .And(_ => GivenTheDownstreamRouteMethodIs(input)) - .And(_ => GivenTheInputRequestHasAValidUri()) - .When(_ => WhenMapped()) - .And(_ => ThenTheMappedRequestHasMethod(expected)) - .BDDfy(); + // Arrange + _inputRequest.Method = "GET"; + _downstreamRoute = new DownstreamRouteBuilder() + .WithDownStreamHttpMethod(input) + .WithDownstreamHttpVersion(new Version("1.1")) + .Build(); + GivenTheInputRequestHasAValidUri(); + + // Act + WhenMapped(); + + // Assert + _mappedRequest.Method.ToString().ShouldBe(expected); } [Fact] public void Should_map_all_headers() { - this.Given(_ => GivenTheInputRequestHasHeaders()) - .And(_ => GivenTheInputRequestHasMethod("GET")) - .And(_ => GivenTheInputRequestHasAValidUri()) - .And(_ => GivenTheDownstreamRoute()) - .When(_ => WhenMapped()) - .And(_ => ThenTheMappedRequestHasEachHeader()) - .BDDfy(); + // Arrange: Given The Input Request Has Headers + var abcVals = new[] { "123", "456" }; + var defVals = new[] { "789", "012" }; + _inputHeaders = new() + { + new("abc", new StringValues(abcVals)), + new("def", new StringValues(defVals)), + }; + + foreach (var inputHeader in _inputHeaders) + { + _inputRequest.Headers.Add(inputHeader); + } + + _inputRequest.Method = "GET"; + GivenTheInputRequestHasAValidUri(); + GivenTheDownstreamRoute(); + + // Act + WhenMapped(); + + // Assert: Then The Mapped Request Has Each Header + _mappedRequest.Headers.Count().ShouldBe(_inputHeaders.Count); + foreach (var header in _mappedRequest.Headers) + { + var inputHeader = _inputHeaders.First(h => h.Key == header.Key); + inputHeader.ShouldNotBe(default); + inputHeader.Value.Count.ShouldBe(header.Value.Count()); + foreach (var inputHeaderValue in inputHeader.Value) + { + Assert.Contains(header.Value, v => v == inputHeaderValue); + } + } } [Fact] public void Should_handle_no_headers() { - this.Given(_ => GivenTheInputRequestHasNoHeaders()) - .And(_ => GivenTheInputRequestHasMethod("GET")) - .And(_ => GivenTheInputRequestHasAValidUri()) - .And(_ => GivenTheDownstreamRoute()) - .When(_ => WhenMapped()) - .And(_ => ThenTheMappedRequestHasNoHeaders()) - .BDDfy(); + // Arrange + _inputRequest.Headers.Clear(); + _inputRequest.Method = "GET"; + GivenTheInputRequestHasAValidUri(); + GivenTheDownstreamRoute(); + + // Act + WhenMapped(); + + // Assert + _mappedRequest.Headers.Count().ShouldBe(0); } [Theory] [Trait("PR", "1972")] [InlineData("GET")] [InlineData("POST")] - public void Should_map_content(string method) - { - this.Given(_ => GivenTheInputRequestHasContent("This is my content")) - .And(_ => GivenTheInputRequestHasMethod(method)) - .And(_ => GivenTheInputRequestHasAValidUri()) - .And(_ => GivenTheDownstreamRoute()) - .When(_ => WhenMapped()) - .And(_ => ThenTheMappedRequestHasContent("This is my content")) - .And(_ => ThenTheMappedRequestHasContentLength("This is my content".Length)) - .BDDfy(); + public async Task Should_map_content(string method) + { + // Arrange + GivenTheInputRequestHasContent("This is my content"); + _inputRequest.Method = method; + GivenTheInputRequestHasAValidUri(); + GivenTheDownstreamRoute(); + + // Act + WhenMapped(); + + // Assert + await ThenTheMappedRequestHasContent("This is my content"); + ThenTheMappedRequestHasContentLength("This is my content".Length); } [Fact] [Trait("PR", "1972")] - public void Should_map_chucked_content() - { - this.Given(_ => GivenTheInputRequestHasChunkedContent("This", " is my content")) - .And(_ => GivenTheInputRequestHasMethod("POST")) - .And(_ => GivenTheInputRequestHasAValidUri()) - .And(_ => GivenTheDownstreamRoute()) - .When(_ => WhenMapped()) - .And(_ => ThenTheMappedRequestHasContent("This is my content")) - .And(_ => ThenTheMappedRequestHasNoContentLength()) - .BDDfy(); + public async Task Should_map_chucked_content() + { + // Arrange + GivenTheInputRequestHasChunkedContent("This", " is my content"); + _inputRequest.Method = "POST"; + GivenTheInputRequestHasAValidUri(); + GivenTheDownstreamRoute(); + + // Act + WhenMapped(); + + // Assert + await ThenTheMappedRequestHasContent("This is my content"); + _mappedRequest.Headers.TryGetValues(HeaderNames.ContentLength, out _).ShouldBeFalse(); // ThenTheMappedRequestHasNoContentLength } [Fact] [Trait("PR", "1972")] - public void Should_map_empty_content() - { - this.Given(_ => GivenTheInputRequestHasContent("")) - .And(_ => GivenTheInputRequestHasMethod("POST")) - .And(_ => GivenTheInputRequestHasAValidUri()) - .And(_ => GivenTheDownstreamRoute()) - .When(_ => WhenMapped()) - .And(_ => ThenTheMappedRequestHasContent("")) - .And(_ => ThenTheMappedRequestHasContentLength(0)) - .BDDfy(); + public async Task Should_map_empty_content() + { + // Arrange + GivenTheInputRequestHasContent(""); + _inputRequest.Method = "POST"; + GivenTheInputRequestHasAValidUri(); + GivenTheDownstreamRoute(); + + // Act + WhenMapped(); + + // Assert + await ThenTheMappedRequestHasContent(""); + ThenTheMappedRequestHasContentLength(0); } [Fact] [Trait("PR", "1972")] - public void Should_map_empty_chucked_content() - { - this.Given(_ => GivenTheInputRequestHasChunkedContent()) - .And(_ => GivenTheInputRequestHasMethod("POST")) - .And(_ => GivenTheInputRequestHasAValidUri()) - .And(_ => GivenTheDownstreamRoute()) - .When(_ => WhenMapped()) - .And(_ => ThenTheMappedRequestHasContent("")) - .And(_ => ThenTheMappedRequestHasNoContentLength()) - .BDDfy(); + public async Task Should_map_empty_chucked_content() + { + // Arrange + GivenTheInputRequestHasChunkedContent(); + _inputRequest.Method = "POST"; + GivenTheInputRequestHasAValidUri(); + GivenTheDownstreamRoute(); + + // Act + WhenMapped(); + + // Assert + await ThenTheMappedRequestHasContent(""); + _mappedRequest.Headers.TryGetValues(HeaderNames.ContentLength, out _).ShouldBeFalse(); // ThenTheMappedRequestHasNoContentLength } [Fact] public void Should_handle_no_content() { - this.Given(_ => GivenTheInputRequestHasNullContent()) - .And(_ => GivenTheInputRequestHasMethod("GET")) - .And(_ => GivenTheInputRequestHasAValidUri()) - .And(_ => GivenTheDownstreamRoute()) - .When(_ => WhenMapped()) - .And(_ => ThenTheMappedRequestHasNoContent()) - .BDDfy(); + // Arrange + _inputRequest.Body = null!; + _inputRequest.Method = "GET"; + GivenTheInputRequestHasAValidUri(); + GivenTheDownstreamRoute(); + + // Act + WhenMapped(); + + // Assert + _mappedRequest.Content.ShouldBeNull(); } [Fact] public void Should_handle_no_content_type() { - this.Given(_ => GivenTheInputRequestHasNoContentType()) - .And(_ => GivenTheInputRequestHasMethod("GET")) - .And(_ => GivenTheInputRequestHasAValidUri()) - .And(_ => GivenTheDownstreamRoute()) - .When(_ => WhenMapped()) - .And(_ => ThenTheMappedRequestHasNoContent()) - .BDDfy(); + // Arrange + _inputRequest.ContentType = null; + _inputRequest.Method = "GET"; + GivenTheInputRequestHasAValidUri(); + GivenTheDownstreamRoute(); + + // Act + WhenMapped(); + + // Assert + _mappedRequest.Content.ShouldBeNull(); } [Fact] public void Should_handle_no_content_length() { - this.Given(_ => GivenTheInputRequestHasNoContentLength()) - .And(_ => GivenTheInputRequestHasMethod("GET")) - .And(_ => GivenTheInputRequestHasAValidUri()) - .And(_ => GivenTheDownstreamRoute()) - .When(_ => WhenMapped()) - .And(_ => ThenTheMappedRequestHasNoContent()) - .BDDfy(); + // Arrange + _inputRequest.ContentLength = null; + _inputRequest.Method = "GET"; + GivenTheInputRequestHasAValidUri(); + GivenTheDownstreamRoute(); + + // Act + WhenMapped(); + + // Assert + _mappedRequest.Content.ShouldBeNull(); } [Fact] public void Should_map_content_headers() { + // Arrange var bytes = Encoding.UTF8.GetBytes("some md5"); var md5Bytes = MD5.HashData(bytes); - this.Given(_ => GivenTheInputRequestHasContent("This is my content")) - .And(_ => GivenTheContentTypeIs("application/json")) - .And(_ => GivenTheContentEncodingIs("gzip, compress")) - .And(_ => GivenTheContentLanguageIs("english")) - .And(_ => GivenTheContentLocationIs("/my-receipts/38")) - .And(_ => GivenTheContentRangeIs("bytes 1-2/*")) - .And(_ => GivenTheContentDispositionIs("inline")) - .And(_ => GivenTheContentMD5Is(md5Bytes)) - .And(_ => GivenTheInputRequestHasMethod("GET")) - .And(_ => GivenTheInputRequestHasAValidUri()) - .And(_ => GivenTheDownstreamRoute()) - .When(_ => WhenMapped()) - .And(_ => ThenTheMappedRequestHasContentTypeHeader("application/json")) - .And(_ => ThenTheMappedRequestHasContentEncodingHeader("gzip", "compress")) - .And(_ => ThenTheMappedRequestHasContentLanguageHeader("english")) - .And(_ => ThenTheMappedRequestHasContentLocationHeader("/my-receipts/38")) - .And(_ => ThenTheMappedRequestHasContentMD5Header(md5Bytes)) - .And(_ => ThenTheMappedRequestHasContentRangeHeader()) - .And(_ => ThenTheMappedRequestHasContentDispositionHeader("inline")) - .And(_ => ThenTheContentHeadersAreNotAddedToNonContentHeaders()) - .BDDfy(); - } - - [Fact] - public void should_not_add_content_headers() - { - this.Given(_ => GivenTheInputRequestHasContent("This is my content")) - .And(_ => GivenTheContentTypeIs("application/json")) - .And(_ => GivenTheInputRequestHasMethod("POST")) - .And(_ => GivenTheInputRequestHasAValidUri()) - .And(_ => GivenTheDownstreamRoute()) - .When(_ => WhenMapped()) - .And(_ => ThenTheMappedRequestHasContentTypeHeader("application/json")) - .And(_ => ThenTheOtherContentTypeHeadersAreNotMapped()) - .BDDfy(); - } - - private void GivenTheDownstreamRouteMethodIs(string input) - { - _downstreamRoute = new DownstreamRouteBuilder() - .WithDownStreamHttpMethod(input) - .WithDownstreamHttpVersion(new Version("1.1")).Build(); - } - - private void GivenTheDownstreamRoute() - { - _downstreamRoute = new DownstreamRouteBuilder() - .WithDownstreamHttpVersion(new Version("1.1")).Build(); - } - - private void GivenTheInputRequestHasNoContentLength() - { - _inputRequest.ContentLength = null; - } - - private void GivenTheInputRequestHasNoContentType() - { - _inputRequest.ContentType = null; - } - - private void ThenTheContentHeadersAreNotAddedToNonContentHeaders() - { + GivenTheInputRequestHasContent("This is my content"); + _inputRequest.ContentType = "application/json"; + _inputRequest.Headers.Append("Content-Encoding", "gzip, compress"); + _inputRequest.Headers.Append("Content-Language", "english"); + _inputRequest.Headers.Append("Content-Location", "/my-receipts/38"); + _inputRequest.Headers.Append("Content-Range", "bytes 1-2/*"); + _inputRequest.Headers.Append("Content-Disposition", "inline"); + var base64 = Convert.ToBase64String(md5Bytes); + _inputRequest.Headers.Append("Content-MD5", base64); + _inputRequest.Method = "GET"; + GivenTheInputRequestHasAValidUri(); + GivenTheDownstreamRoute(); + + // Act + WhenMapped(); + + // Assert + ThenTheMappedRequestHasContentTypeHeader("application/json"); + Assert.NotNull(_mappedRequest.Content); + _mappedRequest.Content.Headers.ContentEncoding.ToArray()[0].ShouldBe("gzip"); + _mappedRequest.Content.Headers.ContentEncoding.ToArray()[1].ShouldBe("compress"); + Assert.NotNull(_mappedRequest.Content); + _mappedRequest.Content.Headers.ContentLanguage.First().ShouldBe("english"); + Assert.NotNull(_mappedRequest.Content); + Assert.NotNull(_mappedRequest.Content.Headers.ContentLocation); + _mappedRequest.Content.Headers.ContentLocation.OriginalString.ShouldBe("/my-receipts/38"); + Assert.NotNull(_mappedRequest.Content); + _mappedRequest.Content.Headers.ContentMD5.ShouldBe(md5Bytes); + Assert.NotNull(_mappedRequest.Content); + Assert.NotNull(_mappedRequest.Content.Headers.ContentRange); + _mappedRequest.Content.Headers.ContentRange.From.ShouldBe(1); + _mappedRequest.Content.Headers.ContentRange.To.ShouldBe(2); + Assert.NotNull(_mappedRequest.Content); + Assert.NotNull(_mappedRequest.Content.Headers.ContentDisposition); + _mappedRequest.Content.Headers.ContentDisposition.DispositionType.ShouldBe("inline"); + + // Assert: Then The Content-* Headers Are Not Added To Non Content Headers _mappedRequest.Headers.ShouldNotContain(x => x.Key == "Content-Disposition"); _mappedRequest.Headers.ShouldNotContain(x => x.Key == "Content-ContentMD5"); _mappedRequest.Headers.ShouldNotContain(x => x.Key == "Content-ContentRange"); @@ -282,8 +333,23 @@ private void ThenTheContentHeadersAreNotAddedToNonContentHeaders() _mappedRequest.Headers.ShouldNotContain(x => x.Key == "Content-Type"); } - private void ThenTheOtherContentTypeHeadersAreNotMapped() - { + [Fact] + public void Should_not_add_content_headers() + { + // Arrange + GivenTheInputRequestHasContent("This is my content"); + _inputRequest.ContentType = "application/json"; + _inputRequest.Method = "POST"; + GivenTheInputRequestHasAValidUri(); + GivenTheDownstreamRoute(); + + // Act + WhenMapped(); + + // Assert + ThenTheMappedRequestHasContentTypeHeader("application/json"); + + // Assert: Then The Other Content Type Headers Are Not Mapped Assert.NotNull(_mappedRequest.Content); _mappedRequest.Content.Headers.ContentDisposition.ShouldBeNull(); _mappedRequest.Content.Headers.ContentMD5.ShouldBeNull(); @@ -293,81 +359,10 @@ private void ThenTheOtherContentTypeHeadersAreNotMapped() _mappedRequest.Content.Headers.ContentLocation.ShouldBeNull(); } - private void ThenTheMappedRequestHasContentDispositionHeader(string expected) - { - Assert.NotNull(_mappedRequest.Content); - Assert.NotNull(_mappedRequest.Content.Headers.ContentDisposition); - _mappedRequest.Content.Headers.ContentDisposition.DispositionType.ShouldBe(expected); - } - - private void GivenTheContentDispositionIs(string input) - { - _inputRequest.Headers.Append("Content-Disposition", input); - } - - private void ThenTheMappedRequestHasContentMD5Header(byte[] expected) - { - Assert.NotNull(_mappedRequest.Content); - _mappedRequest.Content.Headers.ContentMD5.ShouldBe(expected); - } - - private void GivenTheContentMD5Is(byte[] input) - { - var base64 = Convert.ToBase64String(input); - _inputRequest.Headers.Append("Content-MD5", base64); - } - - private void ThenTheMappedRequestHasContentRangeHeader() - { - Assert.NotNull(_mappedRequest.Content); - Assert.NotNull(_mappedRequest.Content.Headers.ContentRange); - _mappedRequest.Content.Headers.ContentRange.From.ShouldBe(1); - _mappedRequest.Content.Headers.ContentRange.To.ShouldBe(2); - } - - private void GivenTheContentRangeIs(string input) - { - _inputRequest.Headers.Append("Content-Range", input); - } - - private void ThenTheMappedRequestHasContentLocationHeader(string expected) - { - Assert.NotNull(_mappedRequest.Content); - Assert.NotNull(_mappedRequest.Content.Headers.ContentLocation); - _mappedRequest.Content.Headers.ContentLocation.OriginalString.ShouldBe(expected); - } - - private void GivenTheContentLocationIs(string input) - { - _inputRequest.Headers.Append("Content-Location", input); - } - - private void ThenTheMappedRequestHasContentLanguageHeader(string expected) - { - Assert.NotNull(_mappedRequest.Content); - _mappedRequest.Content.Headers.ContentLanguage.First().ShouldBe(expected); - } - - private void GivenTheContentLanguageIs(string input) - { - _inputRequest.Headers.Append("Content-Language", input); - } - - private void ThenTheMappedRequestHasContentEncodingHeader(string expected, string expectedTwo) - { - Assert.NotNull(_mappedRequest.Content); - _mappedRequest.Content.Headers.ContentEncoding.ToArray()[0].ShouldBe(expected); - _mappedRequest.Content.Headers.ContentEncoding.ToArray()[1].ShouldBe(expectedTwo); - } - - private void GivenTheContentEncodingIs(string input) - { - _inputRequest.Headers.Append("Content-Encoding", input); - } - - private void GivenTheContentTypeIs(string contentType) + private void GivenTheDownstreamRoute() { - _inputRequest.ContentType = contentType; + _downstreamRoute = new DownstreamRouteBuilder() + .WithDownstreamHttpVersion(new Version("1.1")).Build(); } private void ThenTheMappedRequestHasContentTypeHeader(string expected) @@ -377,22 +372,6 @@ private void ThenTheMappedRequestHasContentTypeHeader(string expected) _mappedRequest.Content.Headers.ContentType.MediaType.ShouldBe(expected); } - private void ThenTheMappedRequestHasContentSize(long expected) - { - Assert.NotNull(_mappedRequest.Content); - _mappedRequest.Content.Headers.ContentLength.ShouldBe(expected); - } - - private void GivenTheInputRequestHasMethod(string method) - { - _inputRequest.Method = method; - } - - private void GivenTheInputRequestHasScheme(string scheme) - { - _inputRequest.Scheme = scheme; - } - private void GivenTheInputRequestHasHost(string host) { _inputRequest.Host = new HostString(host); @@ -416,29 +395,10 @@ private void GivenTheInputRequestHasQueryString(string querystring) private void GivenTheInputRequestHasAValidUri() { - GivenTheInputRequestHasScheme("http"); + _inputRequest.Scheme = "http"; GivenTheInputRequestHasHost("www.google.com"); } - private void GivenTheInputRequestHasHeaders() - { - _inputHeaders = new() - { - new("abc", new StringValues(new string[] { "123", "456" })), - new("def", new StringValues(new string[] { "789", "012" })), - }; - - foreach (var inputHeader in _inputHeaders) - { - _inputRequest.Headers.Add(inputHeader); - } - } - - private void GivenTheInputRequestHasNoHeaders() - { - _inputRequest.Headers.Clear(); - } - private void GivenTheInputRequestHasContent(string content) { _inputRequest.ContentLength = content.Length; @@ -453,52 +413,11 @@ private void GivenTheInputRequestHasChunkedContent(params string[] chunks) _inputRequest.Headers.TransferEncoding = "chunked"; } - private void GivenTheInputRequestHasNullContent() - { - _inputRequest.Body = null!; - } - private void WhenMapped() { _mappedRequest = _requestMapper.Map(_inputRequest, _downstreamRoute); } - private void ThenMapThrowsException() - { - Assert.Throws(() => _requestMapper.Map(_inputRequest, _downstreamRoute)); - } - - private void ThenTheMappedRequestHasUri(string expectedUri) - { - Assert.NotNull(_mappedRequest.RequestUri); - _mappedRequest.RequestUri.OriginalString.ShouldBe(expectedUri); - } - - private void ThenTheMappedRequestHasMethod(string expectedMethod) - { - _mappedRequest.Method.ToString().ShouldBe(expectedMethod); - } - - private void ThenTheMappedRequestHasEachHeader() - { - _mappedRequest.Headers.Count().ShouldBe(_inputHeaders.Count); - foreach (var header in _mappedRequest.Headers) - { - var inputHeader = _inputHeaders.First(h => h.Key == header.Key); - inputHeader.ShouldNotBe(default); - inputHeader.Value.Count.ShouldBe(header.Value.Count()); - foreach (var inputHeaderValue in inputHeader.Value) - { - Assert.Contains(header.Value, v => v == inputHeaderValue); - } - } - } - - private void ThenTheMappedRequestHasNoHeaders() - { - _mappedRequest.Headers.Count().ShouldBe(0); - } - private async Task ThenTheMappedRequestHasContent(string expectedContent) { Assert.NotNull(_mappedRequest.Content); @@ -511,19 +430,4 @@ private void ThenTheMappedRequestHasContentLength(long expectedLength) Assert.NotNull(_mappedRequest.Content); _mappedRequest.Content.Headers.ContentLength.ShouldBe(expectedLength); } - - private void ThenTheMappedRequestHasNoContentLength() - { - _mappedRequest.Headers.TryGetValues(HeaderNames.ContentLength, out _).ShouldBeFalse(); - } - - private void ThenTheMappedRequestHasNoContent() - { - _mappedRequest.Content.ShouldBeNull(); - } - - private void ThenTheMappedRequestIsNull() - { - _mappedRequest.ShouldBeNull(); - } } diff --git a/test/Ocelot.UnitTests/Request/Mapper/StreamHttpContentTests.cs b/test/Ocelot.UnitTests/Request/Mapper/StreamHttpContentTests.cs index 105bb85de..89e5bce6d 100644 --- a/test/Ocelot.UnitTests/Request/Mapper/StreamHttpContentTests.cs +++ b/test/Ocelot.UnitTests/Request/Mapper/StreamHttpContentTests.cs @@ -7,7 +7,7 @@ namespace Ocelot.UnitTests.Request.Mapper; public class StreamHttpContentTests { - private readonly HttpContext _httpContext; + private readonly DefaultHttpContext _httpContext; private const string PayLoad = "[{\"_id\":\"65416ef7eafdf7953c4d7319\",\"index\":0,\"guid\":\"254b515d-0569-494d-9bc8-e21c8bd0365e\",\"isActive\":false,\"balance\":\"$1,225.59\",\"picture\":\"http://placehold.it/32x32\",\"age\":26,\"eyeColor\":\"blue\",\"name\":\"FayHatfield\",\"gender\":\"female\",\"company\":\"VIASIA\",\"email\":\"fayhatfield@viasia.com\",\"phone\":\"+1(970)416-2792\",\"address\":\"768MontroseAvenue,Mansfield,NewMexico,8890\",\"about\":\"Duisoccaecatdoloreeiusmoddoipsummollitaliquipnostrudqui.Cillumdoexercitationexercitationexcepteurincididuntadipisicingminimconsecteturofficiaanimdoloreincididuntlaborealiqua.Tempordoloreirurecillumadnullasuntoccaecatsitnulladosit.Sitnostrudullamcolaborisvelitvelitetofficiasitenimipsumaute.\\r\\n\",\"registered\":\"2023-07-03T03:10:08-02:00\",\"latitude\":0.117661,\"longitude\":-65.570177,\"tags\":[\"Lorem\",\"consequat\",\"consectetur\",\"pariatur\",\"fugiat\",\"est\",\"mollit\"],\"friends\":[{\"id\":0,\"name\":\"LynetteMelendez\"},{\"id\":1,\"name\":\"DrakeMay\"},{\"id\":2,\"name\":\"JenningsConrad\"}],\"greeting\":\"Hello,FayHatfield!Youhave3unreadmessages.\",\"favoriteFruit\":\"apple\"}]"; @@ -20,10 +20,14 @@ public StreamHttpContentTests() [Fact] public async Task Copy_body_to_stream_and_stream_content_should_match_payload() { + // Arrange var sut = StreamHttpContentFactory(); using var stream = new MemoryStream(); + + // Act await sut.CopyToAsync(stream); + // Assert stream.Position = 0; var result = Encoding.UTF8.GetString(stream.ToArray()); result.ShouldBe(PayLoad); @@ -32,12 +36,17 @@ public async Task Copy_body_to_stream_and_stream_content_should_match_payload() [Fact] public async Task Copy_body_to_stream_with_unknown_length_and_stream_content_should_match_payload() { + // Arrange var bytes = Encoding.UTF8.GetBytes(PayLoad); using var inputStream = new MemoryStream(bytes); using var outputStream = new MemoryStream(); + + // Act await CopyAsyncTest( new StreamHttpContent(_httpContext), new object[] { inputStream, outputStream, StreamHttpContent.UnknownLength, false, CancellationToken.None }); + + // Assert inputStream.Position = 0; outputStream.Position = 0; var result = Encoding.UTF8.GetString(outputStream.ToArray()); @@ -47,12 +56,17 @@ await CopyAsyncTest( [Fact] public async Task Copy_body_to_stream_with_body_length_and_stream_content_should_match_payload() { + // Arrange var bytes = Encoding.UTF8.GetBytes(PayLoad); using var inputStream = new MemoryStream(bytes); using var outputStream = new MemoryStream(); + + // Act await CopyAsyncTest( new StreamHttpContent(_httpContext), new object[] { inputStream, outputStream, bytes.Length, false, CancellationToken.None }); + + // Assert inputStream.Position = 0; outputStream.Position = 0; var result = Encoding.UTF8.GetString(outputStream.ToArray()); @@ -62,9 +76,12 @@ await CopyAsyncTest( [Fact] public async Task Should_throw_if_passed_body_length_does_not_match_real_body_length() { + // Arrange var bytes = Encoding.UTF8.GetBytes(PayLoad); using var inputStream = new MemoryStream(bytes); using var outputStream = new MemoryStream(); + + // Act, Assert await Assert.ThrowsAsync(async () => await CopyAsyncTest( new StreamHttpContent(_httpContext), diff --git a/test/Ocelot.UnitTests/RequestId/RequestIdMiddlewareTests.cs b/test/Ocelot.UnitTests/RequestId/RequestIdMiddlewareTests.cs index d6692071b..71a6e96af 100644 --- a/test/Ocelot.UnitTests/RequestId/RequestIdMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/RequestId/RequestIdMiddlewareTests.cs @@ -14,14 +14,12 @@ namespace Ocelot.UnitTests.RequestId; public class RequestIdMiddlewareTests : UnitTest { private readonly HttpRequestMessage _downstreamRequest; - private string _value; - private string _key; private readonly Mock _loggerFactory; private readonly Mock _logger; private readonly RequestIdMiddleware _middleware; private readonly RequestDelegate _next; private readonly Mock _repo; - private readonly HttpContext _httpContext; + private readonly DefaultHttpContext _httpContext; public RequestIdMiddlewareTests() { _httpContext = new DefaultHttpContext(); @@ -40,8 +38,9 @@ public RequestIdMiddlewareTests() } [Fact] - public void should_pass_down_request_id_from_upstream_request() + public async Task Should_pass_down_request_id_from_upstream_request() { + // Arrange var downstreamRoute = new DownstreamRouteHolder(new List(), new RouteBuilder() .WithDownstreamRoute(new DownstreamRouteBuilder() @@ -54,17 +53,21 @@ public void should_pass_down_request_id_from_upstream_request() var requestId = Guid.NewGuid().ToString(); - this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) - .And(x => GivenThereIsNoGlobalRequestId()) - .And(x => x.GivenTheRequestIdIsAddedToTheRequest("LSRequestId", requestId)) - .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.ThenTheTraceIdIs(requestId)) - .BDDfy(); + GivenTheDownStreamRouteIs(downstreamRoute); + GivenThereIsNoGlobalRequestId(); + _httpContext.Request.Headers.TryAdd("LSRequestId", requestId); + + // Act + await _middleware.Invoke(_httpContext); + + // Assert + ThenTheTraceIdIs(requestId); } [Fact] - public void should_add_request_id_when_not_on_upstream_request() + public async Task Should_add_request_id_when_not_on_upstream_request() { + // Arrange var downstreamRoute = new DownstreamRouteHolder(new List(), new RouteBuilder() .WithDownstreamRoute(new DownstreamRouteBuilder() @@ -75,16 +78,21 @@ public void should_add_request_id_when_not_on_upstream_request() .WithUpstreamHttpMethod(new List { "Get" }) .Build()); - this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) - .And(x => GivenThereIsNoGlobalRequestId()) - .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.ThenTheTraceIdIsAnything()) - .BDDfy(); + GivenTheDownStreamRouteIs(downstreamRoute); + GivenThereIsNoGlobalRequestId(); + + // Act + await _middleware.Invoke(_httpContext); + + // Assert: Then The TraceId Is Anything + _httpContext.Response.Headers.TryGetValue("LSRequestId", out var value); + value.First().ShouldNotBeNullOrEmpty(); } [Fact] - public void should_add_request_id_scoped_repo_for_logging_later() + public async Task Should_add_request_id_scoped_repo_for_logging_later() { + // Arrange var downstreamRoute = new DownstreamRouteHolder(new List(), new RouteBuilder() .WithDownstreamRoute(new DownstreamRouteBuilder() @@ -97,18 +105,22 @@ public void should_add_request_id_scoped_repo_for_logging_later() var requestId = Guid.NewGuid().ToString(); - this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) - .And(x => GivenThereIsNoGlobalRequestId()) - .And(x => x.GivenTheRequestIdIsAddedToTheRequest("LSRequestId", requestId)) - .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.ThenTheTraceIdIs(requestId)) - .And(x => ThenTheRequestIdIsSaved()) - .BDDfy(); + GivenTheDownStreamRouteIs(downstreamRoute); + GivenThereIsNoGlobalRequestId(); + _httpContext.Request.Headers.TryAdd("LSRequestId", requestId); + + // Act + await _middleware.Invoke(_httpContext); + + // Assert + ThenTheTraceIdIs(requestId); + _repo.Verify(x => x.Add("RequestId", requestId), Times.Once); } [Fact] - public void should_update_request_id_scoped_repo_for_logging_later() + public async Task Should_update_request_id_scoped_repo_for_logging_later() { + // Arrange var downstreamRoute = new DownstreamRouteHolder(new List(), new RouteBuilder() .WithDownstreamRoute(new DownstreamRouteBuilder() @@ -121,18 +133,22 @@ public void should_update_request_id_scoped_repo_for_logging_later() var requestId = Guid.NewGuid().ToString(); - this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) - .And(x => GivenTheRequestIdWasSetGlobally()) - .And(x => x.GivenTheRequestIdIsAddedToTheRequest("LSRequestId", requestId)) - .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.ThenTheTraceIdIs(requestId)) - .And(x => ThenTheRequestIdIsUpdated()) - .BDDfy(); + GivenTheDownStreamRouteIs(downstreamRoute); + GivenTheRequestIdWasSetGlobally(); + _httpContext.Request.Headers.TryAdd("LSRequestId", requestId); + + // Act + await _middleware.Invoke(_httpContext); + + // Assert + ThenTheTraceIdIs(requestId); + _repo.Verify(x => x.Update("RequestId", requestId), Times.Once); } [Fact] - public void should_not_update_if_global_request_id_is_same_as_re_route_request_id() + public async Task Should_not_update_if_global_request_id_is_same_as_re_route_request_id() { + // Arrange var downstreamRoute = new DownstreamRouteHolder(new List(), new RouteBuilder() .WithDownstreamRoute(new DownstreamRouteBuilder() @@ -145,18 +161,16 @@ public void should_not_update_if_global_request_id_is_same_as_re_route_request_i var requestId = "alreadyset"; - this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) - .And(x => GivenTheRequestIdWasSetGlobally()) - .And(x => x.GivenTheRequestIdIsAddedToTheRequest("LSRequestId", requestId)) - .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.ThenTheTraceIdIs(requestId)) - .And(x => ThenTheRequestIdIsNotUpdated()) - .BDDfy(); - } + GivenTheDownStreamRouteIs(downstreamRoute); + GivenTheRequestIdWasSetGlobally(); + _httpContext.Request.Headers.TryAdd("LSRequestId", requestId); - private Task WhenICallTheMiddleware() - { - return _middleware.Invoke(_httpContext); + // Act + await _middleware.Invoke(_httpContext); + + // Assert + ThenTheTraceIdIs(requestId); + _repo.Verify(x => x.Update("RequestId", requestId), Times.Never); } private void GivenThereIsNoGlobalRequestId() @@ -169,41 +183,12 @@ private void GivenTheRequestIdWasSetGlobally() _repo.Setup(x => x.Get("RequestId")).Returns(new OkResponse("alreadyset")); } - private void ThenTheRequestIdIsSaved() - { - _repo.Verify(x => x.Add("RequestId", _value), Times.Once); - } - - private void ThenTheRequestIdIsUpdated() - { - _repo.Verify(x => x.Update("RequestId", _value), Times.Once); - } - - private void ThenTheRequestIdIsNotUpdated() - { - _repo.Verify(x => x.Update("RequestId", _value), Times.Never); - } - private void GivenTheDownStreamRouteIs(DownstreamRouteHolder downstreamRoute) { _httpContext.Items.UpsertTemplatePlaceholderNameAndValues(downstreamRoute.TemplatePlaceholderNameAndValues); - _httpContext.Items.UpsertDownstreamRoute(downstreamRoute.Route.DownstreamRoute[0]); } - private void GivenTheRequestIdIsAddedToTheRequest(string key, string value) - { - _key = key; - _value = value; - _httpContext.Request.Headers.TryAdd(_key, _value); - } - - private void ThenTheTraceIdIsAnything() - { - _httpContext.Response.Headers.TryGetValue("LSRequestId", out var value); - value.First().ShouldNotBeNullOrEmpty(); - } - private void ThenTheTraceIdIs(string expected) { _httpContext.Response.Headers.TryGetValue("LSRequestId", out var value); diff --git a/test/Ocelot.UnitTests/Requester/DelegatingHandlerHandlerProviderFactoryTests.cs b/test/Ocelot.UnitTests/Requester/DelegatingHandlerHandlerProviderFactoryTests.cs index 9e322eaa5..999723ee5 100644 --- a/test/Ocelot.UnitTests/Requester/DelegatingHandlerHandlerProviderFactoryTests.cs +++ b/test/Ocelot.UnitTests/Requester/DelegatingHandlerHandlerProviderFactoryTests.cs @@ -15,8 +15,6 @@ public class DelegatingHandlerHandlerProviderFactoryTests : UnitTest private DelegatingHandlerHandlerFactory _factory; private readonly Mock _loggerFactory; private readonly Mock _logger; - private DownstreamRoute _downstreamRoute; - private Response>> _result; private readonly Mock _qosFactory; private readonly Mock _tracingFactory; private IServiceProvider _serviceProvider; @@ -36,14 +34,14 @@ public DelegatingHandlerHandlerProviderFactoryTests() } [Fact] - public void should_follow_ordering_add_specifics() + public void Should_follow_ordering_add_specifics() { + // Arrange var qosOptions = new QoSOptionsBuilder() .WithTimeoutValue(1) .WithDurationOfBreak(1) .WithExceptionsAllowedBeforeBreaking(1) .Build(); - var route = new DownstreamRouteBuilder() .WithQosOptions(qosOptions) .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true, int.MaxValue, DefaultPooledConnectionLifeTime)) @@ -54,32 +52,33 @@ public void should_follow_ordering_add_specifics() }) .WithLoadBalancerKey(string.Empty) .Build(); - - this.Given(x => GivenTheFollowingRequest(route)) - .And(x => GivenTheQosFactoryReturns(new FakeQoSHandler())) - .And(x => GivenTheTracingFactoryReturns()) - .And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers()) - .And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers()) - .When(x => WhenIGet()) - .Then(x => ThenThereIsDelegatesInProvider(6)) - .And(x => ThenHandlerAtPositionIs(0)) - .And(x => ThenHandlerAtPositionIs(1)) - .And(x => ThenHandlerAtPositionIs(2)) - .And(x => ThenHandlerAtPositionIs(3)) - .And(x => ThenHandlerAtPositionIs(4)) - .And(x => ThenHandlerAtPositionIs(5)) - .BDDfy(); + GivenTheQosFactoryReturns(new FakeQoSHandler()); + GivenTheTracingFactoryReturns(); + GivenTheServiceProviderReturnsGlobalDelegatingHandlers(); + GivenTheServiceProviderReturnsSpecificDelegatingHandlers(); + + // Act + var result = WhenIGet(route); + + // Assert + result.ThenThereIsDelegatesInProvider(6); + result.ThenHandlerAtPositionIs(0); + result.ThenHandlerAtPositionIs(1); + result.ThenHandlerAtPositionIs(2); + result.ThenHandlerAtPositionIs(3); + result.ThenHandlerAtPositionIs(4); + result.ThenHandlerAtPositionIs(5); } [Fact] - public void should_follow_ordering_order_specifics_and_globals() + public void Should_follow_ordering_order_specifics_and_globals() { + // Arrange var qosOptions = new QoSOptionsBuilder() .WithTimeoutValue(1) .WithDurationOfBreak(1) .WithExceptionsAllowedBeforeBreaking(1) .Build(); - var route = new DownstreamRouteBuilder() .WithQosOptions(qosOptions) .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true, int.MaxValue, DefaultPooledConnectionLifeTime)) @@ -91,32 +90,33 @@ public void should_follow_ordering_order_specifics_and_globals() }) .WithLoadBalancerKey(string.Empty) .Build(); - - this.Given(x => GivenTheFollowingRequest(route)) - .And(x => GivenTheQosFactoryReturns(new FakeQoSHandler())) - .And(x => GivenTheTracingFactoryReturns()) - .And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers()) - .And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers()) - .When(x => WhenIGet()) - .Then(x => ThenThereIsDelegatesInProvider(6)) - .And(x => ThenHandlerAtPositionIs(0)) //first because global not in config - .And(x => ThenHandlerAtPositionIs(1)) //first from config - .And(x => ThenHandlerAtPositionIs(2)) //second from config - .And(x => ThenHandlerAtPositionIs(3)) //third from config (global) - .And(x => ThenHandlerAtPositionIs(4)) - .And(x => ThenHandlerAtPositionIs(5)) - .BDDfy(); + GivenTheQosFactoryReturns(new FakeQoSHandler()); + GivenTheTracingFactoryReturns(); + GivenTheServiceProviderReturnsGlobalDelegatingHandlers(); + GivenTheServiceProviderReturnsSpecificDelegatingHandlers(); + + // Act + var result = WhenIGet(route); + + // Assert + result.ThenThereIsDelegatesInProvider(6); + result.ThenHandlerAtPositionIs(0); //first because global not in config + result.ThenHandlerAtPositionIs(1); //first from config + result.ThenHandlerAtPositionIs(2); //second from config + result.ThenHandlerAtPositionIs(3); //third from config (global) + result.ThenHandlerAtPositionIs(4); + result.ThenHandlerAtPositionIs(5); } [Fact] - public void should_follow_ordering_order_specifics() + public void Should_follow_ordering_order_specifics() { + // Arrange var qosOptions = new QoSOptionsBuilder() .WithTimeoutValue(1) .WithDurationOfBreak(1) .WithExceptionsAllowedBeforeBreaking(1) .Build(); - var route = new DownstreamRouteBuilder() .WithQosOptions(qosOptions) .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true, int.MaxValue, DefaultPooledConnectionLifeTime)) @@ -127,32 +127,33 @@ public void should_follow_ordering_order_specifics() }) .WithLoadBalancerKey(string.Empty) .Build(); - - this.Given(x => GivenTheFollowingRequest(route)) - .And(x => GivenTheQosFactoryReturns(new FakeQoSHandler())) - .And(x => GivenTheTracingFactoryReturns()) - .And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers()) - .And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers()) - .When(x => WhenIGet()) - .Then(x => ThenThereIsDelegatesInProvider(6)) - .And(x => ThenHandlerAtPositionIs(0)) - .And(x => ThenHandlerAtPositionIs(1)) - .And(x => ThenHandlerAtPositionIs(2)) - .And(x => ThenHandlerAtPositionIs(3)) - .And(x => ThenHandlerAtPositionIs(4)) - .And(x => ThenHandlerAtPositionIs(5)) - .BDDfy(); + GivenTheQosFactoryReturns(new FakeQoSHandler()); + GivenTheTracingFactoryReturns(); + GivenTheServiceProviderReturnsGlobalDelegatingHandlers(); + GivenTheServiceProviderReturnsSpecificDelegatingHandlers(); + + // Act + var result = WhenIGet(route); + + // Assert + result.ThenThereIsDelegatesInProvider(6); + result.ThenHandlerAtPositionIs(0); + result.ThenHandlerAtPositionIs(1); + result.ThenHandlerAtPositionIs(2); + result.ThenHandlerAtPositionIs(3); + result.ThenHandlerAtPositionIs(4); + result.ThenHandlerAtPositionIs(5); } [Fact] - public void should_follow_ordering_order_and_only_add_specifics_in_config() + public void Should_follow_ordering_order_and_only_add_specifics_in_config() { + // Arrange var qosOptions = new QoSOptionsBuilder() .WithTimeoutValue(1) .WithDurationOfBreak(1) .WithExceptionsAllowedBeforeBreaking(1) .Build(); - var route = new DownstreamRouteBuilder() .WithQosOptions(qosOptions) .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true, int.MaxValue, DefaultPooledConnectionLifeTime)) @@ -162,57 +163,59 @@ public void should_follow_ordering_order_and_only_add_specifics_in_config() }) .WithLoadBalancerKey(string.Empty) .Build(); - - this.Given(x => GivenTheFollowingRequest(route)) - .And(x => GivenTheQosFactoryReturns(new FakeQoSHandler())) - .And(x => GivenTheTracingFactoryReturns()) - .And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers()) - .And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers()) - .When(x => WhenIGet()) - .Then(x => ThenThereIsDelegatesInProvider(5)) - .And(x => ThenHandlerAtPositionIs(0)) - .And(x => ThenHandlerAtPositionIs(1)) - .And(x => ThenHandlerAtPositionIs(2)) - .And(x => ThenHandlerAtPositionIs(3)) - .And(x => ThenHandlerAtPositionIs(4)) - .BDDfy(); + GivenTheQosFactoryReturns(new FakeQoSHandler()); + GivenTheTracingFactoryReturns(); + GivenTheServiceProviderReturnsGlobalDelegatingHandlers(); + GivenTheServiceProviderReturnsSpecificDelegatingHandlers(); + + // Act + var result = WhenIGet(route); + + // Assert + result.ThenThereIsDelegatesInProvider(5); + result.ThenHandlerAtPositionIs(0); + result.ThenHandlerAtPositionIs(1); + result.ThenHandlerAtPositionIs(2); + result.ThenHandlerAtPositionIs(3); + result.ThenHandlerAtPositionIs(4); } [Fact] - public void should_follow_ordering_dont_add_specifics() + public void Should_follow_ordering_dont_add_specifics() { + // Arrange var qosOptions = new QoSOptionsBuilder() .WithTimeoutValue(1) .WithDurationOfBreak(1) .WithExceptionsAllowedBeforeBreaking(1) .Build(); - var route = new DownstreamRouteBuilder() .WithQosOptions(qosOptions) .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true, int.MaxValue, DefaultPooledConnectionLifeTime)) .WithLoadBalancerKey(string.Empty) .Build(); - - this.Given(x => GivenTheFollowingRequest(route)) - .And(x => GivenTheQosFactoryReturns(new FakeQoSHandler())) - .And(x => GivenTheTracingFactoryReturns()) - .And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers()) - .And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers()) - .When(x => WhenIGet()) - .Then(x => ThenThereIsDelegatesInProvider(4)) - .And(x => ThenHandlerAtPositionIs(0)) - .And(x => ThenHandlerAtPositionIs(1)) - .And(x => ThenHandlerAtPositionIs(2)) - .And(x => ThenHandlerAtPositionIs(3)) - .BDDfy(); + GivenTheQosFactoryReturns(new FakeQoSHandler()); + GivenTheTracingFactoryReturns(); + GivenTheServiceProviderReturnsGlobalDelegatingHandlers(); + GivenTheServiceProviderReturnsSpecificDelegatingHandlers(); + + // Act + var result = WhenIGet(route); + + // Assert + result.ThenThereIsDelegatesInProvider(4); + result.ThenHandlerAtPositionIs(0); + result.ThenHandlerAtPositionIs(1); + result.ThenHandlerAtPositionIs(2); + result.ThenHandlerAtPositionIs(3); } [Fact] - public void should_apply_re_route_specific() + public void Should_apply_re_route_specific() { + // Arrange var qosOptions = new QoSOptionsBuilder() .Build(); - var route = new DownstreamRouteBuilder() .WithQosOptions(qosOptions) .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true, int.MaxValue, DefaultPooledConnectionLifeTime)) @@ -223,176 +226,178 @@ public void should_apply_re_route_specific() }) .WithLoadBalancerKey(string.Empty) .Build(); + GivenTheServiceProviderReturnsSpecificDelegatingHandlers(); + + // Act + var result = WhenIGet(route); - this.Given(x => GivenTheFollowingRequest(route)) - .And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers()) - .When(x => WhenIGet()) - .Then(x => ThenThereIsDelegatesInProvider(2)) - .And(x => ThenTheDelegatesAreAddedCorrectly()) - .BDDfy(); + // Assert + result.ThenThereIsDelegatesInProvider(2); + result.ThenTheDelegatesAreAddedCorrectly(); } [Fact] - public void should_all_from_all_routes_provider_and_qos() + public void Should_all_from_all_routes_provider_and_qos() { + // Arrange var qosOptions = new QoSOptionsBuilder() .WithTimeoutValue(1) .WithDurationOfBreak(1) .WithExceptionsAllowedBeforeBreaking(1) .Build(); - var route = new DownstreamRouteBuilder() .WithQosOptions(qosOptions) .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true, int.MaxValue, DefaultPooledConnectionLifeTime)) .WithLoadBalancerKey(string.Empty) .Build(); + GivenTheQosFactoryReturns(new FakeQoSHandler()); + GivenTheServiceProviderReturnsGlobalDelegatingHandlers(); - this.Given(x => GivenTheFollowingRequest(route)) - .And(x => GivenTheQosFactoryReturns(new FakeQoSHandler())) - .And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers()) - .When(x => WhenIGet()) - .Then(x => ThenThereIsDelegatesInProvider(3)) - .And(x => ThenTheDelegatesAreAddedCorrectly()) - .And(x => ThenItIsQosHandler(2)) - .BDDfy(); + // Act + var result = WhenIGet(route); + + // Assert + result.ThenThereIsDelegatesInProvider(3); + result.ThenTheDelegatesAreAddedCorrectly(); + result.ThenItIsQosHandler(2); } [Fact] - public void should_return_provider_with_no_delegates() + public void Should_return_provider_with_no_delegates() { + // Arrange var qosOptions = new QoSOptionsBuilder() .Build(); - var route = new DownstreamRouteBuilder() .WithQosOptions(qosOptions) .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true, int.MaxValue, DefaultPooledConnectionLifeTime)) .WithLoadBalancerKey(string.Empty) .Build(); + GivenTheServiceProviderReturnsNothing(); - this.Given(x => GivenTheFollowingRequest(route)) - .And(x => GivenTheServiceProviderReturnsNothing()) - .When(x => WhenIGet()) - .Then(x => ThenNoDelegatesAreInTheProvider()) - .BDDfy(); + // Act + var result = WhenIGet(route); + + // Assert: Then No Delegates Are In The Provider + result.ShouldNotBeNull(); + result.Data.Count.ShouldBe(0); } [Fact] - public void should_return_provider_with_qos_delegate() + public void Should_return_provider_with_qos_delegate() { + // Arrange var qosOptions = new QoSOptionsBuilder() .WithTimeoutValue(1) .WithDurationOfBreak(1) .WithExceptionsAllowedBeforeBreaking(1) .Build(); - var route = new DownstreamRouteBuilder() .WithQosOptions(qosOptions) .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true, int.MaxValue, DefaultPooledConnectionLifeTime)) .WithLoadBalancerKey(string.Empty) .Build(); + GivenTheQosFactoryReturns(new FakeQoSHandler()); + GivenTheServiceProviderReturnsNothing(); - this.Given(x => GivenTheFollowingRequest(route)) - .And(x => GivenTheQosFactoryReturns(new FakeQoSHandler())) - .And(x => GivenTheServiceProviderReturnsNothing()) - .When(x => WhenIGet()) - .Then(x => ThenThereIsDelegatesInProvider(1)) - .And(x => ThenItIsQosHandler(0)) - .BDDfy(); + // Act + var result = WhenIGet(route); + + // Assert + result.ThenThereIsDelegatesInProvider(1); + result.ThenItIsQosHandler(0); } [Fact] - public void should_return_provider_with_qos_delegate_when_timeout_value_set() + public void Should_return_provider_with_qos_delegate_when_timeout_value_set() { + // Arrange var qosOptions = new QoSOptionsBuilder() .WithTimeoutValue(1) .Build(); - var route = new DownstreamRouteBuilder() .WithQosOptions(qosOptions) .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true, int.MaxValue, DefaultPooledConnectionLifeTime)) .WithLoadBalancerKey(string.Empty) .Build(); + GivenTheQosFactoryReturns(new FakeQoSHandler()); + GivenTheServiceProviderReturnsNothing(); - this.Given(x => GivenTheFollowingRequest(route)) - .And(x => GivenTheQosFactoryReturns(new FakeQoSHandler())) - .And(x => GivenTheServiceProviderReturnsNothing()) - .When(x => WhenIGet()) - .Then(x => ThenThereIsDelegatesInProvider(1)) - .And(x => ThenItIsQosHandler(0)) - .BDDfy(); + // Act + var result = WhenIGet(route); + + // Assert + result.ThenThereIsDelegatesInProvider(1); + result.ThenItIsQosHandler(0); } [Fact] - public void should_log_error_and_return_no_qos_provider_delegate_when_qos_factory_returns_error() + public void Should_log_error_and_return_no_qos_provider_delegate_when_qos_factory_returns_error() { + // Arrange var qosOptions = new QoSOptionsBuilder() .WithTimeoutValue(1) .WithDurationOfBreak(1) .WithExceptionsAllowedBeforeBreaking(1) .Build(); - var route = new DownstreamRouteBuilder() .WithQosOptions(qosOptions) .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true, int.MaxValue, DefaultPooledConnectionLifeTime)) .WithLoadBalancerKey(string.Empty) .Build(); - - this.Given(x => GivenTheFollowingRequest(route)) - .And(x => GivenTheQosFactoryReturnsError()) - .And(x => GivenTheTracingFactoryReturns()) - .And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers()) - .And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers()) - .When(x => WhenIGet()) - .Then(x => ThenThereIsDelegatesInProvider(4)) - .And(x => ThenHandlerAtPositionIs(0)) - .And(x => ThenHandlerAtPositionIs(1)) - .And(x => ThenHandlerAtPositionIs(2)) - .And(x => ThenHandlerAtPositionIs(3)) - .And(_ => ThenTheWarningIsLogged()) - .BDDfy(); + _qosFactory.Setup(x => x.Get(It.IsAny())) + .Returns(new ErrorResponse(new AnyError())); + GivenTheTracingFactoryReturns(); + GivenTheServiceProviderReturnsGlobalDelegatingHandlers(); + GivenTheServiceProviderReturnsSpecificDelegatingHandlers(); + + // Act + var result = WhenIGet(route); + + // Assert + result.ThenThereIsDelegatesInProvider(4); + result.ThenHandlerAtPositionIs(0); + result.ThenHandlerAtPositionIs(1); + result.ThenHandlerAtPositionIs(2); + result.ThenHandlerAtPositionIs(3); + ThenTheWarningIsLogged(route); } [Fact] - public void should_log_error_and_return_no_qos_provider_delegate_when_qos_factory_returns_null() + public void Should_log_error_and_return_no_qos_provider_delegate_when_qos_factory_returns_null() { + // Arrange var qosOptions = new QoSOptionsBuilder() .WithTimeoutValue(1) .WithDurationOfBreak(1) .WithExceptionsAllowedBeforeBreaking(1) .Build(); - var route = new DownstreamRouteBuilder() .WithQosOptions(qosOptions) .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true, int.MaxValue, DefaultPooledConnectionLifeTime)) .WithLoadBalancerKey(string.Empty) .Build(); - - this.Given(x => GivenTheFollowingRequest(route)) - .And(x => GivenTheQosFactoryReturnsNull()) - .And(x => GivenTheTracingFactoryReturns()) - .And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers()) - .And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers()) - .When(x => WhenIGet()) - .Then(x => ThenThereIsDelegatesInProvider(4)) - .And(x => ThenHandlerAtPositionIs(0)) - .And(x => ThenHandlerAtPositionIs(1)) - .And(x => ThenHandlerAtPositionIs(2)) - .And(x => ThenHandlerAtPositionIs(3)) - .And(_ => ThenTheWarningIsLogged()) - .BDDfy(); - } - - private void ThenTheWarningIsLogged() - { - _logger.Verify(x => x.LogWarning(It.Is>(y => y.Invoke() == $"Route {_downstreamRoute.UpstreamPathTemplate} specifies use QoS but no QosHandler found in DI container. Will use not use a QosHandler, please check your setup!")), Times.Once); + _qosFactory.Setup(x => x.Get(It.IsAny())) + .Returns((ErrorResponse)null); + GivenTheTracingFactoryReturns(); + GivenTheServiceProviderReturnsGlobalDelegatingHandlers(); + GivenTheServiceProviderReturnsSpecificDelegatingHandlers(); + + // Act + var result = WhenIGet(route); + + // Assert + result.ThenThereIsDelegatesInProvider(4); + result.ThenHandlerAtPositionIs(0); + result.ThenHandlerAtPositionIs(1); + result.ThenHandlerAtPositionIs(2); + result.ThenHandlerAtPositionIs(3); + ThenTheWarningIsLogged(route); } - private void ThenHandlerAtPositionIs(int pos) - where T : DelegatingHandler + private void ThenTheWarningIsLogged(DownstreamRoute route) { - var delegates = _result.Data; - var del = delegates[pos].Invoke(); - del.ShouldBeOfType(); + _logger.Verify(x => x.LogWarning(It.Is>(y => y.Invoke() == $"Route {route.UpstreamPathTemplate} specifies use QoS but no QosHandler found in DI container. Will use not use a QosHandler, please check your setup!")), Times.Once); } private void GivenTheTracingFactoryReturns() @@ -433,24 +438,6 @@ private void GivenTheServiceProviderReturnsNothing() _serviceProvider = _services.BuildServiceProvider(true); } - private void ThenAnErrorIsReturned() - { - _result.IsError.ShouldBeTrue(); - } - - private void ThenTheDelegatesAreAddedCorrectly() - { - var delegates = _result.Data; - - var del = delegates[0].Invoke(); - var handler = (FakeDelegatingHandler)del; - handler.Order.ShouldBe(1); - - del = delegates[1].Invoke(); - var handlerTwo = (FakeDelegatingHandlerTwo)del; - handlerTwo.Order.ShouldBe(2); - } - private void GivenTheQosFactoryReturns(DelegatingHandler handler) { _qosFactory @@ -458,55 +445,52 @@ private void GivenTheQosFactoryReturns(DelegatingHandler handler) .Returns(new OkResponse(handler)); } - private void GivenTheQosFactoryReturnsError() + private Response>> WhenIGet(DownstreamRoute route) { - _qosFactory - .Setup(x => x.Get(It.IsAny())) - .Returns(new ErrorResponse(new AnyError())); + _serviceProvider = _services.BuildServiceProvider(true); + _factory = new DelegatingHandlerHandlerFactory(_tracingFactory.Object, _qosFactory.Object, _serviceProvider, _loggerFactory.Object); + return _factory.Get(route); } - private void GivenTheQosFactoryReturnsNull() - { - _qosFactory - .Setup(x => x.Get(It.IsAny())) - .Returns((ErrorResponse)null); - } + /// 120 seconds. + private static TimeSpan DefaultPooledConnectionLifeTime => TimeSpan.FromSeconds(HttpHandlerOptionsCreator.DefaultPooledConnectionLifetimeSeconds); +} - private void ThenItIsQosHandler(int i) +internal static class ResponseExtensions +{ + public static void ThenItIsQosHandler(this Response>> result, int i) { - var delegates = _result.Data; + var delegates = result.Data; var del = delegates[i].Invoke(); del.ShouldBeOfType(); } - private void ThenThereIsDelegatesInProvider(int count) + public static void ThenTheDelegatesAreAddedCorrectly(this Response>> result) { - _result.ShouldNotBeNull(); - _result.Data.Count.ShouldBe(count); - } + var delegates = result.Data; - private void GivenTheFollowingRequest(DownstreamRoute request) - { - _downstreamRoute = request; + var del = delegates[0].Invoke(); + var handler = (FakeDelegatingHandler)del; + handler.Order.ShouldBe(1); + + del = delegates[1].Invoke(); + var handlerTwo = (FakeDelegatingHandlerTwo)del; + handlerTwo.Order.ShouldBe(2); } - private void WhenIGet() + public static void ThenThereIsDelegatesInProvider(this Response>> result, int count) { - _serviceProvider = _services.BuildServiceProvider(true); - _factory = new DelegatingHandlerHandlerFactory(_tracingFactory.Object, _qosFactory.Object, _serviceProvider, _loggerFactory.Object); - _result = _factory.Get(_downstreamRoute); + result.ShouldNotBeNull(); + result.Data.Count.ShouldBe(count); } - private void ThenNoDelegatesAreInTheProvider() + public static void ThenHandlerAtPositionIs(this Response>> result, int pos) + where T : DelegatingHandler { - _result.ShouldNotBeNull(); - _result.Data.Count.ShouldBe(0); + var delegates = result.Data; + var del = delegates[pos].Invoke(); + del.ShouldBeOfType(); } - - /// - /// 120 seconds. - /// - private static TimeSpan DefaultPooledConnectionLifeTime => TimeSpan.FromSeconds(HttpHandlerOptionsCreator.DefaultPooledConnectionLifetimeSeconds); } internal class FakeTracingHandler : DelegatingHandler, ITracingHandler diff --git a/test/Ocelot.UnitTests/Requester/FakeDelegatingHandler.cs b/test/Ocelot.UnitTests/Requester/FakeDelegatingHandler.cs index cf70eb015..4f0731b66 100644 --- a/test/Ocelot.UnitTests/Requester/FakeDelegatingHandler.cs +++ b/test/Ocelot.UnitTests/Requester/FakeDelegatingHandler.cs @@ -2,20 +2,10 @@ namespace Ocelot.UnitTests.Requester; public class FakeDelegatingHandler : DelegatingHandler { - public FakeDelegatingHandler() - { - Order = 1; - } - - public FakeDelegatingHandler(int order) - { - Order = order; - } - + public FakeDelegatingHandler() => Order = 1; + public FakeDelegatingHandler(int order) => Order = order; public int Order { get; } - public DateTime TimeCalled { get; private set; } - protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { TimeCalled = DateTime.Now; @@ -25,15 +15,9 @@ protected override Task SendAsync(HttpRequestMessage reques public class FakeDelegatingHandlerThree : DelegatingHandler { - public FakeDelegatingHandlerThree() - { - Order = 3; - } - + public FakeDelegatingHandlerThree() => Order = 3; public int Order { get; } - public DateTime TimeCalled { get; private set; } - protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { TimeCalled = DateTime.Now; @@ -43,15 +27,9 @@ protected override Task SendAsync(HttpRequestMessage reques public class FakeDelegatingHandlerFour : DelegatingHandler { - public FakeDelegatingHandlerFour() - { - Order = 4; - } - + public FakeDelegatingHandlerFour() => Order = 4; public int Order { get; } - public DateTime TimeCalled { get; private set; } - protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { TimeCalled = DateTime.Now; @@ -61,15 +39,9 @@ protected override Task SendAsync(HttpRequestMessage reques public class FakeDelegatingHandlerTwo : DelegatingHandler { - public FakeDelegatingHandlerTwo() - { - Order = 2; - } - + public FakeDelegatingHandlerTwo() => Order = 2; public int Order { get; } - public DateTime TimeCalled { get; private set; } - protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { TimeCalled = DateTime.Now; diff --git a/test/Ocelot.UnitTests/Requester/HttpExceptionToErrorMapperTests.cs b/test/Ocelot.UnitTests/Requester/HttpExceptionToErrorMapperTests.cs index 0b7c3b485..c9e80a21c 100644 --- a/test/Ocelot.UnitTests/Requester/HttpExceptionToErrorMapperTests.cs +++ b/test/Ocelot.UnitTests/Requester/HttpExceptionToErrorMapperTests.cs @@ -20,38 +20,47 @@ public HttpExceptionToErrorMapperTests() [Fact] public void Should_return_default_error_because_mappers_are_null() { + // Arrange, Act var error = _mapper.Map(new Exception()); + // Assert error.ShouldBeOfType(); } [Fact] public void Should_return_request_canceled() { + // Arrange, Act var error = _mapper.Map(new OperationCanceledException()); + // Assert error.ShouldBeOfType(); } [Fact] public void Should_return_ConnectionToDownstreamServiceError() { + // Arrange, Act var error = _mapper.Map(new HttpRequestException()); + // Assert error.ShouldBeOfType(); } [Fact] public void Should_return_request_canceled_for_subtype() { + // Arrange, Act var error = _mapper.Map(new SomeException()); + // Assert error.ShouldBeOfType(); } [Fact] public void Should_return_error_from_mapper() { + // Arrange IDictionary> errorMapping = new Dictionary> { {typeof(TaskCanceledException), e => new AnyError()}, @@ -63,8 +72,10 @@ public void Should_return_error_from_mapper() _mapper = new HttpExceptionToErrorMapper(provider); + // Act var error = _mapper.Map(new TaskCanceledException()); + // Assert error.ShouldBeOfType(); } diff --git a/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs b/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs index ee710b178..2dc57c2f4 100644 --- a/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs @@ -12,12 +12,11 @@ namespace Ocelot.UnitTests.Requester; public class HttpRequesterMiddlewareTests : UnitTest { private readonly Mock _requester; - private Response _response; private readonly Mock _loggerFactory; private readonly Mock _logger; private readonly HttpRequesterMiddleware _middleware; private readonly RequestDelegate _next; - private readonly HttpContext _httpContext; + private readonly DefaultHttpContext _httpContext; public HttpRequesterMiddlewareTests() { @@ -28,112 +27,109 @@ public HttpRequesterMiddlewareTests() _loggerFactory.Setup(x => x.CreateLogger()).Returns(_logger.Object); _next = context => Task.CompletedTask; _middleware = new HttpRequesterMiddleware(_next, _loggerFactory.Object, _requester.Object); + + _httpContext.Items.UpsertDownstreamRoute(new DownstreamRouteBuilder().Build()); // Given The Request Is } [Fact] - public void should_call_services_correctly() + public async Task Should_call_services_correctly() { - this.Given(x => x.GivenTheRequestIs()) - .And(x => x.GivenTheRequesterReturns(new OkResponse(new HttpResponseMessage(HttpStatusCode.OK)))) - .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.ThenTheDownstreamResponseIsSet()) - .Then(x => InformationIsLogged()) - .BDDfy(); + // Arrange + var response = GivenTheRequesterReturns(new OkResponse(new HttpResponseMessage(HttpStatusCode.OK))); + + // Act + await _middleware.Invoke(_httpContext); + + // Assert + InformationIsLogged(); + + // Assert: Then The Downstream Response Is Set + foreach (var httpResponseHeader in response.Data.Headers) + { + if (_httpContext.Items.DownstreamResponse().Headers.Any(x => x.Key == httpResponseHeader.Key)) + { + throw new Exception("Header in response not in downstreamresponse headers"); + } + } + + _httpContext.Items.DownstreamResponse().Content.ShouldBe(response.Data.Content); + _httpContext.Items.DownstreamResponse().StatusCode.ShouldBe(response.Data.StatusCode); } [Fact] - public void should_set_error() + public async Task Should_set_error() { - this.Given(x => x.GivenTheRequestIs()) - .And(x => x.GivenTheRequesterReturns(new ErrorResponse(new AnyError()))) - .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.ThenTheErrorIsSet()) - .BDDfy(); + // Arrange + GivenTheRequesterReturns(new ErrorResponse(new AnyError())); + + // Act + await _middleware.Invoke(_httpContext); + + // Assert + _httpContext.Items.Errors().Count.ShouldBeGreaterThan(0); } [Fact] - public void should_log_downstream_internal_server_error() + public async Task Should_log_downstream_internal_server_error() { - this.Given(x => x.GivenTheRequestIs()) - .And(x => x.GivenTheRequesterReturns( - new OkResponse(new HttpResponseMessage(HttpStatusCode.InternalServerError)))) - .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.WarningIsLogged()) - .BDDfy(); + // Arrange + GivenTheRequesterReturns(new OkResponse(new HttpResponseMessage(HttpStatusCode.InternalServerError))); + + // Act + await _middleware.Invoke(_httpContext); + + // Assert + WarningIsLogged(); } [Theory] [Trait("Bug", "1953")] [InlineData(HttpStatusCode.OK)] [InlineData(HttpStatusCode.PermanentRedirect)] - public void Should_LogInformation_when_status_is_less_than_BadRequest(HttpStatusCode status) + public async Task Should_LogInformation_when_status_is_less_than_BadRequest(HttpStatusCode status) { - this.Given(x => x.GivenTheRequestIs()) - .And(x => x.GivenTheRequesterReturns(new OkResponse(new HttpResponseMessage(status)))) - .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.InformationIsLogged()) - .BDDfy(); + // Arrange + GivenTheRequesterReturns(new OkResponse(new HttpResponseMessage(status))); + + // Act + await _middleware.Invoke(_httpContext); + + // Assert + InformationIsLogged(); } [Theory] [Trait("Bug", "1953")] [InlineData(HttpStatusCode.BadRequest)] [InlineData(HttpStatusCode.NotFound)] - public void Should_LogWarning_when_status_is_BadRequest_or_greater(HttpStatusCode status) + public async Task Should_LogWarning_when_status_is_BadRequest_or_greater(HttpStatusCode status) { - this.Given(x => x.GivenTheRequestIs()) - .And(x => x.GivenTheRequesterReturns(new OkResponse(new HttpResponseMessage(status)))) - .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.WarningIsLogged()) - .BDDfy(); - } - - private void ThenTheErrorIsSet() - { - _httpContext.Items.Errors().Count.ShouldBeGreaterThan(0); - } + // Arrange + GivenTheRequesterReturns(new OkResponse(new HttpResponseMessage(status))); - private Task WhenICallTheMiddleware() => _middleware.Invoke(_httpContext); + // Act + await _middleware.Invoke(_httpContext); - private void GivenTheRequestIs() - { - _httpContext.Items.UpsertDownstreamRoute(new DownstreamRouteBuilder().Build()); + // Assert + WarningIsLogged(); } - private void GivenTheRequesterReturns(Response response) + private Response GivenTheRequesterReturns(Response response) { - _response = response; - - _requester - .Setup(x => x.GetResponse(It.IsAny())) - .ReturnsAsync(_response); - } - - private void ThenTheDownstreamResponseIsSet() - { - foreach (var httpResponseHeader in _response.Data.Headers) - { - if (_httpContext.Items.DownstreamResponse().Headers.Any(x => x.Key == httpResponseHeader.Key)) - { - throw new Exception("Header in response not in downstreamresponse headers"); - } - } - - _httpContext.Items.DownstreamResponse().Content.ShouldBe(_response.Data.Content); - _httpContext.Items.DownstreamResponse().StatusCode.ShouldBe(_response.Data.StatusCode); + _requester.Setup(x => x.GetResponse(It.IsAny())) + .ReturnsAsync(response); + return response; } private void WarningIsLogged() { - _logger.Verify( - x => x.LogWarning(It.IsAny>()), + _logger.Verify(x => x.LogWarning(It.IsAny>()), Times.Once); } private void InformationIsLogged() { - _logger.Verify( - x => x.LogInformation(It.IsAny>()), + _logger.Verify(x => x.LogInformation(It.IsAny>()), Times.Once); } } diff --git a/test/Ocelot.UnitTests/Requester/MessageInvokerPoolTests.cs b/test/Ocelot.UnitTests/Requester/MessageInvokerPoolTests.cs index 81d7005c4..2e8ed678b 100644 --- a/test/Ocelot.UnitTests/Requester/MessageInvokerPoolTests.cs +++ b/test/Ocelot.UnitTests/Requester/MessageInvokerPoolTests.cs @@ -19,17 +19,16 @@ public class MessageInvokerPoolTests : UnitTest private DownstreamRoute _downstreamRoute1; private DownstreamRoute _downstreamRoute2; private MessageInvokerPool _pool; - private HttpMessageInvoker _firstInvoker; - private HttpMessageInvoker _secondInvoker; private Mock _handlerFactory; private readonly Mock _ocelotLoggerFactory; private readonly Mock _ocelotLogger; - private HttpContext _context; + private readonly DefaultHttpContext _context; private HttpResponseMessage _response; private IWebHost _host; public MessageInvokerPoolTests() { + _context = new(); _ocelotLoggerFactory = new Mock(); _ocelotLogger = new Mock(); _ocelotLoggerFactory.Setup(x => x.CreateLogger()).Returns(_ocelotLogger.Object); @@ -38,53 +37,67 @@ public MessageInvokerPoolTests() [Fact] public void If_calling_the_same_downstream_route_twice_should_return_the_same_message_invoker() { - this.Given(x => x.GivenADownstreamRoute("/super-test")) - .And(x => x.AndAHandlerFactory()) - .And(x => x.GivenAMessageInvokerPool()) - .When(x => x.WhenGettingMessageInvokerTwice()) - .Then(x => x.ThenTheInvokersShouldBeTheSame()) - .BDDfy(); + // Arrange + _downstreamRoute1 = DownstreamRouteFactory("/super-test"); + AndAHandlerFactory(); + GivenAMessageInvokerPool(); + + // Act + var firstInvoker = _pool.Get(_downstreamRoute1); + var secondInvoker = _pool.Get(_downstreamRoute1); + + // Assert + Assert.Equal(firstInvoker, secondInvoker); } [Fact] public void If_calling_two_different_downstream_routes_should_return_different_message_invokers() { - this.Given(x => x.GivenTwoDifferentDownstreamRoutes("/super-test", "/super-test")) - .And(x => x.AndAHandlerFactory()) - .And(x => x.GivenAMessageInvokerPool()) - .When(x => x.WhenGettingMessageInvokerForBothRoutes()) - .Then(x => x.ThenTheInvokersShouldNotBeTheSame()) - .BDDfy(); + // Arrange + _downstreamRoute1 = DownstreamRouteFactory("/super-test"); + _downstreamRoute2 = DownstreamRouteFactory("/super-test"); + AndAHandlerFactory(); + GivenAMessageInvokerPool(); + + // Act + var firstInvoker = _pool.Get(_downstreamRoute1); + var secondInvoker = _pool.Get(_downstreamRoute2); + + // Assert + Assert.NotEqual(firstInvoker, secondInvoker); } [Fact] - public void If_two_delegating_handlers_are_defined_then_these_should_be_call_in_order() + public async Task If_two_delegating_handlers_are_defined_then_these_should_be_call_in_order() { + // Arrange var fakeOne = new FakeDelegatingHandler(); var fakeTwo = new FakeDelegatingHandler(); - var handlers = new List> { () => fakeOne, () => fakeTwo, }; - this.Given(x => GivenTheFactoryReturns(handlers)) - .And(x => GivenADownstreamRoute("/super-test")) - .And(x => GivenAMessageInvokerPool()) - .And(x => GivenARequest()) - .When(x => WhenICallTheClient("http://www.bbc.co.uk")) - .Then(x => ThenTheFakeAreHandledInOrder(fakeOne, fakeTwo)) - .And(x => ThenSomethingIsReturned()) - .BDDfy(); + GivenTheFactoryReturns(handlers); + _downstreamRoute1 = DownstreamRouteFactory("/super-test"); + GivenAMessageInvokerPool(); + GivenARequestWithAUrlAndMethod(_downstreamRoute1, "http://localhost:5003", HttpMethod.Get); + + // Act + await WhenICallTheClient("http://www.bbc.co.uk"); + + // Assert + ThenTheFakeAreHandledInOrder(fakeOne, fakeTwo); + _response.ShouldNotBeNull(); } [Fact] - public void Should_log_if_ignoring_ssl_errors() + public async Task Should_log_if_ignoring_ssl_errors() { + // Arrange var qosOptions = new QoSOptionsBuilder() .Build(); - var route = new DownstreamRouteBuilder() .WithQosOptions(qosOptions) .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue, TimeSpan.FromSeconds(90))) @@ -93,21 +106,25 @@ public void Should_log_if_ignoring_ssl_errors() .WithQosOptions(new QoSOptionsBuilder().Build()) .WithDangerousAcceptAnyServerCertificateValidator(true) .Build(); + GivenTheFactoryReturns(new List>()); + GivenAMessageInvokerPool(); + GivenARequest(route); + + // Act + await WhenICallTheClient("http://www.google.com/"); - this.Given(x => GivenTheFactoryReturns(new List>())) - .And(x => GivenAMessageInvokerPool()) - .And(x => GivenARequest(route)) - .When(x => WhenICallTheClient("http://www.google.com/")) - .Then(x => ThenTheDangerousAcceptAnyServerCertificateValidatorWarningIsLogged()) - .BDDfy(); + // Assert: Then The DangerousAcceptAnyServerCertificateValidator Warning Is Logged + _ocelotLogger.Verify(x => x.LogWarning( + It.Is>(y => y.Invoke() == $"You have ignored all SSL warnings by using DangerousAcceptAnyServerCertificateValidator for this DownstreamRoute, UpstreamPathTemplate: {_context.Items.DownstreamRoute().UpstreamPathTemplate}, DownstreamPathTemplate: {_context.Items.DownstreamRoute().DownstreamPathTemplate}")), + Times.Once); } [Fact] - public void Should_re_use_cookies_from_container() + public async Task Should_re_use_cookies_from_container() { + // Arrange var qosOptions = new QoSOptionsBuilder() .Build(); - var route = new DownstreamRouteBuilder() .WithQosOptions(qosOptions) .WithHttpHandlerOptions(new HttpHandlerOptions(false, true, false, true, int.MaxValue, TimeSpan.FromSeconds(90))) @@ -115,23 +132,25 @@ public void Should_re_use_cookies_from_container() .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue(string.Empty).Build()) .WithQosOptions(new QoSOptionsBuilder().Build()) .Build(); + GivenADownstreamService(); + GivenTheFactoryReturns(new List>()); + GivenAMessageInvokerPool(); + GivenARequest(route); + + // Act, Assert + await WhenICallTheClient("http://localhost:5003"); + _response.Headers.TryGetValues("Set-Cookie", out _).ShouldBeTrue(); - this.Given(_ => GivenADownstreamService()) - .And(x => GivenTheFactoryReturns(new List>())) - .And(x => GivenAMessageInvokerPool()) - .And(x => GivenARequest(route)) - .And(_ => WhenICallTheClient("http://localhost:5003")) - .And(_ => ThenTheCookieIsSet()) - .When(_ => WhenICallTheClient("http://localhost:5003")) - .Then(_ => ThenTheResponseIsOk()) - .BDDfy(); + // Act, Assert + await WhenICallTheClient("http://localhost:5003"); + _response.StatusCode.ShouldBe(HttpStatusCode.OK); } [Theory] [Trait("Issue", "1833")] [InlineData(5, 5)] [InlineData(10, 10)] - public void Create_TimeoutValueInQosOptions_MessageInvokerTimeout(int qosTimeout, int expectedSeconds) + public async Task Create_TimeoutValueInQosOptions_MessageInvokerTimeout(int qosTimeout, int expectedSeconds) { // Arrange var qosOptions = new QoSOptionsBuilder() @@ -145,24 +164,12 @@ public void Create_TimeoutValueInQosOptions_MessageInvokerTimeout(int qosTimeout .WithHttpHandlerOptions(handlerOptions) .Build(); GivenTheFactoryReturnsNothing(); + GivenTheFactoryReturns(new List>()); + GivenAMessageInvokerPool(); + GivenARequest(route); - this.Given(x => GivenTheFactoryReturns(new List>())) - .And(x => GivenAMessageInvokerPool()) - .And(x => GivenARequest(route)) - .Then(x => WhenICallTheClientWillThrowAfterTimeout(TimeSpan.FromSeconds(expectedSeconds))) - .BDDfy(); - } - - private void ThenTheDangerousAcceptAnyServerCertificateValidatorWarningIsLogged() - { - _ocelotLogger.Verify(x => x.LogWarning( - It.Is>(y => y.Invoke() == $"You have ignored all SSL warnings by using DangerousAcceptAnyServerCertificateValidator for this DownstreamRoute, UpstreamPathTemplate: {_context.Items.DownstreamRoute().UpstreamPathTemplate}, DownstreamPathTemplate: {_context.Items.DownstreamRoute().DownstreamPathTemplate}")), - Times.Once); - } - - private void ThenTheCookieIsSet() - { - _response.Headers.TryGetValues("Set-Cookie", out var test).ShouldBeTrue(); + // Act, Assert + await WhenICallTheClientWillThrowAfterTimeout(TimeSpan.FromSeconds(expectedSeconds)); } private void GivenADownstreamService() @@ -205,27 +212,9 @@ private void GivenADownstreamService() _host.Start(); } - private void ThenTheResponseIsOk() - { - _response.StatusCode.ShouldBe(HttpStatusCode.OK); - } - private void GivenARequest(DownstreamRoute downstream) { - GivenARequest(downstream, "http://localhost:5003"); - } - - private void GivenARequest(DownstreamRoute downstream, string downstreamUrl) - { - GivenARequestWithAUrlAndMethod(downstream, downstreamUrl, HttpMethod.Get); - } - - private void GivenADownstreamRoute(string path) => _downstreamRoute1 = DownstreamRouteFactory(path); - - private void GivenTwoDifferentDownstreamRoutes(string path1, string path2) - { - _downstreamRoute1 = DownstreamRouteFactory(path1); - _downstreamRoute2 = DownstreamRouteFactory(path2); + GivenARequestWithAUrlAndMethod(downstream, "http://localhost:5003", HttpMethod.Get); } private void AndAHandlerFactory() => _handlerFactory = GetHandlerFactory(); @@ -233,37 +222,13 @@ private void GivenTwoDifferentDownstreamRoutes(string path1, string path2) private void GivenAMessageInvokerPool() => _pool = new MessageInvokerPool(_handlerFactory.Object, _ocelotLoggerFactory.Object); - private void WhenGettingMessageInvokerTwice() - { - _firstInvoker = _pool.Get(_downstreamRoute1); - _secondInvoker = _pool.Get(_downstreamRoute1); - } - - private void WhenGettingMessageInvokerForBothRoutes() - { - _firstInvoker = _pool.Get(_downstreamRoute1); - _secondInvoker = _pool.Get(_downstreamRoute2); - } - - private void ThenTheInvokersShouldBeTheSame() => Assert.Equal(_firstInvoker, _secondInvoker); - - private void ThenTheInvokersShouldNotBeTheSame() => Assert.NotEqual(_firstInvoker, _secondInvoker); - - private void GivenARequest(string url) => GivenARequestWithAUrlAndMethod(_downstreamRoute1, url, HttpMethod.Get); - - private void GivenARequest() => - GivenARequestWithAUrlAndMethod(_downstreamRoute1, "http://localhost:5003", HttpMethod.Get); - private void GivenARequestWithAUrlAndMethod(DownstreamRoute downstream, string url, HttpMethod method) { - _context = new DefaultHttpContext(); _context.Items.UpsertDownstreamRoute(downstream); _context.Items.UpsertDownstreamRequest(new DownstreamRequest(new HttpRequestMessage { RequestUri = new Uri(url), Method = method })); } - private void ThenSomethingIsReturned() => _response.ShouldNotBeNull(); - private async Task WhenICallTheClient(string url) { var messageInvoker = _pool.Get(_context.Items.DownstreamRoute()); @@ -315,7 +280,7 @@ private void GivenTheFactoryReturns(List> handlers) .Returns(new OkResponse>>(handlers)); } - private Mock GetHandlerFactory() + private static Mock GetHandlerFactory() { var handlerFactory = new Mock(); handlerFactory.Setup(x => x.Get(It.IsAny())) @@ -323,9 +288,7 @@ private Mock GetHandlerFactory() return handlerFactory; } - private DownstreamRoute DownstreamRouteFactory(string path) - { - var downstreamRoute = new DownstreamRouteBuilder() + private static DownstreamRoute DownstreamRouteFactory(string path) => new DownstreamRouteBuilder() .WithDownstreamPathTemplate(path) .WithQosOptions(new QoSOptions(new FileQoSOptions())) .WithLoadBalancerKey(string.Empty) @@ -333,7 +296,4 @@ private DownstreamRoute DownstreamRouteFactory(string path) .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, false, 10, TimeSpan.FromSeconds(120))) .WithUpstreamHttpMethod(new() { "Get" }) .Build(); - - return downstreamRoute; - } } diff --git a/test/Ocelot.UnitTests/Requester/QoSFactoryTests.cs b/test/Ocelot.UnitTests/Requester/QoSFactoryTests.cs index 190742186..0b2d9be4f 100644 --- a/test/Ocelot.UnitTests/Requester/QoSFactoryTests.cs +++ b/test/Ocelot.UnitTests/Requester/QoSFactoryTests.cs @@ -25,24 +25,35 @@ public QoSFactoryTests() } [Fact] - public void should_return_error() + public void Should_return_error() { + // Arrange var downstreamRoute = new DownstreamRouteBuilder().Build(); + + // Act var handler = _factory.Get(downstreamRoute); + + // Assert handler.IsError.ShouldBeTrue(); handler.Errors[0].ShouldBeOfType(); } [Fact] - public void should_return_handler() + public void Should_return_handler() { + // Arrange _services = new ServiceCollection(); - DelegatingHandler QosDelegatingHandlerDelegate(DownstreamRoute a, IHttpContextAccessor b, IOcelotLoggerFactory c) => new FakeDelegatingHandler(); + + static DelegatingHandler QosDelegatingHandlerDelegate(DownstreamRoute a, IHttpContextAccessor b, IOcelotLoggerFactory c) => new FakeDelegatingHandler(); _services.AddSingleton(QosDelegatingHandlerDelegate); var provider = _services.BuildServiceProvider(true); _factory = new QoSFactory(provider, _contextAccessor.Object, _loggerFactory.Object); var downstreamRoute = new DownstreamRouteBuilder().Build(); + + // Act var handler = _factory.Get(downstreamRoute); + + // Assert handler.IsError.ShouldBeFalse(); handler.Data.ShouldBeOfType(); } diff --git a/test/Ocelot.UnitTests/Requester/TracingHandlerFactoryTests.cs b/test/Ocelot.UnitTests/Requester/TracingHandlerFactoryTests.cs index 4ce681797..17e6afc34 100644 --- a/test/Ocelot.UnitTests/Requester/TracingHandlerFactoryTests.cs +++ b/test/Ocelot.UnitTests/Requester/TracingHandlerFactoryTests.cs @@ -24,9 +24,12 @@ public TracingHandlerFactoryTests() } [Fact] - public void should_return() + public void Should_return() { + // Arrange, Act var handler = _factory.Get(); + + // Assert handler.ShouldBeOfType(); } } diff --git a/test/Ocelot.UnitTests/Responder/AnyError.cs b/test/Ocelot.UnitTests/Responder/AnyError.cs index da80a3400..54004046a 100644 --- a/test/Ocelot.UnitTests/Responder/AnyError.cs +++ b/test/Ocelot.UnitTests/Responder/AnyError.cs @@ -5,10 +5,8 @@ namespace Ocelot.UnitTests.Responder; internal class AnyError : Error { public AnyError() : base("blahh", OcelotErrorCode.UnknownError, 404) - { - } + { } public AnyError(OcelotErrorCode errorCode) : base("blah", errorCode, 404) - { - } + { } } diff --git a/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs b/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs index c5a69fa22..54e482f8b 100644 --- a/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs +++ b/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs @@ -1,22 +1,14 @@ using Ocelot.Errors; -using Ocelot.Responder; - +using Ocelot.Responder; namespace Ocelot.UnitTests.Responder; public class ErrorsToHttpStatusCodeMapperTests : UnitTest { - private readonly IErrorsToHttpStatusCodeMapper _codeMapper; - private int _result; - private List _errors; - - public ErrorsToHttpStatusCodeMapperTests() - { - _codeMapper = new ErrorsToHttpStatusCodeMapper(); - } + private readonly ErrorsToHttpStatusCodeMapper _codeMapper = new(); [Theory] [InlineData(OcelotErrorCode.UnauthenticatedError)] - public void should_return_unauthorized(OcelotErrorCode errorCode) + public void Should_return_unauthorized(OcelotErrorCode errorCode) { ShouldMapErrorToStatusCode(errorCode, HttpStatusCode.Unauthorized); } @@ -27,14 +19,14 @@ public void should_return_unauthorized(OcelotErrorCode errorCode) [InlineData(OcelotErrorCode.ScopeNotAuthorizedError)] [InlineData(OcelotErrorCode.UnauthorizedError)] [InlineData(OcelotErrorCode.UserDoesNotHaveClaimError)] - public void should_return_forbidden(OcelotErrorCode errorCode) + public void Should_return_forbidden(OcelotErrorCode errorCode) { ShouldMapErrorToStatusCode(errorCode, HttpStatusCode.Forbidden); } [Theory] [InlineData(OcelotErrorCode.RequestTimedOutError)] - public void should_return_service_unavailable(OcelotErrorCode errorCode) + public void Should_return_service_unavailable(OcelotErrorCode errorCode) { ShouldMapErrorToStatusCode(errorCode, HttpStatusCode.ServiceUnavailable); } @@ -43,14 +35,14 @@ public void should_return_service_unavailable(OcelotErrorCode errorCode) [InlineData(OcelotErrorCode.UnableToCompleteRequestError)] [InlineData(OcelotErrorCode.CouldNotFindLoadBalancerCreator)] [InlineData(OcelotErrorCode.ErrorInvokingLoadBalancerCreator)] - public void should_return_internal_server_error(OcelotErrorCode errorCode) + public void Should_return_internal_server_error(OcelotErrorCode errorCode) { ShouldMapErrorToStatusCode(errorCode, HttpStatusCode.InternalServerError); } [Theory] [InlineData(OcelotErrorCode.ConnectionToDownstreamServiceError)] - public void should_return_bad_gateway_error(OcelotErrorCode errorCode) + public void Should_return_bad_gateway_error(OcelotErrorCode errorCode) { ShouldMapErrorToStatusCode(errorCode, HttpStatusCode.BadGateway); } @@ -78,13 +70,13 @@ public void should_return_bad_gateway_error(OcelotErrorCode errorCode) [InlineData(OcelotErrorCode.UnknownError)] [InlineData(OcelotErrorCode.UnmappableRequestError)] [InlineData(OcelotErrorCode.UnsupportedAuthenticationProviderError)] - public void should_return_not_found(OcelotErrorCode errorCode) + public void Should_return_not_found(OcelotErrorCode errorCode) { ShouldMapErrorToStatusCode(errorCode, HttpStatusCode.NotFound); } [Fact] - public void should_return_request_entity_too_large() + public void Should_return_request_entity_too_large() { ShouldMapErrorsToStatusCode(new() { OcelotErrorCode.PayloadTooLargeError }, HttpStatusCode.RequestEntityTooLarge); } @@ -129,12 +121,12 @@ public void ServiceUnavailableErrorsHaveThirdHighestPriority() } [Fact] - public void check_we_have_considered_all_errors_in_these_tests() + public void Check_we_have_considered_all_errors_in_these_tests() { // If this test fails then it's because the number of error codes has changed. // You should make the appropriate changes to the test cases here to ensure // they cover all the error codes, and then modify this assertion. - Enum.GetNames(typeof(OcelotErrorCode)).Length.ShouldBe(42, "Looks like the number of error codes has changed. Do you need to modify ErrorsToHttpStatusCodeMapper?"); + Enum.GetNames().Length.ShouldBe(42, "Looks like the number of error codes has changed. Do you need to modify ErrorsToHttpStatusCodeMapper?"); } private void ShouldMapErrorToStatusCode(OcelotErrorCode errorCode, HttpStatusCode expectedHttpStatusCode) @@ -144,36 +136,17 @@ private void ShouldMapErrorToStatusCode(OcelotErrorCode errorCode, HttpStatusCod private void ShouldMapErrorsToStatusCode(List errorCodes, HttpStatusCode expectedHttpStatusCode) { + // Arrange var errors = new List(); - foreach (var errorCode in errorCodes) { errors.Add(new AnyError(errorCode)); } - this.Given(x => x.GivenThereAreErrors(errors)) - .When(x => x.WhenIGetErrorStatusCode()) - .Then(x => x.ThenTheResponseIsStatusCodeIs(expectedHttpStatusCode)) - .BDDfy(); - } - - private void GivenThereAreErrors(List errors) - { - _errors = errors; - } - - private void WhenIGetErrorStatusCode() - { - _result = _codeMapper.Map(_errors); - } - - private void ThenTheResponseIsStatusCodeIs(int expectedCode) - { - _result.ShouldBe(expectedCode); - } + // Act + var result = _codeMapper.Map(errors); - private void ThenTheResponseIsStatusCodeIs(HttpStatusCode expectedCode) - { - _result.ShouldBe((int)expectedCode); + // Assert + result.ShouldBe((int)expectedHttpStatusCode); } } diff --git a/test/Ocelot.UnitTests/Responder/HttpContextResponderTests.cs b/test/Ocelot.UnitTests/Responder/HttpContextResponderTests.cs index 6f50c6b65..5d5944dfa 100644 --- a/test/Ocelot.UnitTests/Responder/HttpContextResponderTests.cs +++ b/test/Ocelot.UnitTests/Responder/HttpContextResponderTests.cs @@ -17,8 +17,9 @@ public HttpContextResponderTests() } [Fact] - public async Task should_remove_transfer_encoding_header() + public async Task Should_remove_transfer_encoding_header() { + // Arrange var httpContext = new DefaultHttpContext(); var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.OK, new List>> @@ -26,39 +27,50 @@ public async Task should_remove_transfer_encoding_header() new("Transfer-Encoding", new List {"woop"}), }, "some reason"); + // Act await _responder.SetResponseOnHttpContext(httpContext, response); - var header = httpContext.Response.Headers["Transfer-Encoding"]; + + // Assert + var header = httpContext.Response.Headers.TransferEncoding; header.ShouldBeEmpty(); } [Fact] - public async Task should_ignore_content_if_null() + public async Task Should_ignore_content_if_null() { + // Arrange var httpContext = new DefaultHttpContext(); var response = new DownstreamResponse(null, HttpStatusCode.OK, new List>>(), "some reason"); + // Assert await Should.NotThrowAsync(async () => { + // Act await _responder.SetResponseOnHttpContext(httpContext, response); }); } [Fact] - public async Task should_have_content_length() + public async Task Should_have_content_length() { + // Arrange var httpContext = new DefaultHttpContext(); var response = new DownstreamResponse(new StringContent("test"), HttpStatusCode.OK, new List>>(), "some reason"); + // Act await _responder.SetResponseOnHttpContext(httpContext, response); + + // Assert var header = httpContext.Response.Headers["Content-Length"]; header.First().ShouldBe("4"); } [Fact] - public async Task should_add_header() + public async Task Should_add_header() { + // Arrange var httpContext = new DefaultHttpContext(); var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.OK, new List>> @@ -66,14 +78,18 @@ public async Task should_add_header() new("test", new List {"test"}), }, "some reason"); + // Act await _responder.SetResponseOnHttpContext(httpContext, response); + + // Assert var header = httpContext.Response.Headers["test"]; header.First().ShouldBe("test"); } [Fact] - public async Task should_add_reason_phrase() + public async Task Should_add_reason_phrase() { + // Arrange var httpContext = new DefaultHttpContext(); var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.OK, new List>> @@ -81,14 +97,20 @@ public async Task should_add_reason_phrase() new("test", new List {"test"}), }, "some reason"); + // Act await _responder.SetResponseOnHttpContext(httpContext, response); + + // Assert httpContext.Response.HttpContext.Features.Get().ReasonPhrase.ShouldBe(response.ReasonPhrase); } [Fact] - public void should_call_without_exception() + public void Should_call_without_exception() { + // Arrange var httpContext = new DefaultHttpContext(); + + // Act, Assert _responder.SetErrorResponseOnContext(httpContext, 500); } } diff --git a/test/Ocelot.UnitTests/Responder/ResponderMiddlewareTests.cs b/test/Ocelot.UnitTests/Responder/ResponderMiddlewareTests.cs index d154aa91a..e359a3dca 100644 --- a/test/Ocelot.UnitTests/Responder/ResponderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Responder/ResponderMiddlewareTests.cs @@ -1,6 +1,5 @@ using Microsoft.AspNetCore.Http; using Ocelot.DownstreamRouteFinder.Finder; -using Ocelot.Errors; using Ocelot.Logging; using Ocelot.Middleware; using Ocelot.Responder; @@ -16,7 +15,7 @@ public class ResponderMiddlewareTests : UnitTest private readonly Mock _logger; private readonly ResponderMiddleware _middleware; private readonly RequestDelegate _next; - private readonly HttpContext _httpContext; + private readonly DefaultHttpContext _httpContext; public ResponderMiddlewareTests() { @@ -31,52 +30,44 @@ public ResponderMiddlewareTests() } [Fact] - public void should_not_return_any_errors() + public async Task Should_not_return_any_errors() { - this.Given(x => x.GivenTheHttpResponseMessageIs(new DownstreamResponse(new HttpResponseMessage()))) - .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.ThenThereAreNoErrors()) - .BDDfy(); - } + // Arrange + _httpContext.Items.UpsertDownstreamResponse(new DownstreamResponse(new HttpResponseMessage())); - [Fact] - public void should_return_any_errors() - { - this.Given(x => x.GivenTheHttpResponseMessageIs(new DownstreamResponse(new HttpResponseMessage()))) - .And(x => x.GivenThereArePipelineErrors(new UnableToFindDownstreamRouteError("/path", "GET"))) - .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.ThenThereAreNoErrors()) - .BDDfy(); + // Act + await _middleware.Invoke(_httpContext); + + // Assert + _httpContext.Items.Errors().ShouldBeEmpty(); } [Fact] - public void should_not_call_responder_when_null_downstream_response() + public async Task Should_return_any_errors() { - this._responder.Reset(); - this.Given(x => x.GivenTheHttpResponseMessageIs(null)) - .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.ThenThereAreNoErrors()) - .Then(x => x._responder.VerifyNoOtherCalls()) - .BDDfy(); - } + // Arrange + _httpContext.Items.UpsertDownstreamResponse(new DownstreamResponse(new HttpResponseMessage())); + _httpContext.Items.SetError(new UnableToFindDownstreamRouteError("/path", "GET")); - private async Task WhenICallTheMiddleware() - { + // Act await _middleware.Invoke(_httpContext); - } - private void GivenTheHttpResponseMessageIs(DownstreamResponse response) - { - _httpContext.Items.UpsertDownstreamResponse(response); + // Assert + _httpContext.Items.Errors().Count.ShouldBe(1); } - private void ThenThereAreNoErrors() + [Fact] + public async Task Should_not_call_responder_when_null_downstream_response() { - //todo a better assert? - } + // Arrange + this._responder.Reset(); + _httpContext.Items.UpsertDownstreamResponse(null); - private void GivenThereArePipelineErrors(Error error) - { - _httpContext.Items.SetError(error); + // Act + await _middleware.Invoke(_httpContext); + + // Assert + _httpContext.Items.Errors().ShouldBeEmpty(); + _responder.VerifyNoOtherCalls(); } } diff --git a/test/Ocelot.UnitTests/Security/IPSecurityPolicyTests.cs b/test/Ocelot.UnitTests/Security/IPSecurityPolicyTests.cs index bd7b9cd3d..43098aff9 100644 --- a/test/Ocelot.UnitTests/Security/IPSecurityPolicyTests.cs +++ b/test/Ocelot.UnitTests/Security/IPSecurityPolicyTests.cs @@ -1,5 +1,4 @@ using Microsoft.AspNetCore.Http; -using Ocelot.Configuration; using Ocelot.Configuration.Builder; using Ocelot.Configuration.Creator; using Ocelot.Configuration.File; @@ -14,7 +13,7 @@ public sealed class IPSecurityPolicyTests : UnitTest { private readonly DownstreamRouteBuilder _downstreamRouteBuilder; private readonly IPSecurityPolicy _policy; - private readonly HttpContext _context; + private readonly DefaultHttpContext _context; private readonly SecurityOptionsCreator _securityOptionsCreator; private static readonly FileGlobalConfiguration Empty = new(); @@ -31,258 +30,360 @@ public IPSecurityPolicyTests() [Fact] public void Should_No_blocked_Ip_and_allowed_Ip() { - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); + // Arrange, Act + var actual = WhenTheSecurityPolicy(new()); + + // Assert Assert.False(actual.IsError); } [Fact] public void Should_blockedIp_clientIp_block() { + // Arrange _context.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.1")[0]; - GivenSetBlockedIP(); - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); + var options = new FileSecurityOptions(blockedIPs: "192.168.1.1"); + + // Act + var actual = WhenTheSecurityPolicy(options); + + // Assert Assert.True(actual.IsError); } [Fact] public void Should_blockedIp_clientIp_Not_block() { + // Arrange _context.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.2")[0]; - GivenSetBlockedIP(); - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); + var options = new FileSecurityOptions(blockedIPs: "192.168.1.1"); + + // Act + var actual = WhenTheSecurityPolicy(options); + + // Assert Assert.False(actual.IsError); } [Fact] public void Should_allowedIp_clientIp_block() { + // Arrange _context.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.1")[0]; - GivenSetAllowedIP(); - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); + var options = new FileSecurityOptions("192.168.1.1"); + + // Act + var actual = WhenTheSecurityPolicy(options); + + // Assert Assert.False(actual.IsError); } [Fact] public void Should_allowedIp_clientIp_Not_block() { + // Arrange _context.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.2")[0]; - GivenSetAllowedIP(); - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); + var options = new FileSecurityOptions("192.168.1.1"); + + // Act + var actual = WhenTheSecurityPolicy(options); + + // Assert Assert.True(actual.IsError); } [Fact] public void Should_cidrNotation_allowed24_clientIp_block() { + // Arrange _context.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.10.5")[0]; - GivenCidr24AllowedIP(); - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); + var options = new FileSecurityOptions("192.168.1.0/24"); + + // Act + var actual = WhenTheSecurityPolicy(options); + + // Assert Assert.True(actual.IsError); } [Fact] public void Should_cidrNotation_allowed24_clientIp_not_block() { + // Arrange _context.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.5")[0]; - GivenCidr24AllowedIP(); - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); + var options = new FileSecurityOptions("192.168.1.0/24"); + + // Act + var actual = WhenTheSecurityPolicy(options); + + // Assert Assert.False(actual.IsError); } [Fact] public void Should_cidrNotation_allowed29_clientIp_block() { + // Arrange _context.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.10")[0]; - GivenCidr29AllowedIP(); - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); + var options = new FileSecurityOptions("192.168.1.0/29"); + + // Act + var actual = WhenTheSecurityPolicy(options); + + // Assert Assert.True(actual.IsError); } [Fact] public void Should_cidrNotation_blocked24_clientIp_block() { + // Arrange _context.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.1")[0]; - GivenCidr24BlockedIP(); - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); + var options = new FileSecurityOptions(blockedIPs: "192.168.1.0/24"); + + // Act + var actual = WhenTheSecurityPolicy(options); + + // Assert Assert.True(actual.IsError); } [Fact] public void Should_cidrNotation_blocked24_clientIp_not_block() { + // Arrange _context.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.10.1")[0]; - GivenCidr24BlockedIP(); - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); + var options = new FileSecurityOptions(blockedIPs: "192.168.1.0/24"); + + // Act + var actual = WhenTheSecurityPolicy(options); + + // Assert Assert.False(actual.IsError); } [Fact] public void Should_range_allowed_clientIp_block() { + // Arrange _context.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.15")[0]; - GivenRangeAllowedIP(); - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); + var options = new FileSecurityOptions("192.168.1.0-192.168.1.10"); + + // Act + var actual = WhenTheSecurityPolicy(options); + + // Assert Assert.True(actual.IsError); } [Fact] public void Should_range_allowed_clientIp_not_block() { + // Arrange _context.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.8")[0]; - GivenRangeAllowedIP(); - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); + var options = new FileSecurityOptions("192.168.1.0-192.168.1.10"); + + // Act + var actual = WhenTheSecurityPolicy(options); + + // Assert Assert.False(actual.IsError); } [Fact] public void Should_range_blocked_clientIp_block() { + // Arrange _context.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.5")[0]; - GivenRangeBlockedIP(); - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); + var options = new FileSecurityOptions(blockedIPs: "192.168.1.0-192.168.1.10"); + + // Act + var actual = WhenTheSecurityPolicy(options); + + // Assert Assert.True(actual.IsError); } [Fact] public void Should_range_blocked_clientIp_not_block() { + // Arrange _context.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.15")[0]; - GivenRangeBlockedIP(); - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); + var options = new FileSecurityOptions(blockedIPs: "192.168.1.0-192.168.1.10"); + + // Act + var actual = WhenTheSecurityPolicy(options); + + // Assert Assert.False(actual.IsError); } [Fact] public void Should_shortRange_allowed_clientIp_block() { + // Arrange _context.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.15")[0]; - GivenShortRangeAllowedIP(); - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); + var options = new FileSecurityOptions("192.168.1.0-10"); + + // Act + var actual = WhenTheSecurityPolicy(options); + + // Assert Assert.True(actual.IsError); } [Fact] public void Should_shortRange_allowed_clientIp_not_block() { + // Arrange _context.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.8")[0]; - GivenShortRangeAllowedIP(); - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); + var options = new FileSecurityOptions("192.168.1.0-10"); + + // Act + var actual = WhenTheSecurityPolicy(options); + + // Assert Assert.False(actual.IsError); } [Fact] public void Should_shortRange_blocked_clientIp_block() { + // Arrange _context.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.5")[0]; - GivenShortRangeBlockedIP(); - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); + var options = new FileSecurityOptions(blockedIPs: "192.168.1.0-10"); + + // Act + var actual = WhenTheSecurityPolicy(options); + + // Assert Assert.True(actual.IsError); } [Fact] public void Should_shortRange_blocked_clientIp_not_block() { + // Arrange _context.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.15")[0]; - GivenShortRangeBlockedIP(); - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); + var options = new FileSecurityOptions(blockedIPs: "192.168.1.0-10"); + + // Act + var actual = WhenTheSecurityPolicy(options); + + // Assert Assert.False(actual.IsError); } [Fact] public void Should_ipSubnet_allowed_clientIp_block() { + // Arrange _context.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.10.15")[0]; - GivenIpSubnetAllowedIP(); - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); + var options = new FileSecurityOptions("192.168.1.0/255.255.255.0"); + + // Act + var actual = WhenTheSecurityPolicy(options); + + // Assert Assert.True(actual.IsError); } [Fact] public void Should_ipSubnet_allowed_clientIp_not_block() { + // Arrange _context.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.15")[0]; - GivenIpSubnetAllowedIP(); - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); + var options = new FileSecurityOptions("192.168.1.0/255.255.255.0"); + + // Act + var actual = WhenTheSecurityPolicy(options); + + // Assert Assert.False(actual.IsError); } [Fact] public void Should_ipSubnet_blocked_clientIp_block() { + // Arrange _context.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.15")[0]; - GivenIpSubnetBlockedIP(); - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); + var options = new FileSecurityOptions(blockedIPs: "192.168.1.0/255.255.255.0"); + + // Act + var actual = WhenTheSecurityPolicy(options); + + // Assert Assert.True(actual.IsError); } [Fact] public void Should_ipSubnet_blocked_clientIp_not_block() { + // Arrange _context.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.10.1")[0]; - GivenIpSubnetBlockedIP(); - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); + var options = new FileSecurityOptions(blockedIPs: "192.168.1.0/255.255.255.0"); + + // Act + var actual = WhenTheSecurityPolicy(options); + + // Assert Assert.False(actual.IsError); } [Fact] public void Should_exludeAllowedFromBlocked_moreAllowed_clientIp_block() { + // Arrange _context.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.150")[0]; - GivenIpMoreAllowedThanBlocked(false); - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); + var options = new FileSecurityOptions("192.168.0.0/255.255.0.0", "192.168.1.100-200", false); + + // Act + var actual = WhenTheSecurityPolicy(options); + + // Assert Assert.True(actual.IsError); } [Fact] public void Should_exludeAllowedFromBlocked_moreAllowed_clientIp_not_block() { + // Arrange _context.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.150")[0]; - GivenIpMoreAllowedThanBlocked(true); - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); + var options = new FileSecurityOptions("192.168.0.0/255.255.0.0", "192.168.1.100-200", true); + + // Act + var actual = WhenTheSecurityPolicy(options); + + // Assert Assert.False(actual.IsError); } [Fact] public void Should_exludeAllowedFromBlocked_moreBlocked_clientIp_block() { + // Arrange _context.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.10")[0]; - GivenIpMoreBlockedThanAllowed(false); - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); + var options = new FileSecurityOptions("192.168.1.10-20", "192.168.1.0/23", false); + + // Act + var actual = WhenTheSecurityPolicy(options); + + // Assert Assert.True(actual.IsError); } [Fact] public void Should_exludeAllowedFromBlocked_moreBlocked_clientIp_not_block() { + // Arrange _context.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.10")[0]; - GivenIpMoreBlockedThanAllowed(true); - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); + var options = new FileSecurityOptions("192.168.1.10-20", "192.168.1.0/23", true); + + // Act + var actual = WhenTheSecurityPolicy(options); + + // Assert Assert.False(actual.IsError); } @@ -290,109 +391,29 @@ public void Should_exludeAllowedFromBlocked_moreBlocked_clientIp_not_block() [Trait("Feat", "2170")] public void Should_route_config_overrides_global_config() { + // Arrange _context.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.10")[0]; - GivenRouteConfigAndGlobalConfig(false); - GivenSetDownstreamRoute(); - var actual = WhenTheSecurityPolicy(); - Assert.False(actual.IsError); - } - - private void GivenSetAllowedIP() - { - _downstreamRouteBuilder.WithSecurityOptions(new SecurityOptions("192.168.1.1")); - } - - private void GivenSetBlockedIP() - { - _downstreamRouteBuilder.WithSecurityOptions(new SecurityOptions(blocked: "192.168.1.1")); - } - - private void GivenSetDownstreamRoute() - { - _context.Items.UpsertDownstreamRoute(_downstreamRouteBuilder.Build()); - } - - private void GivenCidr24AllowedIP() - { - var securityOptions = _securityOptionsCreator.Create(new FileSecurityOptions("192.168.1.0/24"), Empty); - _downstreamRouteBuilder.WithSecurityOptions(securityOptions); - } - - private void GivenCidr29AllowedIP() - { - var securityOptions = _securityOptionsCreator.Create(new FileSecurityOptions("192.168.1.0/29"), Empty); - _downstreamRouteBuilder.WithSecurityOptions(securityOptions); - } - - private void GivenCidr24BlockedIP() - { - var securityOptions = _securityOptionsCreator.Create(new FileSecurityOptions(blockedIPs: "192.168.1.0/24"), Empty); - _downstreamRouteBuilder.WithSecurityOptions(securityOptions); - } - - private void GivenRangeAllowedIP() - { - var securityOptions = _securityOptionsCreator.Create(new FileSecurityOptions("192.168.1.0-192.168.1.10"), Empty); - _downstreamRouteBuilder.WithSecurityOptions(securityOptions); - } - - private void GivenRangeBlockedIP() - { - var securityOptions = _securityOptionsCreator.Create(new FileSecurityOptions(blockedIPs: "192.168.1.0-192.168.1.10"), Empty); - _downstreamRouteBuilder.WithSecurityOptions(securityOptions); - } - - private void GivenShortRangeAllowedIP() - { - var securityOptions = _securityOptionsCreator.Create(new FileSecurityOptions("192.168.1.0-10"), Empty); - _downstreamRouteBuilder.WithSecurityOptions(securityOptions); - } - - private void GivenShortRangeBlockedIP() - { - var securityOptions = _securityOptionsCreator.Create(new FileSecurityOptions(blockedIPs: "192.168.1.0-10"), Empty); - _downstreamRouteBuilder.WithSecurityOptions(securityOptions); - } - - private void GivenIpSubnetAllowedIP() - { - var securityOptions = _securityOptionsCreator.Create(new FileSecurityOptions("192.168.1.0/255.255.255.0"), Empty); - _downstreamRouteBuilder.WithSecurityOptions(securityOptions); - } - - private void GivenIpSubnetBlockedIP() - { - var securityOptions = _securityOptionsCreator.Create(new FileSecurityOptions(blockedIPs: "192.168.1.0/255.255.255.0"), Empty); - _downstreamRouteBuilder.WithSecurityOptions(securityOptions); - } - - private void GivenIpMoreAllowedThanBlocked(bool excludeAllowedInBlocked) - { - var securityOptions = _securityOptionsCreator.Create(new FileSecurityOptions("192.168.0.0/255.255.0.0", "192.168.1.100-200", excludeAllowedInBlocked), Empty); - _downstreamRouteBuilder.WithSecurityOptions(securityOptions); - } - - private void GivenIpMoreBlockedThanAllowed(bool excludeAllowedInBlocked) - { - var securityOptions = _securityOptionsCreator.Create(new FileSecurityOptions("192.168.1.10-20", "192.168.1.0/23", excludeAllowedInBlocked), Empty); - _downstreamRouteBuilder.WithSecurityOptions(securityOptions); - } - - private void GivenRouteConfigAndGlobalConfig(bool excludeAllowedInBlocked) - { var globalConfig = new FileGlobalConfiguration { SecurityOptions = new FileSecurityOptions("192.168.1.30-50", "192.168.1.1-100", true), }; - - var localConfig = new FileSecurityOptions("192.168.1.10", "", excludeAllowedInBlocked); + var localConfig = new FileSecurityOptions("192.168.1.10", "", false); - var securityOptions = _securityOptionsCreator.Create(localConfig, globalConfig); - _downstreamRouteBuilder.WithSecurityOptions(securityOptions); + // Act + var actual = WhenTheSecurityPolicy(localConfig, globalConfig); + + // Assert + Assert.False(actual.IsError); } - private Response WhenTheSecurityPolicy() + private Response WhenTheSecurityPolicy(FileSecurityOptions options, FileGlobalConfiguration global = null) { + // Arrange + var securityOptions = _securityOptionsCreator.Create(options, global ?? Empty); + _downstreamRouteBuilder.WithSecurityOptions(securityOptions); + _context.Items.UpsertDownstreamRoute(_downstreamRouteBuilder.Build()); + + // Act return _policy.Security(_context.Items.DownstreamRoute(), _context); } } diff --git a/test/Ocelot.UnitTests/ServiceDiscovery/ConfigurationServiceProviderTests.cs b/test/Ocelot.UnitTests/ServiceDiscovery/ConfigurationServiceProviderTests.cs index 0e0239afe..5c4f66804 100644 --- a/test/Ocelot.UnitTests/ServiceDiscovery/ConfigurationServiceProviderTests.cs +++ b/test/Ocelot.UnitTests/ServiceDiscovery/ConfigurationServiceProviderTests.cs @@ -6,42 +6,24 @@ namespace Ocelot.UnitTests.ServiceDiscovery; public class ConfigurationServiceProviderTests : UnitTest { private ConfigurationServiceProvider _serviceProvider; - private List _result; - private List _expected; [Fact] - public void should_return_services() + public async Task Should_return_services() { + // Arrange var hostAndPort = new ServiceHostAndPort("127.0.0.1", 80); - var services = new List { new("product", hostAndPort, string.Empty, string.Empty, Array.Empty()), }; + _serviceProvider = new ConfigurationServiceProvider(services); - this.Given(x => x.GivenServices(services)) - .When(x => x.WhenIGetTheService()) - .Then(x => x.ThenTheFollowingIsReturned(services)) - .BDDfy(); - } - - private void GivenServices(List services) - { - _expected = services; - } - - private async Task WhenIGetTheService() - { - _serviceProvider = new ConfigurationServiceProvider(_expected); - _result = await _serviceProvider.GetAsync(); - } - - private void ThenTheFollowingIsReturned(List services) - { - _result[0].HostAndPort.DownstreamHost.ShouldBe(services[0].HostAndPort.DownstreamHost); - - _result[0].HostAndPort.DownstreamPort.ShouldBe(services[0].HostAndPort.DownstreamPort); + // Act + var result = await _serviceProvider.GetAsync(); - _result[0].Name.ShouldBe(services[0].Name); + // Assert + result[0].HostAndPort.DownstreamHost.ShouldBe(services[0].HostAndPort.DownstreamHost); + result[0].HostAndPort.DownstreamPort.ShouldBe(services[0].HostAndPort.DownstreamPort); + result[0].Name.ShouldBe(services[0].Name); } } diff --git a/test/Ocelot.UnitTests/ServiceDiscovery/ServiceDiscoveryProviderFactoryTests.cs b/test/Ocelot.UnitTests/ServiceDiscovery/ServiceDiscoveryProviderFactoryTests.cs index 0016a6639..b0b816c76 100644 --- a/test/Ocelot.UnitTests/ServiceDiscovery/ServiceDiscoveryProviderFactoryTests.cs +++ b/test/Ocelot.UnitTests/ServiceDiscovery/ServiceDiscoveryProviderFactoryTests.cs @@ -13,10 +13,8 @@ namespace Ocelot.UnitTests.ServiceDiscovery; public class ServiceDiscoveryProviderFactoryTests : UnitTest { - private ServiceProviderConfiguration _serviceConfig; private Response _result; private ServiceDiscoveryProviderFactory _factory; - private DownstreamRoute _route; private readonly Mock _loggerFactory; private readonly Mock _logger; private IServiceProvider _provider; @@ -37,93 +35,119 @@ public ServiceDiscoveryProviderFactoryTests() [Fact] public void Should_return_no_service_provider() { + // Arrange var serviceConfig = new ServiceProviderConfigurationBuilder() .Build(); - var route = new DownstreamRouteBuilder().Build(); - this.Given(x => x.GivenTheRoute(serviceConfig, route)) - .When(x => x.WhenIGetTheServiceProvider()) - .Then(x => x.ThenTheServiceProviderIs()) - .BDDfy(); + // Act + WhenIGetTheServiceProvider(serviceConfig, route); + + // Assert + _result.Data.ShouldBeOfType(); } [Fact] - public void Should_return_list_of_configuration_services() + public async Task Should_return_list_of_configuration_services() { + // Arrange var serviceConfig = new ServiceProviderConfigurationBuilder() .Build(); - var downstreamAddresses = new List { new("asdf.com", 80), new("abc.com", 80), }; - var route = new DownstreamRouteBuilder().WithDownstreamAddresses(downstreamAddresses).Build(); - this.Given(x => x.GivenTheRoute(serviceConfig, route)) - .When(x => x.WhenIGetTheServiceProvider()) - .Then(x => x.ThenTheServiceProviderIs()) - .Then(x => ThenTheFollowingServicesAreReturned(downstreamAddresses)) - .BDDfy(); + // Act + WhenIGetTheServiceProvider(serviceConfig, route); + + // Assert + _result.Data.ShouldBeOfType(); + + // Assert: Then The Following Services Are Returned + var result = (ConfigurationServiceProvider)_result.Data; + var services = await result.GetAsync(); + for (var i = 0; i < services.Count; i++) + { + var service = services[i]; + var downstreamAddress = downstreamAddresses[i]; + + service.HostAndPort.DownstreamHost.ShouldBe(downstreamAddress.Host); + service.HostAndPort.DownstreamPort.ShouldBe(downstreamAddress.Port); + } } [Fact] public void Should_return_provider_because_type_matches_reflected_type_from_delegate() { + // Arrange var route = new DownstreamRouteBuilder() .WithServiceName("product") .WithUseServiceDiscovery(true) .Build(); - var serviceConfig = new ServiceProviderConfigurationBuilder() .WithType(nameof(Fake)) .Build(); + GivenAFakeDelegate(); - this.Given(x => x.GivenTheRoute(serviceConfig, route)) - .And(x => GivenAFakeDelegate()) - .When(x => x.WhenIGetTheServiceProvider()) - .Then(x => x.ThenTheDelegateIsCalled()) - .BDDfy(); + // Act + WhenIGetTheServiceProvider(serviceConfig, route); + + // Assert + _result.Data.GetType().Name.ShouldBe("Fake"); } [Fact] public void Should_not_return_provider_because_type_doesnt_match_reflected_type_from_delegate() { + // Arrange var route = new DownstreamRouteBuilder() .WithServiceName("product") .WithUseServiceDiscovery(true) .Build(); - var serviceConfig = new ServiceProviderConfigurationBuilder() .WithType("Wookie") .Build(); + GivenAFakeDelegate(); + + // Act + WhenIGetTheServiceProvider(serviceConfig, route); + + // Assert + _result.IsError.ShouldBeTrue(); + _result.Errors.Count.ShouldBe(1); + + _logInformationMessages.ShouldNotBeNull() + .Count.ShouldBe(2); + _logger.Verify(x => x.LogInformation(It.IsAny>()), + Times.Exactly(2)); - this.Given(x => x.GivenTheRoute(serviceConfig, route)) - .And(x => GivenAFakeDelegate()) - .When(x => x.WhenIGetTheServiceProvider()) - .Then(x => x.ThenTheResultIsError()) - .BDDfy(); + _logWarningMessages.ShouldNotBeNull() + .Count.ShouldBe(1); + _logger.Verify(x => x.LogWarning(It.IsAny>()), + Times.Once()); } [Fact] public void Should_return_service_fabric_provider() { + // Arrange var route = new DownstreamRouteBuilder() .WithServiceName("product") .WithUseServiceDiscovery(true) .Build(); - var serviceConfig = new ServiceProviderConfigurationBuilder() .WithType("ServiceFabric") .Build(); + GivenAFakeDelegate(); + + // Act + WhenIGetTheServiceProvider(serviceConfig, route); - this.Given(x => x.GivenTheRoute(serviceConfig, route)) - .And(x => GivenAFakeDelegate()) - .When(x => x.WhenIGetTheServiceProvider()) - .Then(x => x.ThenTheServiceProviderIs()) - .BDDfy(); + // Assert + _result.Data.ShouldBeOfType(); } [Theory] @@ -135,25 +159,29 @@ public void Should_return_service_fabric_provider() [InlineData("unknown", false)] public void Should_return_Kubernetes_provider_with_type_names_from_docs(string typeName, bool success) { + // Arrange var route = new DownstreamRouteBuilder() .WithServiceName(nameof(Should_return_Kubernetes_provider_with_type_names_from_docs)) .WithUseServiceDiscovery(true) .Build(); - var serviceConfig = new ServiceProviderConfigurationBuilder() .WithType(typeName) .WithPollingInterval(Timeout.Infinite) .Build(); - this.Given(x => x.GivenTheRoute(serviceConfig, route)) - .And(x => GivenKubernetesProvider()) - .When(x => x.WhenIGetTheServiceProvider()) - .Then(x => EnsureResponse(success)) - .BDDfy(); - } - - private void EnsureResponse(bool success) - { + // Arrange: Given Kubernetes Provider + var k8sClient = new Mock(); + _collection + .AddSingleton(KubernetesProviderFactory.Get) + .AddSingleton(k8sClient.Object) + .AddSingleton(_loggerFactory.Object); + _provider = _collection.BuildServiceProvider(true); + _factory = new ServiceDiscoveryProviderFactory(_loggerFactory.Object, _provider); + + // Act + WhenIGetTheServiceProvider(serviceConfig, route); + + // Assert if (success) { _result.ShouldBeOfType>(); @@ -162,92 +190,31 @@ private void EnsureResponse(bool success) { _result.ShouldBeOfType>(); } - } + } private void GivenAFakeDelegate() { - ServiceDiscoveryFinderDelegate fake = (provider, config, name) => new Fake(); - _collection.AddSingleton(fake); - _provider = _collection.BuildServiceProvider(true); - _factory = new ServiceDiscoveryProviderFactory(_loggerFactory.Object, _provider); - } - - private void GivenKubernetesProvider() - { - var k8sClient = new Mock(); - _collection - .AddSingleton(KubernetesProviderFactory.Get) - .AddSingleton(k8sClient.Object) - .AddSingleton(_loggerFactory.Object); + static IServiceDiscoveryProvider fake(IServiceProvider provider, ServiceProviderConfiguration config, DownstreamRoute name) => new Fake(); + _collection.AddSingleton((ServiceDiscoveryFinderDelegate)fake); _provider = _collection.BuildServiceProvider(true); _factory = new ServiceDiscoveryProviderFactory(_loggerFactory.Object, _provider); } private class Fake : IServiceDiscoveryProvider { - public Task> GetAsync() - { - return null; - } + public Task> GetAsync() => null; } - private void ThenTheDelegateIsCalled() - { - _result.Data.GetType().Name.ShouldBe("Fake"); - } - - private void ThenTheResultIsError() - { - _result.IsError.ShouldBeTrue(); - _result.Errors.Count.ShouldBe(1); - - _logInformationMessages.ShouldNotBeNull() - .Count.ShouldBe(2); - _logger.Verify(x => x.LogInformation(It.IsAny>()), - Times.Exactly(2)); + private readonly List _logInformationMessages = new(); + private readonly List _logWarningMessages = new(); - _logWarningMessages.ShouldNotBeNull() - .Count.ShouldBe(1); - _logger.Verify(x => x.LogWarning(It.IsAny>()), - Times.Once()); - } - - private async Task ThenTheFollowingServicesAreReturned(List downstreamAddresses) - { - var result = (ConfigurationServiceProvider)_result.Data; - var services = await result.GetAsync(); - - for (var i = 0; i < services.Count; i++) - { - var service = services[i]; - var downstreamAddress = downstreamAddresses[i]; - - service.HostAndPort.DownstreamHost.ShouldBe(downstreamAddress.Host); - service.HostAndPort.DownstreamPort.ShouldBe(downstreamAddress.Port); - } - } - - private void GivenTheRoute(ServiceProviderConfiguration serviceConfig, DownstreamRoute route) - { - _serviceConfig = serviceConfig; - _route = route; - } - - private List _logInformationMessages = new(); - private List _logWarningMessages = new(); - - private void WhenIGetTheServiceProvider() + private void WhenIGetTheServiceProvider(ServiceProviderConfiguration serviceConfig, DownstreamRoute route) { _logger.Setup(x => x.LogInformation(It.IsAny>())) .Callback>(myFunc => _logInformationMessages.Add(myFunc.Invoke())); _logger.Setup(x => x.LogWarning(It.IsAny>())) .Callback>(myFunc => _logWarningMessages.Add(myFunc.Invoke())); - _result = _factory.Get(_serviceConfig, _route); - } - - private void ThenTheServiceProviderIs() - { - _result.Data.ShouldBeOfType(); + _result = _factory.Get(serviceConfig, route); } } diff --git a/test/Ocelot.UnitTests/ServiceDiscovery/ServiceFabricServiceDiscoveryProviderTests.cs b/test/Ocelot.UnitTests/ServiceDiscovery/ServiceFabricServiceDiscoveryProviderTests.cs index 3b18a714b..e4c3bd9d5 100644 --- a/test/Ocelot.UnitTests/ServiceDiscovery/ServiceFabricServiceDiscoveryProviderTests.cs +++ b/test/Ocelot.UnitTests/ServiceDiscovery/ServiceFabricServiceDiscoveryProviderTests.cs @@ -1,45 +1,26 @@ using Ocelot.ServiceDiscovery.Configuration; using Ocelot.ServiceDiscovery.Providers; -using Ocelot.Values; namespace Ocelot.UnitTests.ServiceDiscovery; public class ServiceFabricServiceDiscoveryProviderTests : UnitTest { - private ServiceFabricServiceDiscoveryProvider _provider; - private ServiceFabricConfiguration _config; - private string _host; - private string _serviceName; - private int _port; - private List _services; - [Fact] - public void should_return_service_fabric_naming_service() - { - this.Given(x => GivenTheFollowing()) - .When(x => WhenIGet()) - .Then(x => ThenTheServiceFabricNamingServiceIsRetured()) - .BDDfy(); - } - - private void GivenTheFollowing() + public async Task Should_return_service_fabric_naming_service() { - _host = "localhost"; - _serviceName = "OcelotServiceApplication/OcelotApplicationService"; - _port = 19081; - } + // Arrange + const string host = "localhost"; + const int port = 19081; + const string serviceName = "OcelotServiceApplication/OcelotApplicationService"; - private async Task WhenIGet() - { - _config = new ServiceFabricConfiguration(_host, _port, _serviceName); - _provider = new ServiceFabricServiceDiscoveryProvider(_config); - _services = await _provider.GetAsync(); - } + // Act + var config = new ServiceFabricConfiguration(host, port, serviceName); + var provider = new ServiceFabricServiceDiscoveryProvider(config); + var services = await provider.GetAsync(); - private void ThenTheServiceFabricNamingServiceIsRetured() - { - _services.Count.ShouldBe(1); - _services[0].HostAndPort.DownstreamHost.ShouldBe(_host); - _services[0].HostAndPort.DownstreamPort.ShouldBe(_port); + // Assert: Then The ServiceFabric Naming Service Is Retured + services.Count.ShouldBe(1); + services[0].HostAndPort.DownstreamHost.ShouldBe(host); + services[0].HostAndPort.DownstreamPort.ShouldBe(port); } } diff --git a/test/Ocelot.UnitTests/ServiceDiscovery/ServiceRegistryTests.cs b/test/Ocelot.UnitTests/ServiceDiscovery/ServiceRegistryTests.cs index 0c53edb0a..00a8be111 100644 --- a/test/Ocelot.UnitTests/ServiceDiscovery/ServiceRegistryTests.cs +++ b/test/Ocelot.UnitTests/ServiceDiscovery/ServiceRegistryTests.cs @@ -1,6 +1,5 @@ using Ocelot.Values; -// nothing in use namespace Ocelot.UnitTests.ServiceDiscovery; public class ServiceRegistryTests : UnitTest @@ -17,108 +16,63 @@ public ServiceRegistryTests() } [Fact] - public void should_register_service() + public void Should_register_service() { - this.Given(x => x.GivenAServiceToRegister("product", "localhost:5000", 80)) - .When(x => x.WhenIRegisterTheService()) - .Then(x => x.ThenTheServiceIsRegistered()) - .BDDfy(); - } - - [Fact] - public void should_lookup_service() - { - this.Given(x => x.GivenAServiceIsRegistered("product", "localhost:600", 80)) - .When(x => x.WhenILookupTheService("product")) - .Then(x => x.ThenTheServiceDetailsAreReturned()) - .BDDfy(); - } + // Arrange + _service = new Service("product", new ServiceHostAndPort("localhost:5000", 80), string.Empty, string.Empty, Array.Empty()); - private void ThenTheServiceDetailsAreReturned() - { - _services[0].HostAndPort.DownstreamHost.ShouldBe(_service.HostAndPort.DownstreamHost); - _services[0].HostAndPort.DownstreamPort.ShouldBe(_service.HostAndPort.DownstreamPort); - _services[0].Name.ShouldBe(_service.Name); - } + // Act + _serviceRegistry.Register(_service); - private void WhenILookupTheService(string name) - { - _services = _serviceRegistry.Lookup(name); + // Assert: Then The Service Is Registered + var serviceNameAndAddress = _serviceRepository.Get(_service.Name); + serviceNameAndAddress[0].HostAndPort.DownstreamHost.ShouldBe(_service.HostAndPort.DownstreamHost); + serviceNameAndAddress[0].HostAndPort.DownstreamPort.ShouldBe(_service.HostAndPort.DownstreamPort); + serviceNameAndAddress[0].Name.ShouldBe(_service.Name); } - private void GivenAServiceIsRegistered(string name, string address, int port) + [Fact] + public void Should_lookup_service() { - _service = new Service(name, new ServiceHostAndPort(address, port), string.Empty, string.Empty, Array.Empty()); + // Arrange + _service = new Service("product", new ServiceHostAndPort("localhost:600", 80), string.Empty, string.Empty, Array.Empty()); _serviceRepository.Set(_service); - } - private void GivenAServiceToRegister(string name, string address, int port) - { - _service = new Service(name, new ServiceHostAndPort(address, port), string.Empty, string.Empty, Array.Empty()); - } - - private void WhenIRegisterTheService() - { - _serviceRegistry.Register(_service); - } + // Act + _services = _serviceRegistry.Lookup("product"); - private void ThenTheServiceIsRegistered() - { - var serviceNameAndAddress = _serviceRepository.Get(_service.Name); - serviceNameAndAddress[0].HostAndPort.DownstreamHost.ShouldBe(_service.HostAndPort.DownstreamHost); - serviceNameAndAddress[0].HostAndPort.DownstreamPort.ShouldBe(_service.HostAndPort.DownstreamPort); - serviceNameAndAddress[0].Name.ShouldBe(_service.Name); + // Assert + _services[0].HostAndPort.DownstreamHost.ShouldBe(_service.HostAndPort.DownstreamHost); + _services[0].HostAndPort.DownstreamPort.ShouldBe(_service.HostAndPort.DownstreamPort); + _services[0].Name.ShouldBe(_service.Name); } } public interface IServiceRegistry { void Register(Service serviceNameAndAddress); - List Lookup(string name); } public class ServiceRegistry : IServiceRegistry { private readonly IServiceRepository _repository; - - public ServiceRegistry(IServiceRepository repository) - { - _repository = repository; - } - - public void Register(Service serviceNameAndAddress) - { - _repository.Set(serviceNameAndAddress); - } - - public List Lookup(string name) - { - return _repository.Get(name); - } + public ServiceRegistry(IServiceRepository repository) => _repository = repository; + public void Register(Service serviceNameAndAddress) => _repository.Set(serviceNameAndAddress); + public List Lookup(string name) => _repository.Get(name); } public interface IServiceRepository { List Get(string serviceName); - void Set(Service serviceNameAndAddress); } public class ServiceRepository : IServiceRepository { private readonly Dictionary> _registeredServices; - - public ServiceRepository() - { - _registeredServices = new Dictionary>(); - } - - public List Get(string serviceName) - { - return _registeredServices[serviceName]; - } - + public ServiceRepository() => _registeredServices = new Dictionary>(); + public List Get(string serviceName) => _registeredServices[serviceName]; public void Set(Service serviceNameAndAddress) { if (_registeredServices.TryGetValue(serviceNameAndAddress.Name, out var services)) diff --git a/test/Ocelot.UnitTests/UnitTest.cs b/test/Ocelot.UnitTests/UnitTest.cs index a50782f5a..8cc0b6e1b 100644 --- a/test/Ocelot.UnitTests/UnitTest.cs +++ b/test/Ocelot.UnitTests/UnitTest.cs @@ -1,12 +1,9 @@ -using TestStack.BDDfy.Configuration; - -namespace Ocelot.UnitTests; +namespace Ocelot.UnitTests; public class UnitTest { public UnitTest() { - Configurator.Processors.ConsoleReport.Disable(); } protected readonly Guid _testId = Guid.NewGuid(); diff --git a/test/Ocelot.UnitTests/Usings.cs b/test/Ocelot.UnitTests/Usings.cs index 9648f6280..caec2c0b1 100644 --- a/test/Ocelot.UnitTests/Usings.cs +++ b/test/Ocelot.UnitTests/Usings.cs @@ -13,5 +13,4 @@ global using Ocelot.Testing; global using Shouldly; global using System.Net; -global using TestStack.BDDfy; global using Xunit; diff --git a/test/Ocelot.UnitTests/WebSockets/MockWebSocket.cs b/test/Ocelot.UnitTests/WebSockets/MockWebSocket.cs index 7b73a2b5e..0fac890a2 100644 --- a/test/Ocelot.UnitTests/WebSockets/MockWebSocket.cs +++ b/test/Ocelot.UnitTests/WebSockets/MockWebSocket.cs @@ -14,20 +14,12 @@ internal class MockWebSocket : WebSocket private string closeStatusDescription; private WebSocketState state; private readonly string subProtocol; - private readonly ConcurrentQueue receiveBuffers = new ConcurrentQueue(); - private readonly AsyncAutoResetEvent receiveEvent = new AsyncAutoResetEvent(false); + private readonly ConcurrentQueue receiveBuffers = new(); + private readonly AsyncAutoResetEvent receiveEvent = new(false); private bool disposedValue; - public MockWebSocket(string subProtocol = null) - { - this.subProtocol = subProtocol; - } - - public void SetState(WebSocketState state) - { - this.state = state; - } - + public MockWebSocket(string subProtocol = null) => this.subProtocol = subProtocol; + public void SetState(WebSocketState state) => this.state = state; public EventHandler MessageSent { get; set; } public Task InvokeReceiveAsync(ArraySegment buffer, WebSocketMessageType messageType, bool endOfMessage) @@ -43,17 +35,10 @@ public Task InvokeReceiveAsync(ArraySegment buffer, WebSocketMessageType m } public override WebSocketCloseStatus? CloseStatus => closeStatus; - public override string CloseStatusDescription => closeStatusDescription; - public override WebSocketState State => state; - public override string SubProtocol => subProtocol; - - public override void Abort() - { - throw new NotImplementedException(); - } + public override void Abort() => throw new NotImplementedException(); public override Task CloseAsync(WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken) @@ -62,7 +47,7 @@ public override Task CloseAsync(WebSocketCloseStatus closeStatus, string statusD closeStatusDescription = statusDescription; receiveBuffers.Enqueue(new MessageData() { - Buffer = new ArraySegment(new byte[] { }), + Buffer = new ArraySegment(Array.Empty()), EndOfMessage = true, MessageType = WebSocketMessageType.Close, }); @@ -70,11 +55,7 @@ public override Task CloseAsync(WebSocketCloseStatus closeStatus, string statusD return Task.CompletedTask; } - public override Task CloseOutputAsync(WebSocketCloseStatus closeStatus, string statusDescription, - CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } + public override Task CloseOutputAsync(WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken) => throw new NotImplementedException(); public override async Task ReceiveAsync( ArraySegment buffer, @@ -89,8 +70,7 @@ public override async Task ReceiveAsync( var endOfMessage = true; var messageType = WebSocketMessageType.Close; - MessageData received = null; - if (receiveBuffers.TryPeek(out received)) + if (receiveBuffers.TryPeek(out MessageData received)) { messageType = received.MessageType; if (received.Buffer.Count <= buffer.Count) diff --git a/test/Ocelot.UnitTests/WebSockets/WebSocketsProxyMiddlewareTests.cs b/test/Ocelot.UnitTests/WebSockets/WebSocketsProxyMiddlewareTests.cs index 42af9716d..e1ee2deb5 100644 --- a/test/Ocelot.UnitTests/WebSockets/WebSocketsProxyMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/WebSockets/WebSocketsProxyMiddlewareTests.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Http; +using Ocelot.Configuration; using Ocelot.Configuration.Builder; using Ocelot.Logging; using Ocelot.Middleware; @@ -41,15 +42,19 @@ public WebSocketsProxyMiddlewareTests() } [Fact] - public void ShouldIgnoreAllSslWarningsWhenDangerousAcceptAnyServerCertificateValidatorIsTrue() + public async Task ShouldIgnoreAllSslWarningsWhenDangerousAcceptAnyServerCertificateValidatorIsTrue() { + // Arrange List actual = new(); - this.Given(x => x.GivenPropertyDangerousAcceptAnyServerCertificateValidator(true, actual)) - .And(x => x.AndDoNotSetupProtocolsAndHeaders()) - .And(x => x.AndDoNotConnectReally(null)) - .When(x => x.WhenInvokeWithHttpContext()) - .Then(x => x.ThenIgnoredAllSslWarnings(actual)) - .BDDfy(); + GivenPropertyDangerousAcceptAnyServerCertificateValidator(true, actual); + AndDoNotSetupProtocolsAndHeaders(); + AndDoNotConnectReally(null); + + // Act + await _middleware.Invoke(_context.Object); + + // Assert + ThenIgnoredAllSslWarnings(actual); } private void GivenPropertyDangerousAcceptAnyServerCertificateValidator(bool enabled, List actual) @@ -100,11 +105,6 @@ private void AndDoNotConnectReally(Action callbackConnec serverSocket.SetupGet(x => x.CloseStatus).Returns(WebSocketCloseStatus.Empty); } - private async Task WhenInvokeWithHttpContext() - { - await _middleware.Invoke(_context.Object); - } - private void ThenIgnoredAllSslWarnings(List actual) { var route = _context.Object.Items.DownstreamRoute(); @@ -130,15 +130,19 @@ private void ThenIgnoredAllSslWarnings(List actual) [InlineData("http", "ws")] [InlineData("https", "wss")] [InlineData("ftp", "ftp")] - public void ShouldReplaceNonWsSchemes(string scheme, string expectedScheme) + public async Task ShouldReplaceNonWsSchemes(string scheme, string expectedScheme) { + // Arrange List actual = new(); - this.Given(x => x.GivenNonWebsocketScheme(scheme, actual)) - .And(x => x.AndDoNotSetupProtocolsAndHeaders()) - .And(x => x.AndDoNotConnectReally((uri, token) => actual.Add(uri))) - .When(x => x.WhenInvokeWithHttpContext()) - .Then(x => x.ThenNonWsSchemesAreReplaced(scheme, expectedScheme, actual)) - .BDDfy(); + GivenNonWebsocketScheme(scheme, actual); + AndDoNotSetupProtocolsAndHeaders(); + AndDoNotConnectReally((uri, token) => actual.Add(uri)); + + // Act + await _middleware.Invoke(_context.Object); + + // Assert + ThenNonWsSchemesAreReplaced(scheme, expectedScheme, actual); } private void GivenNonWebsocketScheme(string scheme, List actual) @@ -148,8 +152,8 @@ private void GivenNonWebsocketScheme(string scheme, List actual) var route = new DownstreamRouteBuilder().Build(); var items = new Dictionary { - { "DownstreamRequest", request }, - { "DownstreamRoute", route }, + { nameof(DownstreamRequest), request }, + { nameof(DownstreamRoute), route }, }; _context.SetupGet(x => x.Items).Returns(items);