From bf0a31f8de9b5388e7df3f63d92343b2e761b90f Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Tue, 7 Nov 2017 08:05:41 +0000 Subject: [PATCH 01/11] moving load balancer creation into its own class --- .../Finder/DownstreamRouteFinder.cs | 2 +- .../LoadBalancer/LoadBalancerCreator.cs | 24 ++++++++ .../LoadBalancer/LoadBalancerCreatorTests.cs | 57 +++++++++++++++++++ 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 src/Ocelot/LoadBalancer/LoadBalancerCreator.cs create mode 100644 test/Ocelot.UnitTests/LoadBalancer/LoadBalancerCreatorTests.cs diff --git a/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs b/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs index cd2c098f..d6509b23 100644 --- a/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs +++ b/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs @@ -27,7 +27,7 @@ namespace Ocelot.DownstreamRouteFinder.Finder { upstreamUrlPath = upstreamUrlPath.SetLastCharacterAs('/'); - var configuration = await _configProvider.Get(); + var configuration = await _configProvider.Get(); var applicableReRoutes = configuration.Data.ReRoutes.Where(r => r.UpstreamHttpMethod.Count == 0 || r.UpstreamHttpMethod.Select(x => x.Method.ToLower()).Contains(upstreamHttpMethod.ToLower())); diff --git a/src/Ocelot/LoadBalancer/LoadBalancerCreator.cs b/src/Ocelot/LoadBalancer/LoadBalancerCreator.cs new file mode 100644 index 00000000..70a42148 --- /dev/null +++ b/src/Ocelot/LoadBalancer/LoadBalancerCreator.cs @@ -0,0 +1,24 @@ +using System.Threading.Tasks; +using Ocelot.Configuration; +using Ocelot.LoadBalancer.LoadBalancers; + +namespace Ocelot.LoadBalancer +{ + public class LoadBalancerCreator + { + private readonly ILoadBalancerHouse _loadBalancerHouse; + private readonly ILoadBalancerFactory _loadBalanceFactory; + + public LoadBalancerCreator(ILoadBalancerHouse loadBalancerHouse, ILoadBalancerFactory loadBalancerFactory) + { + _loadBalancerHouse = loadBalancerHouse; + _loadBalanceFactory = loadBalancerFactory; + } + + public async Task SetupLoadBalancer(ReRoute reRoute) + { + var loadBalancer = await _loadBalanceFactory.Get(reRoute); + _loadBalancerHouse.Add(reRoute.ReRouteKey, loadBalancer); + } + } +} \ No newline at end of file diff --git a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerCreatorTests.cs b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerCreatorTests.cs new file mode 100644 index 00000000..9b9a2df1 --- /dev/null +++ b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerCreatorTests.cs @@ -0,0 +1,57 @@ +using Xunit; +using Shouldly; +using TestStack.BDDfy; +using Ocelot.LoadBalancer; +using Ocelot.LoadBalancer.LoadBalancers; +using Moq; +using Ocelot.Configuration; +using System.Collections.Generic; +using Ocelot.Values; +using Ocelot.Configuration.Builder; + +namespace Ocelot.UnitTests.LoadBalancer +{ + public class LoadBalancerCreatorTests + { + private LoadBalancerCreator _creator; + private ILoadBalancerHouse _house; + private Mock _factory; + private ReRoute _reRoute; + + public LoadBalancerCreatorTests() + { + _house = new LoadBalancerHouse(); + _factory = new Mock(); + _creator = new LoadBalancerCreator(_house, _factory.Object); + } + + [Fact] + public void should_create_load_balancer() + { + var reRoute = new ReRouteBuilder().WithLoadBalancerKey("Test").Build(); + this.Given(x => GivenTheFollowingReRoute(reRoute)) + .When(x => WhenICallTheCreator()) + .Then(x => x.ThenTheLoadBalancerIsCreated()) + .BDDfy(); + } + + private void GivenTheFollowingReRoute(ReRoute reRoute) + { + _reRoute = reRoute; + _factory + .Setup(x => x.Get(It.IsAny())) + .ReturnsAsync(new NoLoadBalancer(new List())); + } + + private void WhenICallTheCreator() + { + _creator.SetupLoadBalancer(_reRoute).Wait(); + } + + private void ThenTheLoadBalancerIsCreated() + { + var lb = _house.Get(_reRoute.ReRouteKey); + lb.ShouldNotBeNull(); + } + } +} \ No newline at end of file From ab14df91278b6437c7841c38c3622a1373afa95d Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Tue, 7 Nov 2017 08:12:48 +0000 Subject: [PATCH 02/11] plugged new lb creator into tests --- .../Creator/FileOcelotConfigurationCreator.cs | 18 +++------- .../ServiceCollectionExtensions.cs | 2 ++ .../LoadBalancer/ILoadBalancerCreator.cs | 10 ++++++ .../LoadBalancer/LoadBalancerCreator.cs | 2 +- .../FileConfigurationCreatorTests.cs | 34 ++++--------------- 5 files changed, 25 insertions(+), 41 deletions(-) create mode 100644 src/Ocelot/LoadBalancer/ILoadBalancerCreator.cs diff --git a/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs index 9fe77bbf..fd27e4e6 100644 --- a/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs +++ b/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs @@ -9,6 +9,7 @@ using Ocelot.Configuration.Builder; using Ocelot.Configuration.File; using Ocelot.Configuration.Parser; using Ocelot.Configuration.Validator; +using Ocelot.LoadBalancer; using Ocelot.LoadBalancer.LoadBalancers; using Ocelot.Logging; using Ocelot.Requester.QoS; @@ -25,8 +26,7 @@ namespace Ocelot.Configuration.Creator private readonly IOptions _options; private readonly IConfigurationValidator _configurationValidator; private readonly IOcelotLogger _logger; - private readonly ILoadBalancerFactory _loadBalanceFactory; - private readonly ILoadBalancerHouse _loadBalancerHouse; + private readonly ILoadBalancerCreator _lbCreator; private readonly IQoSProviderFactory _qoSProviderFactory; private readonly IQosProviderHouse _qosProviderHouse; private readonly IClaimsToThingCreator _claimsToThingCreator; @@ -44,8 +44,7 @@ namespace Ocelot.Configuration.Creator IOptions options, IConfigurationValidator configurationValidator, IOcelotLoggerFactory loggerFactory, - ILoadBalancerFactory loadBalancerFactory, - ILoadBalancerHouse loadBalancerHouse, + ILoadBalancerCreator lbCreator, IQoSProviderFactory qoSProviderFactory, IQosProviderHouse qosProviderHouse, IClaimsToThingCreator claimsToThingCreator, @@ -60,13 +59,12 @@ namespace Ocelot.Configuration.Creator IHttpHandlerOptionsCreator httpHandlerOptionsCreator ) { + _lbCreator = lbCreator; _regionCreator = regionCreator; _rateLimitOptionsCreator = rateLimitOptionsCreator; _requestIdKeyCreator = requestIdKeyCreator; _upstreamTemplatePatternCreator = upstreamTemplatePatternCreator; _authOptionsCreator = authOptionsCreator; - _loadBalanceFactory = loadBalancerFactory; - _loadBalancerHouse = loadBalancerHouse; _qoSProviderFactory = qoSProviderFactory; _qosProviderHouse = qosProviderHouse; _options = options; @@ -176,7 +174,7 @@ namespace Ocelot.Configuration.Creator .WithHttpHandlerOptions(httpHandlerOptions) .Build(); - await SetupLoadBalancer(reRoute); + await _lbCreator.SetupLoadBalancer(reRoute); SetupQosProvider(reRoute); return reRoute; } @@ -188,12 +186,6 @@ namespace Ocelot.Configuration.Creator return loadBalancerKey; } - private async Task SetupLoadBalancer(ReRoute reRoute) - { - var loadBalancer = await _loadBalanceFactory.Get(reRoute); - _loadBalancerHouse.Add(reRoute.ReRouteKey, loadBalancer); - } - private void SetupQosProvider(ReRoute reRoute) { var loadBalancer = _qoSProviderFactory.Get(reRoute); diff --git a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs index 430ae18d..85f0f4b6 100644 --- a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs @@ -46,6 +46,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Ocelot.Configuration; using FileConfigurationProvider = Ocelot.Configuration.Provider.FileConfigurationProvider; +using Ocelot.LoadBalancer; namespace Ocelot.DependencyInjection { @@ -93,6 +94,7 @@ namespace Ocelot.DependencyInjection .AddJsonFormatters(); services.AddLogging(); + services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); diff --git a/src/Ocelot/LoadBalancer/ILoadBalancerCreator.cs b/src/Ocelot/LoadBalancer/ILoadBalancerCreator.cs new file mode 100644 index 00000000..e60c36f0 --- /dev/null +++ b/src/Ocelot/LoadBalancer/ILoadBalancerCreator.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; +using Ocelot.Configuration; + +namespace Ocelot.LoadBalancer +{ + public interface ILoadBalancerCreator + { + Task SetupLoadBalancer(ReRoute reRoute); + } +} \ No newline at end of file diff --git a/src/Ocelot/LoadBalancer/LoadBalancerCreator.cs b/src/Ocelot/LoadBalancer/LoadBalancerCreator.cs index 70a42148..da28e5b8 100644 --- a/src/Ocelot/LoadBalancer/LoadBalancerCreator.cs +++ b/src/Ocelot/LoadBalancer/LoadBalancerCreator.cs @@ -4,7 +4,7 @@ using Ocelot.LoadBalancer.LoadBalancers; namespace Ocelot.LoadBalancer { - public class LoadBalancerCreator + public class LoadBalancerCreator : ILoadBalancerCreator { private readonly ILoadBalancerHouse _loadBalancerHouse; private readonly ILoadBalancerFactory _loadBalanceFactory; diff --git a/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs index d897bf64..0440e7ee 100644 --- a/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs @@ -19,7 +19,7 @@ using Xunit; namespace Ocelot.UnitTests.Configuration { using System.Collections; - + using Ocelot.LoadBalancer; using Ocelot.UnitTests.TestData; public class FileConfigurationCreatorTests @@ -30,8 +30,6 @@ namespace Ocelot.UnitTests.Configuration private FileConfiguration _fileConfiguration; private readonly Mock _logger; private readonly FileOcelotConfigurationCreator _ocelotConfigurationCreator; - private readonly Mock _loadBalancerFactory; - private readonly Mock _loadBalancerHouse; private readonly Mock _loadBalancer; private readonly Mock _qosProviderFactory; private readonly Mock _qosProviderHouse; @@ -46,6 +44,7 @@ namespace Ocelot.UnitTests.Configuration private Mock _rateLimitOptions; private Mock _regionCreator; private Mock _httpHandlerOptionsCreator; + private Mock _lbCreator; public FileConfigurationCreatorTests() { @@ -55,8 +54,6 @@ namespace Ocelot.UnitTests.Configuration _logger = new Mock(); _validator = new Mock(); _fileConfig = new Mock>(); - _loadBalancerFactory = new Mock(); - _loadBalancerHouse = new Mock(); _loadBalancer = new Mock(); _claimsToThingCreator = new Mock(); _authOptionsCreator = new Mock(); @@ -68,10 +65,11 @@ namespace Ocelot.UnitTests.Configuration _rateLimitOptions = new Mock(); _regionCreator = new Mock(); _httpHandlerOptionsCreator = new Mock(); + _lbCreator = new Mock(); _ocelotConfigurationCreator = new FileOcelotConfigurationCreator( _fileConfig.Object, _validator.Object, _logger.Object, - _loadBalancerFactory.Object, _loadBalancerHouse.Object, + _lbCreator.Object, _qosProviderFactory.Object, _qosProviderHouse.Object, _claimsToThingCreator.Object, _authOptionsCreator.Object, _upstreamTemplatePatternCreator.Object, _requestIdKeyCreator.Object, _serviceProviderConfigCreator.Object, _qosOptionsCreator.Object, _fileReRouteOptionsCreator.Object, @@ -212,10 +210,8 @@ namespace Ocelot.UnitTests.Configuration })) .And(x => x.GivenTheConfigIsValid()) .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions)) - .And(x => x.GivenTheLoadBalancerFactoryReturns()) .When(x => x.WhenICreateTheConfig()) - .Then(x => x.TheLoadBalancerFactoryIsCalledCorrectly()) - .And(x => x.ThenTheLoadBalancerHouseIsCalledCorrectly()) + .And(x => x.ThenTheLoadBalancerCreatorIsCalledCorrectly()) .BDDfy(); } @@ -516,7 +512,6 @@ namespace Ocelot.UnitTests.Configuration .And(x => x.GivenTheAuthOptionsCreatorReturns(authenticationOptions)) .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions)) .And(x => x.GivenTheClaimsToThingCreatorReturns(new List { new ClaimToThing("CustomerId", "CustomerId", "", 0) })) - .And(x => x.GivenTheLoadBalancerFactoryReturns()) .When(x => x.WhenICreateTheConfig()) .Then(x => x.ThenTheReRoutesAre(expected)) .And(x => x.ThenTheAuthenticationOptionsAre(expected)) @@ -550,7 +545,6 @@ namespace Ocelot.UnitTests.Configuration .And(x => x.GivenTheConfigIsValid()) .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions)) .And(x => x.GivenTheAuthOptionsCreatorReturns(authenticationOptions)) - .And(x => x.GivenTheLoadBalancerFactoryReturns()) .When(x => x.WhenICreateTheConfig()) .Then(x => x.ThenTheReRoutesAre(expected)) .And(x => x.ThenTheAuthenticationOptionsAre(expected)) @@ -634,23 +628,9 @@ namespace Ocelot.UnitTests.Configuration } } - private void GivenTheLoadBalancerFactoryReturns() + private void ThenTheLoadBalancerCreatorIsCalledCorrectly() { - _loadBalancerFactory - .Setup(x => x.Get(It.IsAny())) - .ReturnsAsync(_loadBalancer.Object); - } - - private void TheLoadBalancerFactoryIsCalledCorrectly() - { - _loadBalancerFactory - .Verify(x => x.Get(It.IsAny()), Times.Once); - } - - private void ThenTheLoadBalancerHouseIsCalledCorrectly() - { - _loadBalancerHouse - .Verify(x => x.Add(It.IsAny(), _loadBalancer.Object), Times.Once); + _lbCreator.Verify(x => x.SetupLoadBalancer(It.IsAny()), Times.Once); } private void GivenTheQosProviderFactoryReturns() From e43732290ab6aa77e0f7009b088dfc73fd6fa5b8 Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Wed, 8 Nov 2017 21:26:49 +0000 Subject: [PATCH 03/11] massive refactor to handle creating load balancer first time a re route is called --- global.json | 2 +- .../Configuration/Builder/ReRouteBuilder.cs | 26 ++++-- .../ServiceProviderConfigurationBuilder.cs | 32 +------ .../Creator/FileOcelotConfigurationCreator.cs | 11 +-- .../IServiceProviderConfigurationCreator.cs | 2 +- .../ServiceProviderConfigurationCreator.cs | 9 +- .../Configuration/IOcelotConfiguration.cs | 1 + .../Configuration/OcelotConfiguration.cs | 4 +- src/Ocelot/Configuration/ReRoute.cs | 11 ++- .../ServiceProviderConfiguraion.cs | 11 +-- .../ServiceCollectionExtensions.cs | 1 - .../LoadBalancer/ILoadBalancerCreator.cs | 10 --- .../LoadBalancer/LoadBalancerCreator.cs | 24 ----- .../LoadBalancers/ILoadBalancerFactory.cs | 2 +- .../LoadBalancers/ILoadBalancerHouse.cs | 7 +- .../LoadBalancers/LoadBalancerFactory.cs | 6 +- .../LoadBalancers/LoadBalancerHouse.cs | 50 ++++++++--- .../Middleware/LoadBalancingMiddleware.cs | 10 ++- .../IServiceDiscoveryProviderFactory.cs | 2 +- .../ServiceDiscoveryProviderFactory.cs | 10 +-- .../ConfigurationInConsulTests.cs | 71 ++++++++++++++- .../RequestId:0HL9635DF6NNV | 0 .../FileConfigurationCreatorTests.cs | 60 +------------ .../FileConfigurationSetterTests.cs | 4 +- .../InMemoryConfigurationRepositoryTests.cs | 2 + .../OcelotConfigurationProviderTests.cs | 7 +- .../ServiceProviderCreatorTests.cs | 5 +- .../DownstreamRouteFinderTests.cs | 38 +++++--- .../LoadBalancer/LoadBalancerCreatorTests.cs | 57 ------------ .../LoadBalancer/LoadBalancerFactoryTests.cs | 22 +++-- .../LoadBalancer/LoadBalancerHouseTests.cs | 87 ++++++++++++------- .../LoadBalancerMiddlewareTests.cs | 9 +- .../ServiceProviderFactoryTests.cs | 20 +++-- 33 files changed, 294 insertions(+), 319 deletions(-) delete mode 100644 src/Ocelot/LoadBalancer/ILoadBalancerCreator.cs delete mode 100644 src/Ocelot/LoadBalancer/LoadBalancerCreator.cs create mode 100644 test/Ocelot.AcceptanceTests/RequestId:0HL9635DF6NNV delete mode 100644 test/Ocelot.UnitTests/LoadBalancer/LoadBalancerCreatorTests.cs diff --git a/global.json b/global.json index 332404a7..9a3e328e 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "projects": [ "src", "test" ], "sdk": { - "version": "2.0.0" + "version": "2.0.2" } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs b/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs index 272242c8..b823e6ac 100644 --- a/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs +++ b/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs @@ -26,13 +26,14 @@ namespace Ocelot.Configuration.Builder private string _downstreamHost; private int _downstreamPort; private string _loadBalancer; - private ServiceProviderConfiguration _serviceProviderConfiguraion; private bool _useQos; private QoSOptions _qosOptions; private HttpHandlerOptions _httpHandlerOptions; public bool _enableRateLimiting; public RateLimitOptions _rateLimitOptions; private string _authenticationProviderKey; + private bool _useServiceDiscovery; + private string _serviceName; public ReRouteBuilder WithLoadBalancer(string loadBalancer) { @@ -154,12 +155,6 @@ namespace Ocelot.Configuration.Builder return this; } - public ReRouteBuilder WithServiceProviderConfiguraion(ServiceProviderConfiguration serviceProviderConfiguraion) - { - _serviceProviderConfiguraion = serviceProviderConfiguraion; - return this; - } - public ReRouteBuilder WithAuthenticationOptions(AuthenticationOptions authenticationOptions) { _authenticationOptions = authenticationOptions; @@ -190,6 +185,18 @@ namespace Ocelot.Configuration.Builder return this; } + public ReRouteBuilder WithUseServiceDiscovery(bool useServiceDiscovery) + { + _useServiceDiscovery = useServiceDiscovery; + return this; + } + + public ReRouteBuilder WithServiceName(string serviceName) + { + _serviceName = serviceName; + return this; + } + public ReRoute Build() { return new ReRoute( @@ -212,12 +219,13 @@ namespace Ocelot.Configuration.Builder _downstreamHost, _downstreamPort, _loadBalancerKey, - _serviceProviderConfiguraion, _useQos, _qosOptions, _enableRateLimiting, _rateLimitOptions, - _httpHandlerOptions); + _httpHandlerOptions, + _useServiceDiscovery, + _serviceName); } } } diff --git a/src/Ocelot/Configuration/Builder/ServiceProviderConfigurationBuilder.cs b/src/Ocelot/Configuration/Builder/ServiceProviderConfigurationBuilder.cs index cb3c521c..fe9f7f3c 100644 --- a/src/Ocelot/Configuration/Builder/ServiceProviderConfigurationBuilder.cs +++ b/src/Ocelot/Configuration/Builder/ServiceProviderConfigurationBuilder.cs @@ -2,38 +2,10 @@ namespace Ocelot.Configuration.Builder { public class ServiceProviderConfigurationBuilder { - private string _serviceName; - private string _downstreamHost; - private int _downstreamPort; - private bool _userServiceDiscovery; private string _serviceDiscoveryProvider; private string _serviceDiscoveryProviderHost; private int _serviceDiscoveryProviderPort; - public ServiceProviderConfigurationBuilder WithServiceName(string serviceName) - { - _serviceName = serviceName; - return this; - } - - public ServiceProviderConfigurationBuilder WithDownstreamHost(string downstreamHost) - { - _downstreamHost = downstreamHost; - return this; - } - - public ServiceProviderConfigurationBuilder WithDownstreamPort(int downstreamPort) - { - _downstreamPort = downstreamPort; - return this; - } - - public ServiceProviderConfigurationBuilder WithUseServiceDiscovery(bool userServiceDiscovery) - { - _userServiceDiscovery = userServiceDiscovery; - return this; - } - public ServiceProviderConfigurationBuilder WithServiceDiscoveryProvider(string serviceDiscoveryProvider) { _serviceDiscoveryProvider = serviceDiscoveryProvider; @@ -52,11 +24,9 @@ namespace Ocelot.Configuration.Builder return this; } - public ServiceProviderConfiguration Build() { - return new ServiceProviderConfiguration(_serviceName, _downstreamHost, _downstreamPort, _userServiceDiscovery, - _serviceDiscoveryProvider, _serviceDiscoveryProviderHost,_serviceDiscoveryProviderPort); + return new ServiceProviderConfiguration(_serviceDiscoveryProvider, _serviceDiscoveryProviderHost,_serviceDiscoveryProviderPort); } } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs index fd27e4e6..5a5bb607 100644 --- a/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs +++ b/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs @@ -26,7 +26,6 @@ namespace Ocelot.Configuration.Creator private readonly IOptions _options; private readonly IConfigurationValidator _configurationValidator; private readonly IOcelotLogger _logger; - private readonly ILoadBalancerCreator _lbCreator; private readonly IQoSProviderFactory _qoSProviderFactory; private readonly IQosProviderHouse _qosProviderHouse; private readonly IClaimsToThingCreator _claimsToThingCreator; @@ -44,7 +43,6 @@ namespace Ocelot.Configuration.Creator IOptions options, IConfigurationValidator configurationValidator, IOcelotLoggerFactory loggerFactory, - ILoadBalancerCreator lbCreator, IQoSProviderFactory qoSProviderFactory, IQosProviderHouse qosProviderHouse, IClaimsToThingCreator claimsToThingCreator, @@ -59,7 +57,6 @@ namespace Ocelot.Configuration.Creator IHttpHandlerOptionsCreator httpHandlerOptionsCreator ) { - _lbCreator = lbCreator; _regionCreator = regionCreator; _rateLimitOptionsCreator = rateLimitOptionsCreator; _requestIdKeyCreator = requestIdKeyCreator; @@ -114,8 +111,10 @@ namespace Ocelot.Configuration.Creator var ocelotReRoute = await SetUpReRoute(reRoute, fileConfiguration.GlobalConfiguration); reRoutes.Add(ocelotReRoute); } + + var serviceProviderConfiguration = _serviceProviderConfigCreator.Create(fileConfiguration.GlobalConfiguration); - return new OcelotConfiguration(reRoutes, fileConfiguration.GlobalConfiguration.AdministrationPath); + return new OcelotConfiguration(reRoutes, fileConfiguration.GlobalConfiguration.AdministrationPath, serviceProviderConfiguration); } private async Task SetUpReRoute(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration) @@ -128,8 +127,6 @@ namespace Ocelot.Configuration.Creator var upstreamTemplatePattern = _upstreamTemplatePatternCreator.Create(fileReRoute); - var serviceProviderConfiguration = _serviceProviderConfigCreator.Create(fileReRoute, globalConfiguration); - var authOptionsForRoute = _authOptionsCreator.Create(fileReRoute); var claimsToHeaders = _claimsToThingCreator.Create(fileReRoute.AddHeadersToRequest); @@ -166,7 +163,6 @@ namespace Ocelot.Configuration.Creator .WithDownstreamHost(fileReRoute.DownstreamHost) .WithDownstreamPort(fileReRoute.DownstreamPort) .WithLoadBalancerKey(reRouteKey) - .WithServiceProviderConfiguraion(serviceProviderConfiguration) .WithIsQos(fileReRouteOptions.IsQos) .WithQosOptions(qosOptions) .WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting) @@ -174,7 +170,6 @@ namespace Ocelot.Configuration.Creator .WithHttpHandlerOptions(httpHandlerOptions) .Build(); - await _lbCreator.SetupLoadBalancer(reRoute); SetupQosProvider(reRoute); return reRoute; } diff --git a/src/Ocelot/Configuration/Creator/IServiceProviderConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/IServiceProviderConfigurationCreator.cs index 1c03d893..ea48ba54 100644 --- a/src/Ocelot/Configuration/Creator/IServiceProviderConfigurationCreator.cs +++ b/src/Ocelot/Configuration/Creator/IServiceProviderConfigurationCreator.cs @@ -4,6 +4,6 @@ namespace Ocelot.Configuration.Creator { public interface IServiceProviderConfigurationCreator { - ServiceProviderConfiguration Create(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration); + ServiceProviderConfiguration Create(FileGlobalConfiguration globalConfiguration); } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/Creator/ServiceProviderConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/ServiceProviderConfigurationCreator.cs index 8132d021..a29e285c 100644 --- a/src/Ocelot/Configuration/Creator/ServiceProviderConfigurationCreator.cs +++ b/src/Ocelot/Configuration/Creator/ServiceProviderConfigurationCreator.cs @@ -5,18 +5,11 @@ namespace Ocelot.Configuration.Creator { public class ServiceProviderConfigurationCreator : IServiceProviderConfigurationCreator { - public ServiceProviderConfiguration Create(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration) + public ServiceProviderConfiguration Create(FileGlobalConfiguration globalConfiguration) { - var useServiceDiscovery = !string.IsNullOrEmpty(fileReRoute.ServiceName) - && !string.IsNullOrEmpty(globalConfiguration?.ServiceDiscoveryProvider?.Provider); - var serviceProviderPort = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0; return new ServiceProviderConfigurationBuilder() - .WithServiceName(fileReRoute.ServiceName) - .WithDownstreamHost(fileReRoute.DownstreamHost) - .WithDownstreamPort(fileReRoute.DownstreamPort) - .WithUseServiceDiscovery(useServiceDiscovery) .WithServiceDiscoveryProvider(globalConfiguration?.ServiceDiscoveryProvider?.Provider) .WithServiceDiscoveryProviderHost(globalConfiguration?.ServiceDiscoveryProvider?.Host) .WithServiceDiscoveryProviderPort(serviceProviderPort) diff --git a/src/Ocelot/Configuration/IOcelotConfiguration.cs b/src/Ocelot/Configuration/IOcelotConfiguration.cs index 566e2f91..cb1ff606 100644 --- a/src/Ocelot/Configuration/IOcelotConfiguration.cs +++ b/src/Ocelot/Configuration/IOcelotConfiguration.cs @@ -6,5 +6,6 @@ namespace Ocelot.Configuration { List ReRoutes { get; } string AdministrationPath {get;} + ServiceProviderConfiguration ServiceProviderConfiguration {get;} } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/OcelotConfiguration.cs b/src/Ocelot/Configuration/OcelotConfiguration.cs index 5655b3c2..b4f5d169 100644 --- a/src/Ocelot/Configuration/OcelotConfiguration.cs +++ b/src/Ocelot/Configuration/OcelotConfiguration.cs @@ -4,13 +4,15 @@ namespace Ocelot.Configuration { public class OcelotConfiguration : IOcelotConfiguration { - public OcelotConfiguration(List reRoutes, string administrationPath) + public OcelotConfiguration(List reRoutes, string administrationPath, ServiceProviderConfiguration serviceProviderConfiguration) { ReRoutes = reRoutes; AdministrationPath = administrationPath; + ServiceProviderConfiguration = serviceProviderConfiguration; } public List ReRoutes { get; } public string AdministrationPath {get;} + public ServiceProviderConfiguration ServiceProviderConfiguration {get;} } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/ReRoute.cs b/src/Ocelot/Configuration/ReRoute.cs index cfc8b9ba..57f8fcc5 100644 --- a/src/Ocelot/Configuration/ReRoute.cs +++ b/src/Ocelot/Configuration/ReRoute.cs @@ -25,15 +25,17 @@ namespace Ocelot.Configuration string downstreamHost, int downstreamPort, string reRouteKey, - ServiceProviderConfiguration serviceProviderConfiguraion, bool isQos, QoSOptions qosOptions, bool enableEndpointRateLimiting, RateLimitOptions ratelimitOptions, - HttpHandlerOptions httpHandlerOptions) + HttpHandlerOptions httpHandlerOptions, + bool useServiceDiscovery, + string serviceName) { + ServiceName = serviceName; + UseServiceDiscovery = useServiceDiscovery; ReRouteKey = reRouteKey; - ServiceProviderConfiguraion = serviceProviderConfiguraion; LoadBalancer = loadBalancer; DownstreamHost = downstreamHost; DownstreamPort = downstreamPort; @@ -83,9 +85,10 @@ namespace Ocelot.Configuration public string LoadBalancer {get;private set;} public string DownstreamHost { get; private set; } public int DownstreamPort { get; private set; } - public ServiceProviderConfiguration ServiceProviderConfiguraion { get; private set; } public bool EnableEndpointEndpointRateLimiting { get; private set; } public RateLimitOptions RateLimitOptions { get; private set; } public HttpHandlerOptions HttpHandlerOptions { get; private set; } + public bool UseServiceDiscovery {get;private set;} + public string ServiceName {get;private set;} } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/ServiceProviderConfiguraion.cs b/src/Ocelot/Configuration/ServiceProviderConfiguraion.cs index 664fa4c3..46351044 100644 --- a/src/Ocelot/Configuration/ServiceProviderConfiguraion.cs +++ b/src/Ocelot/Configuration/ServiceProviderConfiguraion.cs @@ -2,22 +2,13 @@ { public class ServiceProviderConfiguration { - public ServiceProviderConfiguration(string serviceName, string downstreamHost, - int downstreamPort, bool useServiceDiscovery, string serviceDiscoveryProvider, string serviceProviderHost, int serviceProviderPort) + public ServiceProviderConfiguration(string serviceDiscoveryProvider, string serviceProviderHost, int serviceProviderPort) { - ServiceName = serviceName; - DownstreamHost = downstreamHost; - DownstreamPort = downstreamPort; - UseServiceDiscovery = useServiceDiscovery; ServiceDiscoveryProvider = serviceDiscoveryProvider; ServiceProviderHost = serviceProviderHost; ServiceProviderPort = serviceProviderPort; } - public string ServiceName { get; } - public string DownstreamHost { get; } - public int DownstreamPort { get; } - public bool UseServiceDiscovery { get; } public string ServiceDiscoveryProvider { get; } public string ServiceProviderHost { get; private set; } public int ServiceProviderPort { get; private set; } diff --git a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs index 85f0f4b6..33f6dabb 100644 --- a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs @@ -94,7 +94,6 @@ namespace Ocelot.DependencyInjection .AddJsonFormatters(); services.AddLogging(); - services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); diff --git a/src/Ocelot/LoadBalancer/ILoadBalancerCreator.cs b/src/Ocelot/LoadBalancer/ILoadBalancerCreator.cs deleted file mode 100644 index e60c36f0..00000000 --- a/src/Ocelot/LoadBalancer/ILoadBalancerCreator.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Threading.Tasks; -using Ocelot.Configuration; - -namespace Ocelot.LoadBalancer -{ - public interface ILoadBalancerCreator - { - Task SetupLoadBalancer(ReRoute reRoute); - } -} \ No newline at end of file diff --git a/src/Ocelot/LoadBalancer/LoadBalancerCreator.cs b/src/Ocelot/LoadBalancer/LoadBalancerCreator.cs deleted file mode 100644 index da28e5b8..00000000 --- a/src/Ocelot/LoadBalancer/LoadBalancerCreator.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Threading.Tasks; -using Ocelot.Configuration; -using Ocelot.LoadBalancer.LoadBalancers; - -namespace Ocelot.LoadBalancer -{ - public class LoadBalancerCreator : ILoadBalancerCreator - { - private readonly ILoadBalancerHouse _loadBalancerHouse; - private readonly ILoadBalancerFactory _loadBalanceFactory; - - public LoadBalancerCreator(ILoadBalancerHouse loadBalancerHouse, ILoadBalancerFactory loadBalancerFactory) - { - _loadBalancerHouse = loadBalancerHouse; - _loadBalanceFactory = loadBalancerFactory; - } - - public async Task SetupLoadBalancer(ReRoute reRoute) - { - var loadBalancer = await _loadBalanceFactory.Get(reRoute); - _loadBalancerHouse.Add(reRoute.ReRouteKey, loadBalancer); - } - } -} \ No newline at end of file diff --git a/src/Ocelot/LoadBalancer/LoadBalancers/ILoadBalancerFactory.cs b/src/Ocelot/LoadBalancer/LoadBalancers/ILoadBalancerFactory.cs index 19fdf3eb..cc7bc6a6 100644 --- a/src/Ocelot/LoadBalancer/LoadBalancers/ILoadBalancerFactory.cs +++ b/src/Ocelot/LoadBalancer/LoadBalancers/ILoadBalancerFactory.cs @@ -5,6 +5,6 @@ namespace Ocelot.LoadBalancer.LoadBalancers { public interface ILoadBalancerFactory { - Task Get(ReRoute reRoute); + Task Get(ReRoute reRoute, ServiceProviderConfiguration config); } } \ No newline at end of file diff --git a/src/Ocelot/LoadBalancer/LoadBalancers/ILoadBalancerHouse.cs b/src/Ocelot/LoadBalancer/LoadBalancers/ILoadBalancerHouse.cs index 065ae2ac..558861cf 100644 --- a/src/Ocelot/LoadBalancer/LoadBalancers/ILoadBalancerHouse.cs +++ b/src/Ocelot/LoadBalancer/LoadBalancers/ILoadBalancerHouse.cs @@ -1,10 +1,11 @@ -using Ocelot.Responses; +using System.Threading.Tasks; +using Ocelot.Configuration; +using Ocelot.Responses; namespace Ocelot.LoadBalancer.LoadBalancers { public interface ILoadBalancerHouse { - Response Get(string key); - Response Add(string key, ILoadBalancer loadBalancer); + Task> Get(ReRoute reRoute, ServiceProviderConfiguration config); } } \ No newline at end of file diff --git a/src/Ocelot/LoadBalancer/LoadBalancers/LoadBalancerFactory.cs b/src/Ocelot/LoadBalancer/LoadBalancers/LoadBalancerFactory.cs index e7b323a4..596a1c22 100644 --- a/src/Ocelot/LoadBalancer/LoadBalancers/LoadBalancerFactory.cs +++ b/src/Ocelot/LoadBalancer/LoadBalancers/LoadBalancerFactory.cs @@ -12,16 +12,16 @@ namespace Ocelot.LoadBalancer.LoadBalancers _serviceProviderFactory = serviceProviderFactory; } - public async Task Get(ReRoute reRoute) + public async Task Get(ReRoute reRoute, ServiceProviderConfiguration config) { - var serviceProvider = _serviceProviderFactory.Get(reRoute.ServiceProviderConfiguraion); + var serviceProvider = _serviceProviderFactory.Get(config, reRoute); switch (reRoute.LoadBalancer) { case "RoundRobin": return new RoundRobinLoadBalancer(async () => await serviceProvider.Get()); case "LeastConnection": - return new LeastConnectionLoadBalancer(async () => await serviceProvider.Get(), reRoute.ServiceProviderConfiguraion.ServiceName); + return new LeastConnectionLoadBalancer(async () => await serviceProvider.Get(), reRoute.ServiceName); default: return new NoLoadBalancer(await serviceProvider.Get()); } diff --git a/src/Ocelot/LoadBalancer/LoadBalancers/LoadBalancerHouse.cs b/src/Ocelot/LoadBalancer/LoadBalancers/LoadBalancerHouse.cs index 68e42fe2..01d530af 100644 --- a/src/Ocelot/LoadBalancer/LoadBalancers/LoadBalancerHouse.cs +++ b/src/Ocelot/LoadBalancer/LoadBalancers/LoadBalancerHouse.cs @@ -1,33 +1,58 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Ocelot.Configuration; using Ocelot.Responses; namespace Ocelot.LoadBalancer.LoadBalancers { public class LoadBalancerHouse : ILoadBalancerHouse { + private readonly ILoadBalancerFactory _factory; private readonly Dictionary _loadBalancers; - public LoadBalancerHouse() + public LoadBalancerHouse(ILoadBalancerFactory factory) { + _factory = factory; _loadBalancers = new Dictionary(); } - public Response Get(string key) + public async Task> Get(ReRoute reRoute, ServiceProviderConfiguration config) { - ILoadBalancer loadBalancer; - - if(_loadBalancers.TryGetValue(key, out loadBalancer)) + try { - return new OkResponse(_loadBalancers[key]); + ILoadBalancer loadBalancer; + + if(_loadBalancers.TryGetValue(reRoute.ReRouteKey, out loadBalancer)) + { + loadBalancer = _loadBalancers[reRoute.ReRouteKey]; + + //todo - we have some duplicate namey type logic in the LoadBalancerFactory...maybe we can do something + //about this.. + if((reRoute.LoadBalancer == "RoundRobin" && loadBalancer.GetType() != typeof(RoundRobinLoadBalancer)) + || (reRoute.LoadBalancer == "LeastConnection" && loadBalancer.GetType() != typeof(LeastConnectionLoadBalancer))) + { + loadBalancer = await _factory.Get(reRoute, config); + AddLoadBalancer(reRoute.ReRouteKey, loadBalancer); + } + + return new OkResponse(loadBalancer); + } + + loadBalancer = await _factory.Get(reRoute, config); + AddLoadBalancer(reRoute.ReRouteKey, loadBalancer); + return new OkResponse(loadBalancer); } - - return new ErrorResponse(new List() + catch(Exception ex) { - new UnableToFindLoadBalancerError($"unabe to find load balancer for {key}") - }); + return new ErrorResponse(new List() + { + new UnableToFindLoadBalancerError($"unabe to find load balancer for {reRoute.ReRouteKey} exception is {ex}") + }); + } } - public Response Add(string key, ILoadBalancer loadBalancer) + private void AddLoadBalancer(string key, ILoadBalancer loadBalancer) { if (!_loadBalancers.ContainsKey(key)) { @@ -36,7 +61,6 @@ namespace Ocelot.LoadBalancer.LoadBalancers _loadBalancers.Remove(key); _loadBalancers.Add(key, loadBalancer); - return new OkResponse(); } } } diff --git a/src/Ocelot/LoadBalancer/Middleware/LoadBalancingMiddleware.cs b/src/Ocelot/LoadBalancer/Middleware/LoadBalancingMiddleware.cs index 909ef755..079f3584 100644 --- a/src/Ocelot/LoadBalancer/Middleware/LoadBalancingMiddleware.cs +++ b/src/Ocelot/LoadBalancer/Middleware/LoadBalancingMiddleware.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; +using Ocelot.Configuration.Provider; using Ocelot.Infrastructure.RequestData; using Ocelot.LoadBalancer.LoadBalancers; using Ocelot.Logging; @@ -11,6 +12,7 @@ namespace Ocelot.LoadBalancer.Middleware { public class LoadBalancingMiddleware : OcelotMiddleware { + private readonly IOcelotConfigurationProvider _configProvider; private readonly RequestDelegate _next; private readonly IOcelotLogger _logger; private readonly ILoadBalancerHouse _loadBalancerHouse; @@ -18,9 +20,11 @@ namespace Ocelot.LoadBalancer.Middleware public LoadBalancingMiddleware(RequestDelegate next, IOcelotLoggerFactory loggerFactory, IRequestScopedDataRepository requestScopedDataRepository, - ILoadBalancerHouse loadBalancerHouse) + ILoadBalancerHouse loadBalancerHouse, + IOcelotConfigurationProvider configProvider) : base(requestScopedDataRepository) { + _configProvider = configProvider; _next = next; _logger = loggerFactory.CreateLogger(); _loadBalancerHouse = loadBalancerHouse; @@ -28,7 +32,9 @@ namespace Ocelot.LoadBalancer.Middleware public async Task Invoke(HttpContext context) { - var loadBalancer = _loadBalancerHouse.Get(DownstreamRoute.ReRoute.ReRouteKey); + var configuration = await _configProvider.Get(); + + var loadBalancer = await _loadBalancerHouse.Get(DownstreamRoute.ReRoute, configuration.Data.ServiceProviderConfiguration); if(loadBalancer.IsError) { _logger.LogDebug("there was an error retriving the loadbalancer, setting pipeline error"); diff --git a/src/Ocelot/ServiceDiscovery/IServiceDiscoveryProviderFactory.cs b/src/Ocelot/ServiceDiscovery/IServiceDiscoveryProviderFactory.cs index 18c88c76..e92d50b0 100644 --- a/src/Ocelot/ServiceDiscovery/IServiceDiscoveryProviderFactory.cs +++ b/src/Ocelot/ServiceDiscovery/IServiceDiscoveryProviderFactory.cs @@ -4,6 +4,6 @@ namespace Ocelot.ServiceDiscovery { public interface IServiceDiscoveryProviderFactory { - IServiceDiscoveryProvider Get(ServiceProviderConfiguration serviceConfig); + IServiceDiscoveryProvider Get(ServiceProviderConfiguration serviceConfig, ReRoute reRoute); } } \ No newline at end of file diff --git a/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs b/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs index 49151c01..5dc4982a 100644 --- a/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs +++ b/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs @@ -6,17 +6,17 @@ namespace Ocelot.ServiceDiscovery { public class ServiceDiscoveryProviderFactory : IServiceDiscoveryProviderFactory { - public IServiceDiscoveryProvider Get(ServiceProviderConfiguration serviceConfig) + public IServiceDiscoveryProvider Get(ServiceProviderConfiguration serviceConfig, ReRoute reRoute) { - if (serviceConfig.UseServiceDiscovery) + if (reRoute.UseServiceDiscovery) { - return GetServiceDiscoveryProvider(serviceConfig.ServiceName, serviceConfig.ServiceDiscoveryProvider, serviceConfig.ServiceProviderHost, serviceConfig.ServiceProviderPort); + return GetServiceDiscoveryProvider(reRoute.ServiceName, serviceConfig.ServiceDiscoveryProvider, serviceConfig.ServiceProviderHost, serviceConfig.ServiceProviderPort); } var services = new List() { - new Service(serviceConfig.ServiceName, - new HostAndPort(serviceConfig.DownstreamHost, serviceConfig.DownstreamPort), + new Service(reRoute.ServiceName, + new HostAndPort(reRoute.DownstreamHost, reRoute.DownstreamPort), string.Empty, string.Empty, new string[0]) diff --git a/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs b/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs index 87476533..90db18e3 100644 --- a/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs +++ b/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs @@ -3,11 +3,13 @@ using System.Collections.Generic; using System.IO; using System.Net; using System.Text; +using System.Threading; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Newtonsoft.Json; using Ocelot.Configuration; +using Ocelot.Configuration.Builder; using Ocelot.Configuration.File; using Ocelot.ServiceDiscovery; using TestStack.BDDfy; @@ -60,7 +62,7 @@ namespace Ocelot.AcceptanceTests var consulConfig = new ConsulRegistryConfiguration("localhost", 9500, "Ocelot"); this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl)) - .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51779", 200, "Hello from Laura")) + .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51779", "", 200, "Hello from Laura")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfig(consulConfig)) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) @@ -69,6 +71,69 @@ namespace Ocelot.AcceptanceTests .BDDfy(); } + [Fact] + public void should_fix_issue_142() + { + var configuration = new FileConfiguration + { + ReRoutes = new List + { + }, + GlobalConfiguration = new FileGlobalConfiguration() + { + ServiceDiscoveryProvider = new FileServiceDiscoveryProvider() + { + Provider = "Consul", + Host = "localhost", + Port = 9500 + } + } + }; + + var fakeConsulServiceDiscoveryUrl = "http://localhost:9500"; + + var consulConfig = new ConsulRegistryConfiguration("localhost", 9500, "Ocelot"); + + var serviceProviderConfig = new ServiceProviderConfigurationBuilder() + .WithServiceDiscoveryProvider("Consul") + .WithServiceDiscoveryProviderHost("localhost") + .WithServiceDiscoveryProviderPort(8500) + .Build(); + + var reRoute = new ReRouteBuilder() + .WithDownstreamPathTemplate("/status") + .WithUpstreamTemplatePattern("^(?i)/cs/status/$") + .WithDownstreamScheme("http") + .WithDownstreamHost("localhost") + .WithDownstreamPort(51779) + .WithUpstreamPathTemplate("/cs/status") + .WithUpstreamHttpMethod(new List {"Get"}) + .WithLoadBalancer("LeastConnection") + .WithLoadBalancerKey("/cs/status|Get") + .WithServiceName("") + .WithUseServiceDiscovery(true) + .Build(); + + var reRoutes = new List { reRoute }; + + var config = new OcelotConfiguration(reRoutes, null, serviceProviderConfig); + + this.Given(x => GivenTheConsulConfigurationIs(config)) + .And(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl)) + .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51779", "/status", 200, "Hello from Laura")) + .And(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfig(consulConfig)) + .When(x => _steps.WhenIGetUrlOnTheApiGateway("/cs/status")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) + .BDDfy(); + } + + private void GivenTheConsulConfigurationIs(OcelotConfiguration config) + { + _config = config; + } + private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url) { _fakeConsulBuilder = new WebHostBuilder() @@ -137,7 +202,7 @@ namespace Ocelot.AcceptanceTests public string Session => "adf4238a-882b-9ddc-4a9d-5b6758e4159e"; } - private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody) + private void GivenThereIsAServiceRunningOn(string url, string basePath, int statusCode, string responseBody) { _builder = new WebHostBuilder() .UseUrls(url) @@ -147,6 +212,8 @@ namespace Ocelot.AcceptanceTests .UseUrls(url) .Configure(app => { + app.UsePathBase(basePath); + app.Run(async context => { context.Response.StatusCode = statusCode; diff --git a/test/Ocelot.AcceptanceTests/RequestId:0HL9635DF6NNV b/test/Ocelot.AcceptanceTests/RequestId:0HL9635DF6NNV new file mode 100644 index 00000000..e69de29b diff --git a/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs index 0440e7ee..d68bc054 100644 --- a/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs @@ -44,7 +44,6 @@ namespace Ocelot.UnitTests.Configuration private Mock _rateLimitOptions; private Mock _regionCreator; private Mock _httpHandlerOptionsCreator; - private Mock _lbCreator; public FileConfigurationCreatorTests() { @@ -65,11 +64,9 @@ namespace Ocelot.UnitTests.Configuration _rateLimitOptions = new Mock(); _regionCreator = new Mock(); _httpHandlerOptionsCreator = new Mock(); - _lbCreator = new Mock(); _ocelotConfigurationCreator = new FileOcelotConfigurationCreator( _fileConfig.Object, _validator.Object, _logger.Object, - _lbCreator.Object, _qosProviderFactory.Object, _qosProviderHouse.Object, _claimsToThingCreator.Object, _authOptionsCreator.Object, _upstreamTemplatePatternCreator.Object, _requestIdKeyCreator.Object, _serviceProviderConfigCreator.Object, _qosOptionsCreator.Object, _fileReRouteOptionsCreator.Object, @@ -189,32 +186,6 @@ namespace Ocelot.UnitTests.Configuration .BDDfy(); } - [Fact] - public void should_create_load_balancer() - { - var reRouteOptions = new ReRouteOptionsBuilder() - .Build(); - - this.Given(x => x.GivenTheConfigIs(new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - DownstreamHost = "127.0.0.1", - UpstreamPathTemplate = "/api/products/{productId}", - DownstreamPathTemplate = "/products/{productId}", - UpstreamHttpMethod = new List { "Get" }, - } - }, - })) - .And(x => x.GivenTheConfigIsValid()) - .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions)) - .When(x => x.WhenICreateTheConfig()) - .And(x => x.ThenTheLoadBalancerCreatorIsCalledCorrectly()) - .BDDfy(); - } - [Fact] public void should_use_downstream_host() { @@ -320,12 +291,8 @@ namespace Ocelot.UnitTests.Configuration .WithDownstreamPathTemplate("/products/{productId}") .WithUpstreamPathTemplate("/api/products/{productId}") .WithUpstreamHttpMethod(new List { "Get" }) - .WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder() - .WithUseServiceDiscovery(true) - .WithServiceDiscoveryProvider("consul") - .WithServiceDiscoveryProviderHost("127.0.0.1") - .WithServiceName("ProductService") - .Build()) + .WithUseServiceDiscovery(true) + .WithServiceName("ProductService") .Build() })) .BDDfy(); @@ -359,9 +326,7 @@ namespace Ocelot.UnitTests.Configuration .WithDownstreamPathTemplate("/products/{productId}") .WithUpstreamPathTemplate("/api/products/{productId}") .WithUpstreamHttpMethod(new List { "Get" }) - .WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder() - .WithUseServiceDiscovery(false) - .Build()) + .WithUseServiceDiscovery(false) .Build() })) .BDDfy(); @@ -604,20 +569,6 @@ namespace Ocelot.UnitTests.Configuration } } - private void ThenTheServiceConfigurationIs(ServiceProviderConfiguration expected) - { - for (int i = 0; i < _config.Data.ReRoutes.Count; i++) - { - var result = _config.Data.ReRoutes[i]; - result.ServiceProviderConfiguraion.DownstreamHost.ShouldBe(expected.DownstreamHost); - result.ServiceProviderConfiguraion.DownstreamPort.ShouldBe(expected.DownstreamPort); - result.ServiceProviderConfiguraion.ServiceDiscoveryProvider.ShouldBe(expected.ServiceDiscoveryProvider); - result.ServiceProviderConfiguraion.ServiceName.ShouldBe(expected.ServiceName); - result.ServiceProviderConfiguraion.ServiceProviderHost.ShouldBe(expected.ServiceProviderHost); - result.ServiceProviderConfiguraion.ServiceProviderPort.ShouldBe(expected.ServiceProviderPort); - } - } - private void ThenTheAuthenticationOptionsAre(List expectedReRoutes) { for (int i = 0; i < _config.Data.ReRoutes.Count; i++) @@ -628,11 +579,6 @@ namespace Ocelot.UnitTests.Configuration } } - private void ThenTheLoadBalancerCreatorIsCalledCorrectly() - { - _lbCreator.Verify(x => x.SetupLoadBalancer(It.IsAny()), Times.Once); - } - private void GivenTheQosProviderFactoryReturns() { _qosProviderFactory diff --git a/test/Ocelot.UnitTests/Configuration/FileConfigurationSetterTests.cs b/test/Ocelot.UnitTests/Configuration/FileConfigurationSetterTests.cs index bf4804f6..50ab0bc8 100644 --- a/test/Ocelot.UnitTests/Configuration/FileConfigurationSetterTests.cs +++ b/test/Ocelot.UnitTests/Configuration/FileConfigurationSetterTests.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using Moq; using Ocelot.Configuration; +using Ocelot.Configuration.Builder; using Ocelot.Configuration.Creator; using Ocelot.Configuration.File; using Ocelot.Configuration.Repository; @@ -36,7 +37,8 @@ namespace Ocelot.UnitTests.Configuration public void should_set_configuration() { var fileConfig = new FileConfiguration(); - var config = new OcelotConfiguration(new List(), string.Empty); + var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); + var config = new OcelotConfiguration(new List(), string.Empty, serviceProviderConfig); this.Given(x => GivenTheFollowingConfiguration(fileConfig)) .And(x => GivenTheRepoReturns(new OkResponse())) diff --git a/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs b/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs index b65aa095..fa853c7f 100644 --- a/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs +++ b/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs @@ -92,6 +92,8 @@ namespace Ocelot.UnitTests.Configuration }; public string AdministrationPath {get;} + + public ServiceProviderConfiguration ServiceProviderConfiguration => throw new NotImplementedException(); } } } diff --git a/test/Ocelot.UnitTests/Configuration/OcelotConfigurationProviderTests.cs b/test/Ocelot.UnitTests/Configuration/OcelotConfigurationProviderTests.cs index 430844fe..b1a6f314 100644 --- a/test/Ocelot.UnitTests/Configuration/OcelotConfigurationProviderTests.cs +++ b/test/Ocelot.UnitTests/Configuration/OcelotConfigurationProviderTests.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using Moq; using Ocelot.Configuration; +using Ocelot.Configuration.Builder; using Ocelot.Configuration.Creator; using Ocelot.Configuration.Provider; using Ocelot.Configuration.Repository; @@ -27,9 +28,11 @@ namespace Ocelot.UnitTests.Configuration [Fact] public void should_get_config() { - this.Given(x => x.GivenTheRepoReturns(new OkResponse(new OcelotConfiguration(new List(), string.Empty)))) + var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); + + this.Given(x => x.GivenTheRepoReturns(new OkResponse(new OcelotConfiguration(new List(), string.Empty, serviceProviderConfig)))) .When(x => x.WhenIGetTheConfig()) - .Then(x => x.TheFollowingIsReturned(new OkResponse(new OcelotConfiguration(new List(), string.Empty)))) + .Then(x => x.TheFollowingIsReturned(new OkResponse(new OcelotConfiguration(new List(), string.Empty, serviceProviderConfig)))) .BDDfy(); } diff --git a/test/Ocelot.UnitTests/Configuration/ServiceProviderCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/ServiceProviderCreatorTests.cs index 8d76e864..8c33b4e5 100644 --- a/test/Ocelot.UnitTests/Configuration/ServiceProviderCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/ServiceProviderCreatorTests.cs @@ -60,15 +60,12 @@ namespace Ocelot.UnitTests.Configuration private void WhenICreate() { - _result = _creator.Create(_reRoute, _globalConfig); + _result = _creator.Create(_globalConfig); } private void ThenTheConfigIs(ServiceProviderConfiguration expected) { - _result.DownstreamHost.ShouldBe(expected.DownstreamHost); - _result.DownstreamPort.ShouldBe(expected.DownstreamPort); _result.ServiceDiscoveryProvider.ShouldBe(expected.ServiceDiscoveryProvider); - _result.ServiceName.ShouldBe(expected.ServiceName); _result.ServiceProviderHost.ShouldBe(expected.ServiceProviderHost); _result.ServiceProviderPort.ShouldBe(expected.ServiceProviderPort); } diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs index 8dbe6ef4..2ae88eb3 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs @@ -36,6 +36,8 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder [Fact] public void should_return_route() { + var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher/")) .And(x =>x.GivenTheTemplateVariableAndNameFinderReturns( new OkResponse>( @@ -48,7 +50,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .WithUpstreamHttpMethod(new List { "Get" }) .WithUpstreamTemplatePattern("someUpstreamPath") .Build() - }, string.Empty + }, string.Empty, serviceProviderConfig )) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) .And(x => x.GivenTheUpstreamHttpMethodIs("Get")) @@ -69,6 +71,8 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder [Fact] public void should_append_slash_to_upstream_url_path() { + var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher")) .And(x =>x.GivenTheTemplateVariableAndNameFinderReturns( new OkResponse>( @@ -81,7 +85,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .WithUpstreamHttpMethod(new List { "Get" }) .WithUpstreamTemplatePattern("someUpstreamPath") .Build() - }, string.Empty + }, string.Empty, serviceProviderConfig )) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) .And(x => x.GivenTheUpstreamHttpMethodIs("Get")) @@ -101,6 +105,8 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder [Fact] public void should_return_route_if_upstream_path_and_upstream_template_are_the_same() { + var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) .And( x => @@ -114,7 +120,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .WithUpstreamHttpMethod(new List { "Get" }) .WithUpstreamTemplatePattern("someUpstreamPath") .Build() - }, string.Empty + }, string.Empty, serviceProviderConfig )) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) .And(x => x.GivenTheUpstreamHttpMethodIs("Get")) @@ -133,6 +139,8 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder [Fact] public void should_return_correct_route_for_http_verb() { + var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) .And( x => @@ -152,7 +160,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .WithUpstreamHttpMethod(new List { "Post" }) .WithUpstreamTemplatePattern("") .Build() - }, string.Empty + }, string.Empty, serviceProviderConfig )) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) .And(x => x.GivenTheUpstreamHttpMethodIs("Post")) @@ -169,7 +177,9 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder [Fact] public void should_not_return_route() - { + { + var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("dontMatchPath/")) .And(x => x.GivenTheConfigurationIs(new List { @@ -179,7 +189,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .WithUpstreamHttpMethod(new List { "Get" }) .WithUpstreamTemplatePattern("somePath") .Build(), - }, string.Empty + }, string.Empty, serviceProviderConfig )) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(false)))) .And(x => x.GivenTheUpstreamHttpMethodIs("Get")) @@ -193,6 +203,8 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder [Fact] public void should_return_correct_route_for_http_verb_setting_multiple_upstream_http_method() { + var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) .And( x => @@ -206,7 +218,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .WithUpstreamHttpMethod(new List { "Get", "Post" }) .WithUpstreamTemplatePattern("") .Build() - }, string.Empty + }, string.Empty, serviceProviderConfig )) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) .And(x => x.GivenTheUpstreamHttpMethodIs("Post")) @@ -224,6 +236,8 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder [Fact] public void should_return_correct_route_for_http_verb_setting_all_upstream_http_method() { + var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) .And( x => @@ -237,7 +251,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .WithUpstreamHttpMethod(new List()) .WithUpstreamTemplatePattern("") .Build() - }, string.Empty + }, string.Empty, serviceProviderConfig )) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) .And(x => x.GivenTheUpstreamHttpMethodIs("Post")) @@ -255,6 +269,8 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder [Fact] public void should_not_return_route_for_http_verb_not_setting_in_upstream_http_method() { + var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) .And( x => @@ -268,7 +284,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .WithUpstreamHttpMethod(new List { "Get", "Patch", "Delete" }) .WithUpstreamTemplatePattern("") .Build() - }, string.Empty + }, string.Empty, serviceProviderConfig )) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) .And(x => x.GivenTheUpstreamHttpMethodIs("Post")) @@ -322,12 +338,12 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .Returns(_match); } - private void GivenTheConfigurationIs(List reRoutesConfig, string adminPath) + private void GivenTheConfigurationIs(List reRoutesConfig, string adminPath, ServiceProviderConfiguration serviceProviderConfig) { _reRoutesConfig = reRoutesConfig; _mockConfig .Setup(x => x.Get()) - .ReturnsAsync(new OkResponse(new OcelotConfiguration(_reRoutesConfig, adminPath))); + .ReturnsAsync(new OkResponse(new OcelotConfiguration(_reRoutesConfig, adminPath, serviceProviderConfig))); } private void GivenThereIsAnUpstreamUrlPath(string upstreamUrlPath) diff --git a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerCreatorTests.cs b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerCreatorTests.cs deleted file mode 100644 index 9b9a2df1..00000000 --- a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerCreatorTests.cs +++ /dev/null @@ -1,57 +0,0 @@ -using Xunit; -using Shouldly; -using TestStack.BDDfy; -using Ocelot.LoadBalancer; -using Ocelot.LoadBalancer.LoadBalancers; -using Moq; -using Ocelot.Configuration; -using System.Collections.Generic; -using Ocelot.Values; -using Ocelot.Configuration.Builder; - -namespace Ocelot.UnitTests.LoadBalancer -{ - public class LoadBalancerCreatorTests - { - private LoadBalancerCreator _creator; - private ILoadBalancerHouse _house; - private Mock _factory; - private ReRoute _reRoute; - - public LoadBalancerCreatorTests() - { - _house = new LoadBalancerHouse(); - _factory = new Mock(); - _creator = new LoadBalancerCreator(_house, _factory.Object); - } - - [Fact] - public void should_create_load_balancer() - { - var reRoute = new ReRouteBuilder().WithLoadBalancerKey("Test").Build(); - this.Given(x => GivenTheFollowingReRoute(reRoute)) - .When(x => WhenICallTheCreator()) - .Then(x => x.ThenTheLoadBalancerIsCreated()) - .BDDfy(); - } - - private void GivenTheFollowingReRoute(ReRoute reRoute) - { - _reRoute = reRoute; - _factory - .Setup(x => x.Get(It.IsAny())) - .ReturnsAsync(new NoLoadBalancer(new List())); - } - - private void WhenICallTheCreator() - { - _creator.SetupLoadBalancer(_reRoute).Wait(); - } - - private void ThenTheLoadBalancerIsCreated() - { - var lb = _house.Get(_reRoute.ReRouteKey); - lb.ShouldNotBeNull(); - } - } -} \ No newline at end of file diff --git a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerFactoryTests.cs b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerFactoryTests.cs index ccf97772..9fde2f78 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerFactoryTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerFactoryTests.cs @@ -17,7 +17,8 @@ namespace Ocelot.UnitTests.LoadBalancer private ILoadBalancer _result; private Mock _serviceProviderFactory; private Mock _serviceProvider; - + private ServiceProviderConfiguration _serviceProviderConfig; + public LoadBalancerFactoryTests() { _serviceProviderFactory = new Mock(); @@ -29,11 +30,11 @@ namespace Ocelot.UnitTests.LoadBalancer public void should_return_no_load_balancer() { var reRoute = new ReRouteBuilder() - .WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder().Build()) .WithUpstreamHttpMethod(new List { "Get" }) .Build(); this.Given(x => x.GivenAReRoute(reRoute)) + .And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build())) .And(x => x.GivenTheServiceProviderFactoryReturns()) .When(x => x.WhenIGetTheLoadBalancer()) .Then(x => x.ThenTheLoadBalancerIsReturned()) @@ -46,10 +47,10 @@ namespace Ocelot.UnitTests.LoadBalancer var reRoute = new ReRouteBuilder() .WithLoadBalancer("RoundRobin") .WithUpstreamHttpMethod(new List { "Get" }) - .WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder().Build()) .Build(); this.Given(x => x.GivenAReRoute(reRoute)) + .And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build())) .And(x => x.GivenTheServiceProviderFactoryReturns()) .When(x => x.WhenIGetTheLoadBalancer()) .Then(x => x.ThenTheLoadBalancerIsReturned()) @@ -62,10 +63,10 @@ namespace Ocelot.UnitTests.LoadBalancer var reRoute = new ReRouteBuilder() .WithLoadBalancer("LeastConnection") .WithUpstreamHttpMethod(new List { "Get" }) - .WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder().Build()) .Build(); this.Given(x => x.GivenAReRoute(reRoute)) + .And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build())) .And(x => x.GivenTheServiceProviderFactoryReturns()) .When(x => x.WhenIGetTheLoadBalancer()) .Then(x => x.ThenTheLoadBalancerIsReturned()) @@ -78,27 +79,32 @@ namespace Ocelot.UnitTests.LoadBalancer var reRoute = new ReRouteBuilder() .WithLoadBalancer("RoundRobin") .WithUpstreamHttpMethod(new List { "Get" }) - .WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder().Build()) .Build(); this.Given(x => x.GivenAReRoute(reRoute)) + .And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build())) .And(x => x.GivenTheServiceProviderFactoryReturns()) .When(x => x.WhenIGetTheLoadBalancer()) .Then(x => x.ThenTheServiceProviderIsCalledCorrectly()) .BDDfy(); } + private void GivenAServiceProviderConfig(ServiceProviderConfiguration serviceProviderConfig) + { + _serviceProviderConfig = serviceProviderConfig; + } + private void GivenTheServiceProviderFactoryReturns() { _serviceProviderFactory - .Setup(x => x.Get(It.IsAny())) + .Setup(x => x.Get(It.IsAny(), It.IsAny())) .Returns(_serviceProvider.Object); } private void ThenTheServiceProviderIsCalledCorrectly() { _serviceProviderFactory - .Verify(x => x.Get(It.IsAny()), Times.Once); + .Verify(x => x.Get(It.IsAny(), It.IsAny()), Times.Once); } private void GivenAReRoute(ReRoute reRoute) @@ -108,7 +114,7 @@ namespace Ocelot.UnitTests.LoadBalancer private void WhenIGetTheLoadBalancer() { - _result = _factory.Get(_reRoute).Result; + _result = _factory.Get(_reRoute, _serviceProviderConfig).Result; } private void ThenTheLoadBalancerIsReturned() diff --git a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerHouseTests.cs b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerHouseTests.cs index ac24b490..ccfb32ff 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerHouseTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerHouseTests.cs @@ -1,5 +1,8 @@ using System; using System.Threading.Tasks; +using Moq; +using Ocelot.Configuration; +using Ocelot.Configuration.Builder; using Ocelot.LoadBalancer.LoadBalancers; using Ocelot.Responses; using Ocelot.Values; @@ -11,35 +14,38 @@ namespace Ocelot.UnitTests.LoadBalancer { public class LoadBalancerHouseTests { + private ReRoute _reRoute; private ILoadBalancer _loadBalancer; private readonly LoadBalancerHouse _loadBalancerHouse; private Response _addResult; private Response _getResult; private string _key; + private Mock _factory; + private ServiceProviderConfiguration _serviceProviderConfig; public LoadBalancerHouseTests() { - _loadBalancerHouse = new LoadBalancerHouse(); + _factory = new Mock(); + _loadBalancerHouse = new LoadBalancerHouse(_factory.Object); } [Fact] - public void should_store_load_balancer() + public void should_store_load_balancer_on_first_request() { - var key = "test"; + var reRoute = new ReRouteBuilder().WithLoadBalancerKey("test").Build(); - this.Given(x => x.GivenThereIsALoadBalancer(key, new FakeLoadBalancer())) - .When(x => x.WhenIAddTheLoadBalancer()) + this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer())) .Then(x => x.ThenItIsAdded()) .BDDfy(); } [Fact] - public void should_get_load_balancer() + public void should_not_store_load_balancer_on_second_request() { - var key = "test"; + var reRoute = new ReRouteBuilder().WithLoadBalancerKey("test").Build(); - this.Given(x => x.GivenThereIsALoadBalancer(key, new FakeLoadBalancer())) - .When(x => x.WhenWeGetTheLoadBalancer(key)) + this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer())) + .When(x => x.WhenWeGetTheLoadBalancer(reRoute)) .Then(x => x.ThenItIsReturned()) .BDDfy(); } @@ -47,26 +53,50 @@ namespace Ocelot.UnitTests.LoadBalancer [Fact] public void should_store_load_balancers_by_key() { - var key = "test"; - var keyTwo = "testTwo"; + var reRoute = new ReRouteBuilder().WithLoadBalancerKey("test").Build(); + var reRouteTwo = new ReRouteBuilder().WithLoadBalancerKey("testtwo").Build(); - this.Given(x => x.GivenThereIsALoadBalancer(key, new FakeLoadBalancer())) - .And(x => x.GivenThereIsALoadBalancer(keyTwo, new FakeRoundRobinLoadBalancer())) - .When(x => x.WhenWeGetTheLoadBalancer(key)) + this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer())) + .And(x => x.GivenThereIsALoadBalancer(reRouteTwo, new FakeRoundRobinLoadBalancer())) + .When(x => x.WhenWeGetTheLoadBalancer(reRoute)) .Then(x => x.ThenTheLoadBalancerIs()) - .When(x => x.WhenWeGetTheLoadBalancer(keyTwo)) + .When(x => x.WhenWeGetTheLoadBalancer(reRouteTwo)) .Then(x => x.ThenTheLoadBalancerIs()) .BDDfy(); } [Fact] - public void should_return_error_if_no_load_balancer_with_key() + public void should_return_error_if_exception() { - this.When(x => x.WhenWeGetTheLoadBalancer("test")) + var reRoute = new ReRouteBuilder().Build(); + + this.When(x => x.WhenWeGetTheLoadBalancer(reRoute)) .Then(x => x.ThenAnErrorIsReturned()) .BDDfy(); } + [Fact] + public void should_get_new_load_balancer_if_reroute_load_balancer_has_changed() + { + var reRoute = new ReRouteBuilder().WithLoadBalancerKey("test").Build(); + + var reRouteTwo = new ReRouteBuilder().WithLoadBalancer("LeastConnection").WithLoadBalancerKey("test").Build(); + + this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer())) + .When(x => x.WhenWeGetTheLoadBalancer(reRoute)) + .Then(x => x.ThenTheLoadBalancerIs()) + .When(x => x.WhenIGetTheReRouteWithTheSameKeyButDifferentLoadBalancer(reRouteTwo)) + .Then(x => x.ThenTheLoadBalancerIs()) + .BDDfy(); + } + + private void WhenIGetTheReRouteWithTheSameKeyButDifferentLoadBalancer(ReRoute reRoute) + { + _reRoute = reRoute; + _factory.Setup(x => x.Get(_reRoute, _serviceProviderConfig)).ReturnsAsync(new LeastConnectionLoadBalancer(null, null)); + _getResult = _loadBalancerHouse.Get(_reRoute, _serviceProviderConfig).Result; + } + private void ThenAnErrorIsReturned() { _getResult.IsError.ShouldBeTrue(); @@ -80,31 +110,30 @@ namespace Ocelot.UnitTests.LoadBalancer private void ThenItIsAdded() { - _addResult.IsError.ShouldBe(false); - _addResult.ShouldBeOfType(); - } - - private void WhenIAddTheLoadBalancer() - { - _addResult = _loadBalancerHouse.Add(_key, _loadBalancer); + _getResult.IsError.ShouldBe(false); + _getResult.ShouldBeOfType>(); + _getResult.Data.ShouldBe(_loadBalancer); + _factory.Verify(x => x.Get(_reRoute, _serviceProviderConfig), Times.Once); } - private void GivenThereIsALoadBalancer(string key, ILoadBalancer loadBalancer) + private void GivenThereIsALoadBalancer(ReRoute reRoute, ILoadBalancer loadBalancer) { - _key = key; + _reRoute = reRoute; _loadBalancer = loadBalancer; - WhenIAddTheLoadBalancer(); + _factory.Setup(x => x.Get(_reRoute, _serviceProviderConfig)).ReturnsAsync(loadBalancer); + _getResult = _loadBalancerHouse.Get(reRoute, _serviceProviderConfig).Result; } - private void WhenWeGetTheLoadBalancer(string key) + private void WhenWeGetTheLoadBalancer(ReRoute reRoute) { - _getResult = _loadBalancerHouse.Get(key); + _getResult = _loadBalancerHouse.Get(reRoute, _serviceProviderConfig).Result; } private void ThenItIsReturned() { _getResult.Data.ShouldBe(_loadBalancer); + _factory.Verify(x => x.Get(_reRoute, _serviceProviderConfig), Times.Once); } class FakeLoadBalancer : ILoadBalancer diff --git a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs index e483f31c..6ef4029b 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs @@ -5,6 +5,7 @@ namespace Ocelot.UnitTests.LoadBalancer using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Moq; + using Ocelot.Configuration; using Ocelot.Configuration.Builder; using Ocelot.DownstreamRouteFinder; using Ocelot.Errors; @@ -137,8 +138,8 @@ namespace Ocelot.UnitTests.LoadBalancer private void GivenTheLoadBalancerHouseReturns() { _loadBalancerHouse - .Setup(x => x.Get(It.IsAny())) - .Returns(new OkResponse(_loadBalancer.Object)); + .Setup(x => x.Get(It.IsAny(), It.IsAny())) + .ReturnsAsync(new OkResponse(_loadBalancer.Object)); } private void GivenTheLoadBalancerHouseReturnsAnError() @@ -149,8 +150,8 @@ namespace Ocelot.UnitTests.LoadBalancer }); _loadBalancerHouse - .Setup(x => x.Get(It.IsAny())) - .Returns(_getLoadBalancerHouseError); + .Setup(x => x.Get(It.IsAny(), It.IsAny())) + .ReturnsAsync(_getLoadBalancerHouseError); } private void ThenAnErrorStatingLoadBalancerCouldNotBeFoundIsSetOnPipeline() diff --git a/test/Ocelot.UnitTests/ServiceDiscovery/ServiceProviderFactoryTests.cs b/test/Ocelot.UnitTests/ServiceDiscovery/ServiceProviderFactoryTests.cs index afa86c1b..71ed1430 100644 --- a/test/Ocelot.UnitTests/ServiceDiscovery/ServiceProviderFactoryTests.cs +++ b/test/Ocelot.UnitTests/ServiceDiscovery/ServiceProviderFactoryTests.cs @@ -12,6 +12,7 @@ namespace Ocelot.UnitTests.ServiceDiscovery private ServiceProviderConfiguration _serviceConfig; private IServiceDiscoveryProvider _result; private readonly ServiceDiscoveryProviderFactory _factory; + private ReRoute _reRoute; public ServiceProviderFactoryTests() { @@ -22,12 +23,11 @@ namespace Ocelot.UnitTests.ServiceDiscovery public void should_return_no_service_provider() { var serviceConfig = new ServiceProviderConfigurationBuilder() - .WithDownstreamHost("127.0.0.1") - .WithDownstreamPort(80) - .WithUseServiceDiscovery(false) .Build(); - this.Given(x => x.GivenTheReRoute(serviceConfig)) + var reRoute = new ReRouteBuilder().Build(); + + this.Given(x => x.GivenTheReRoute(serviceConfig, reRoute)) .When(x => x.WhenIGetTheServiceProvider()) .Then(x => x.ThenTheServiceProviderIs()) .BDDfy(); @@ -36,26 +36,30 @@ namespace Ocelot.UnitTests.ServiceDiscovery [Fact] public void should_return_consul_service_provider() { - var serviceConfig = new ServiceProviderConfigurationBuilder() + var reRoute = new ReRouteBuilder() .WithServiceName("product") .WithUseServiceDiscovery(true) + .Build(); + + var serviceConfig = new ServiceProviderConfigurationBuilder() .WithServiceDiscoveryProvider("Consul") .Build(); - this.Given(x => x.GivenTheReRoute(serviceConfig)) + this.Given(x => x.GivenTheReRoute(serviceConfig, reRoute)) .When(x => x.WhenIGetTheServiceProvider()) .Then(x => x.ThenTheServiceProviderIs()) .BDDfy(); } - private void GivenTheReRoute(ServiceProviderConfiguration serviceConfig) + private void GivenTheReRoute(ServiceProviderConfiguration serviceConfig, ReRoute reRoute) { _serviceConfig = serviceConfig; + _reRoute = reRoute; } private void WhenIGetTheServiceProvider() { - _result = _factory.Get(_serviceConfig); + _result = _factory.Get(_serviceConfig, _reRoute); } private void ThenTheServiceProviderIs() From bc1ba53f214252630036198a2102eca9940fa705 Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Thu, 9 Nov 2017 08:19:36 +0000 Subject: [PATCH 04/11] unit tests passing again --- .../LoadBalancerMiddlewareTests.cs | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs index 6ef4029b..987b75ea 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs @@ -7,6 +7,7 @@ namespace Ocelot.UnitTests.LoadBalancer using Moq; using Ocelot.Configuration; using Ocelot.Configuration.Builder; + using Ocelot.Configuration.Provider; using Ocelot.DownstreamRouteFinder; using Ocelot.Errors; using Ocelot.LoadBalancer.LoadBalancers; @@ -22,18 +23,20 @@ namespace Ocelot.UnitTests.LoadBalancer { private readonly Mock _loadBalancerHouse; private readonly Mock _loadBalancer; + private readonly Mock _configProvider; private HostAndPort _hostAndPort; private OkResponse _downstreamRoute; private ErrorResponse _getLoadBalancerHouseError; private ErrorResponse _getHostAndPortError; private HttpRequestMessage _downstreamRequest; + private ServiceProviderConfiguration _config; public LoadBalancerMiddlewareTests() { + _configProvider = new Mock(); _loadBalancerHouse = new Mock(); _loadBalancer = new Mock(); _loadBalancerHouse = new Mock(); - _downstreamRequest = new HttpRequestMessage(HttpMethod.Get, ""); ScopedRepository @@ -51,7 +54,11 @@ namespace Ocelot.UnitTests.LoadBalancer .WithUpstreamHttpMethod(new List { "Get" }) .Build()); + var serviceProviderConfig = new ServiceProviderConfigurationBuilder() + .Build(); + this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123")) + .And(x => GivenTheConfigurationIs(serviceProviderConfig)) .And(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) .And(x => x.GivenTheLoadBalancerHouseReturns()) .And(x => x.GivenTheLoadBalancerReturns()) @@ -68,7 +75,11 @@ namespace Ocelot.UnitTests.LoadBalancer .WithUpstreamHttpMethod(new List { "Get" }) .Build()); + var serviceProviderConfig = new ServiceProviderConfigurationBuilder() + .Build(); + this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123")) + .And(x => GivenTheConfigurationIs(serviceProviderConfig)) .And(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) .And(x => x.GivenTheLoadBalancerHouseReturnsAnError()) .When(x => x.WhenICallTheMiddleware()) @@ -83,8 +94,12 @@ namespace Ocelot.UnitTests.LoadBalancer new ReRouteBuilder() .WithUpstreamHttpMethod(new List { "Get" }) .Build()); + + var serviceProviderConfig = new ServiceProviderConfigurationBuilder() + .Build(); this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123")) + .And(x => GivenTheConfigurationIs(serviceProviderConfig)) .And(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) .And(x => x.GivenTheLoadBalancerHouseReturns()) .And(x => x.GivenTheLoadBalancerReturnsAnError()) @@ -93,11 +108,19 @@ namespace Ocelot.UnitTests.LoadBalancer .BDDfy(); } + private void GivenTheConfigurationIs(ServiceProviderConfiguration config) + { + _config = config; + _configProvider + .Setup(x => x.Get()).ReturnsAsync(new OkResponse(new OcelotConfiguration(null, null, _config))); + } + protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services) { services.AddSingleton(); services.AddLogging(); services.AddSingleton(_loadBalancerHouse.Object); + services.AddSingleton(_configProvider.Object); services.AddSingleton(ScopedRepository.Object); } From 0bc39fca5376ff08659c9201ea8ce58c087daf33 Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Thu, 9 Nov 2017 08:27:38 +0000 Subject: [PATCH 05/11] another test to make sure service provider config is craeted --- .../FileConfigurationCreatorTests.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs index d68bc054..b9264cee 100644 --- a/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs @@ -73,6 +73,30 @@ namespace Ocelot.UnitTests.Configuration _rateLimitOptions.Object, _regionCreator.Object, _httpHandlerOptionsCreator.Object); } + [Fact] + public void should_call_service_provider_config_creator() + { + var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build(); + + this.Given(x => x.GivenTheConfigIs(new FileConfiguration + { + GlobalConfiguration = new FileGlobalConfiguration + { + ServiceDiscoveryProvider = new FileServiceDiscoveryProvider + { + Host = "localhost", + Port = 8500, + Provider = "consul" + } + } + })) + .And(x => x.GivenTheFollowingIsReturned(serviceProviderConfig)) + .And(x => x.GivenTheConfigIsValid()) + .When(x => x.WhenICreateTheConfig()) + .Then(x => x.ThenTheServiceProviderCreatorIsCalledCorrectly()) + .BDDfy(); + } + [Fact] public void should_call_region_creator() { @@ -652,5 +676,17 @@ namespace Ocelot.UnitTests.Configuration _config.Data.ReRoutes[0].QosOptionsOptions.ExceptionsAllowedBeforeBreaking.ShouldBe(qosOptions.ExceptionsAllowedBeforeBreaking); _config.Data.ReRoutes[0].QosOptionsOptions.TimeoutValue.ShouldBe(qosOptions.TimeoutValue); } + + private void ThenTheServiceProviderCreatorIsCalledCorrectly() + { + _serviceProviderConfigCreator + .Verify(x => x.Create(_fileConfiguration.GlobalConfiguration), Times.Once); + } + + private void GivenTheFollowingIsReturned(ServiceProviderConfiguration serviceProviderConfiguration) + { + _serviceProviderConfigCreator + .Setup(x => x.Create(It.IsAny())).Returns(serviceProviderConfiguration); + } } } From b64b06e06954d9ad5cc589ffb8fec5b9e7b5fb0e Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Thu, 9 Nov 2017 09:02:41 +0000 Subject: [PATCH 06/11] getting acceptance tests working again --- .../Creator/FileOcelotConfigurationCreator.cs | 2 + src/Ocelot/Configuration/File/FileReRoute.cs | 1 + .../LoadBalancers/LoadBalancerHouse.cs | 22 +++++---- .../ServiceDiscoveryTests.cs | 5 +- test/Ocelot.AcceptanceTests/Startup.cs | 47 +++++++++++++++++++ test/Ocelot.AcceptanceTests/Steps.cs | 38 --------------- 6 files changed, 67 insertions(+), 48 deletions(-) create mode 100644 test/Ocelot.AcceptanceTests/Startup.cs diff --git a/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs index 5a5bb607..cd6e54ff 100644 --- a/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs +++ b/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs @@ -168,6 +168,8 @@ namespace Ocelot.Configuration.Creator .WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting) .WithRateLimitOptions(rateLimitOption) .WithHttpHandlerOptions(httpHandlerOptions) + .WithServiceName(fileReRoute.ServiceName) + .WithUseServiceDiscovery(fileReRoute.UseServiceDiscovery) .Build(); SetupQosProvider(reRoute); diff --git a/src/Ocelot/Configuration/File/FileReRoute.cs b/src/Ocelot/Configuration/File/FileReRoute.cs index 9abb5a7d..d33ba8e4 100644 --- a/src/Ocelot/Configuration/File/FileReRoute.cs +++ b/src/Ocelot/Configuration/File/FileReRoute.cs @@ -37,5 +37,6 @@ namespace Ocelot.Configuration.File public FileRateLimitRule RateLimitOptions { get; set; } public FileAuthenticationOptions AuthenticationOptions { get; set; } public FileHttpHandlerOptions HttpHandlerOptions { get; set; } + public bool UseServiceDiscovery {get;set;} } } \ No newline at end of file diff --git a/src/Ocelot/LoadBalancer/LoadBalancers/LoadBalancerHouse.cs b/src/Ocelot/LoadBalancer/LoadBalancers/LoadBalancerHouse.cs index 01d530af..d4a54bd7 100644 --- a/src/Ocelot/LoadBalancer/LoadBalancers/LoadBalancerHouse.cs +++ b/src/Ocelot/LoadBalancer/LoadBalancers/LoadBalancerHouse.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading.Tasks; using Ocelot.Configuration; @@ -9,12 +10,12 @@ namespace Ocelot.LoadBalancer.LoadBalancers public class LoadBalancerHouse : ILoadBalancerHouse { private readonly ILoadBalancerFactory _factory; - private readonly Dictionary _loadBalancers; + private readonly ConcurrentDictionary _loadBalancers; public LoadBalancerHouse(ILoadBalancerFactory factory) { _factory = factory; - _loadBalancers = new Dictionary(); + _loadBalancers = new ConcurrentDictionary(); } public async Task> Get(ReRoute reRoute, ServiceProviderConfiguration config) @@ -54,13 +55,18 @@ namespace Ocelot.LoadBalancer.LoadBalancers private void AddLoadBalancer(string key, ILoadBalancer loadBalancer) { - if (!_loadBalancers.ContainsKey(key)) - { - _loadBalancers.Add(key, loadBalancer); - } + _loadBalancers.AddOrUpdate(key, loadBalancer, (x, y) => { + return loadBalancer; + }); + + // if (!_loadBalancers.ContainsKey(key)) + // { + // _loadBalancers.TryAdd(key, loadBalancer); + // } - _loadBalancers.Remove(key); - _loadBalancers.Add(key, loadBalancer); + // ILoadBalancer old; + // _loadBalancers.Remove(key, out old); + // _loadBalancers.TryAdd(key, loadBalancer); } } } diff --git a/test/Ocelot.AcceptanceTests/ServiceDiscoveryTests.cs b/test/Ocelot.AcceptanceTests/ServiceDiscoveryTests.cs index 943e8a23..5978f842 100644 --- a/test/Ocelot.AcceptanceTests/ServiceDiscoveryTests.cs +++ b/test/Ocelot.AcceptanceTests/ServiceDiscoveryTests.cs @@ -72,6 +72,7 @@ namespace Ocelot.AcceptanceTests UpstreamHttpMethod = new List { "Get" }, ServiceName = serviceName, LoadBalancer = "LeastConnection", + UseServiceDiscovery = true, } }, GlobalConfiguration = new FileGlobalConfiguration() @@ -99,8 +100,8 @@ namespace Ocelot.AcceptanceTests private void ThenBothServicesCalledRealisticAmountOfTimes() { - _counterOne.ShouldBe(25); - _counterTwo.ShouldBe(25); + _counterOne.ShouldBe(26); + _counterTwo.ShouldBe(24); } private void ThenTheTwoServicesShouldHaveBeenCalledTimes(int expected) diff --git a/test/Ocelot.AcceptanceTests/Startup.cs b/test/Ocelot.AcceptanceTests/Startup.cs new file mode 100644 index 00000000..3a53bfaa --- /dev/null +++ b/test/Ocelot.AcceptanceTests/Startup.cs @@ -0,0 +1,47 @@ +using System; +using CacheManager.Core; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Ocelot.DependencyInjection; +using Ocelot.Middleware; +using ConfigurationBuilder = Microsoft.Extensions.Configuration.ConfigurationBuilder; + +namespace Ocelot.AcceptanceTests +{ + public class Startup + { + public Startup(IHostingEnvironment env) + { + var builder = new ConfigurationBuilder() + .SetBasePath(env.ContentRootPath) + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) + .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) + .AddJsonFile("configuration.json") + .AddEnvironmentVariables(); + + Configuration = builder.Build(); + } + + public IConfigurationRoot Configuration { get; } + + public void ConfigureServices(IServiceCollection services) + { + Action settings = (x) => + { + x.WithDictionaryHandle(); + }; + + services.AddOcelot(Configuration, settings); + } + + public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) + { + loggerFactory.AddConsole(Configuration.GetSection("Logging")); + + app.UseOcelot().Wait(); + } + } +} diff --git a/test/Ocelot.AcceptanceTests/Steps.cs b/test/Ocelot.AcceptanceTests/Steps.cs index fb853fbb..80a3e68e 100644 --- a/test/Ocelot.AcceptanceTests/Steps.cs +++ b/test/Ocelot.AcceptanceTests/Steps.cs @@ -381,42 +381,4 @@ namespace Ocelot.AcceptanceTests _response.Headers.GetValues(RequestIdKey).First().ShouldBe(expected); } } - - public class Startup - { - public Startup(IHostingEnvironment env) - { - var builder = new ConfigurationBuilder() - .SetBasePath(env.ContentRootPath) - .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) - .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) - .AddJsonFile("configuration.json") - .AddEnvironmentVariables(); - - Configuration = builder.Build(); - } - - public IConfigurationRoot Configuration { get; } - - public void ConfigureServices(IServiceCollection services) - { - Action settings = (x) => - { - x.WithMicrosoftLogging(log => - { - log.AddConsole(LogLevel.Debug); - }) - .WithDictionaryHandle(); - }; - - services.AddOcelot(Configuration, settings); - } - - public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) - { - loggerFactory.AddConsole(Configuration.GetSection("Logging")); - - app.UseOcelot().Wait(); - } - } } From 93b4f2269a7722c31258a06202ee72fcfba61bf4 Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Thu, 9 Nov 2017 09:07:54 +0000 Subject: [PATCH 07/11] changed assertions for test to be more realistic --- test/Ocelot.AcceptanceTests/ServiceDiscoveryTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Ocelot.AcceptanceTests/ServiceDiscoveryTests.cs b/test/Ocelot.AcceptanceTests/ServiceDiscoveryTests.cs index 5978f842..a856656e 100644 --- a/test/Ocelot.AcceptanceTests/ServiceDiscoveryTests.cs +++ b/test/Ocelot.AcceptanceTests/ServiceDiscoveryTests.cs @@ -100,8 +100,8 @@ namespace Ocelot.AcceptanceTests private void ThenBothServicesCalledRealisticAmountOfTimes() { - _counterOne.ShouldBe(26); - _counterTwo.ShouldBe(24); + _counterOne.ShouldBeInRange(24,26); + _counterOne.ShouldBeInRange(24,26); } private void ThenTheTwoServicesShouldHaveBeenCalledTimes(int expected) From b08837ea9dc9c41de083bdac83878e38ce3fc279 Mon Sep 17 00:00:00 2001 From: Tom Pallister Date: Thu, 9 Nov 2017 09:56:20 +0000 Subject: [PATCH 08/11] removed crap --- test/Ocelot.AcceptanceTests/RequestId:0HL9635DF6NNV | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 test/Ocelot.AcceptanceTests/RequestId:0HL9635DF6NNV diff --git a/test/Ocelot.AcceptanceTests/RequestId:0HL9635DF6NNV b/test/Ocelot.AcceptanceTests/RequestId:0HL9635DF6NNV deleted file mode 100644 index e69de29b..00000000 From 1d61e403ed7b8ba51449c2c667536ee35f0f913a Mon Sep 17 00:00:00 2001 From: Tom Pallister Date: Thu, 9 Nov 2017 17:35:49 +0000 Subject: [PATCH 09/11] changes to create load balancers and qos providers on first request to reroute and then check if they have changed on subsequent requests but not create again if they havent..quite a few breaking changes here. --- .../Configuration/Builder/ReRouteBuilder.cs | 2 +- .../ServiceProviderConfigurationBuilder.cs | 9 +- .../Creator/FileOcelotConfigurationCreator.cs | 19 +- .../ServiceProviderConfigurationCreator.cs | 1 - .../File/FileServiceDiscoveryProvider.cs | 2 - .../ConsulOcelotConfigurationRepository.cs | 16 +- .../ServiceProviderConfiguraion.cs | 4 +- .../ServiceCollectionExtensions.cs | 25 +- ...tionLoadBalancer.cs => LeastConnection.cs} | 4 +- .../LoadBalancers/LoadBalancerFactory.cs | 4 +- .../LoadBalancers/LoadBalancerHouse.cs | 22 +- ...oundRobinLoadBalancer.cs => RoundRobin.cs} | 4 +- .../HttpRequestBuilderMiddleware.cs | 2 +- src/Ocelot/Requester/QoS/CircuitBreaker.cs | 17 ++ src/Ocelot/Requester/QoS/IQoSProvider.cs | 7 + .../Requester/QoS/IQoSProviderFactory.cs | 137 +--------- src/Ocelot/Requester/QoS/IQosProviderHouse.cs | 10 + src/Ocelot/Requester/QoS/NoQoSProvider.cs | 7 + src/Ocelot/Requester/QoS/PollyQoSProvider.cs | 51 ++++ .../Requester/QoS/QoSProviderFactory.cs | 25 ++ src/Ocelot/Requester/QoS/QosProviderHouse.cs | 53 ++++ .../ConsulRegistryConfiguration.cs | 6 +- .../ConsulServiceDiscoveryProvider.cs | 8 +- .../ServiceDiscoveryProviderFactory.cs | 6 +- .../ConfigurationInConsulTests.cs | 31 +-- .../ServiceDiscoveryTests.cs | 6 +- test/Ocelot.AcceptanceTests/Startup.cs | 35 +++ test/Ocelot.AcceptanceTests/Steps.cs | 6 +- .../AdministrationTests.cs | 2 - .../FileConfigurationCreatorTests.cs | 39 +-- .../FileConfigurationRepositoryTests.cs | 4 - .../ServiceProviderCreatorTests.cs | 3 - .../LoadBalancer/LeastConnectionTests.cs | 12 +- .../LoadBalancer/LoadBalancerFactoryTests.cs | 4 +- .../LoadBalancer/LoadBalancerHouseTests.cs | 16 +- .../LoadBalancer/RoundRobinTests.cs | 4 +- .../HttpRequestBuilderMiddlewareTests.cs | 240 +++++++++--------- .../Requester/QosProviderHouseTests.cs | 89 ++++--- .../ServiceProviderFactoryTests.cs | 1 - 39 files changed, 474 insertions(+), 459 deletions(-) rename src/Ocelot/LoadBalancer/LoadBalancers/{LeastConnectionLoadBalancer.cs => LeastConnection.cs} (96%) rename src/Ocelot/LoadBalancer/LoadBalancers/{RoundRobinLoadBalancer.cs => RoundRobin.cs} (85%) create mode 100644 src/Ocelot/Requester/QoS/CircuitBreaker.cs create mode 100644 src/Ocelot/Requester/QoS/IQoSProvider.cs create mode 100644 src/Ocelot/Requester/QoS/IQosProviderHouse.cs create mode 100644 src/Ocelot/Requester/QoS/NoQoSProvider.cs create mode 100644 src/Ocelot/Requester/QoS/PollyQoSProvider.cs create mode 100644 src/Ocelot/Requester/QoS/QoSProviderFactory.cs create mode 100644 src/Ocelot/Requester/QoS/QosProviderHouse.cs diff --git a/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs b/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs index b823e6ac..1a8877e7 100644 --- a/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs +++ b/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs @@ -149,7 +149,7 @@ namespace Ocelot.Configuration.Builder return this; } - public ReRouteBuilder WithLoadBalancerKey(string loadBalancerKey) + public ReRouteBuilder WithReRouteKey(string loadBalancerKey) { _loadBalancerKey = loadBalancerKey; return this; diff --git a/src/Ocelot/Configuration/Builder/ServiceProviderConfigurationBuilder.cs b/src/Ocelot/Configuration/Builder/ServiceProviderConfigurationBuilder.cs index fe9f7f3c..3a9f7974 100644 --- a/src/Ocelot/Configuration/Builder/ServiceProviderConfigurationBuilder.cs +++ b/src/Ocelot/Configuration/Builder/ServiceProviderConfigurationBuilder.cs @@ -2,16 +2,9 @@ namespace Ocelot.Configuration.Builder { public class ServiceProviderConfigurationBuilder { - private string _serviceDiscoveryProvider; private string _serviceDiscoveryProviderHost; private int _serviceDiscoveryProviderPort; - public ServiceProviderConfigurationBuilder WithServiceDiscoveryProvider(string serviceDiscoveryProvider) - { - _serviceDiscoveryProvider = serviceDiscoveryProvider; - return this; - } - public ServiceProviderConfigurationBuilder WithServiceDiscoveryProviderHost(string serviceDiscoveryProviderHost) { _serviceDiscoveryProviderHost = serviceDiscoveryProviderHost; @@ -26,7 +19,7 @@ namespace Ocelot.Configuration.Builder public ServiceProviderConfiguration Build() { - return new ServiceProviderConfiguration(_serviceDiscoveryProvider, _serviceDiscoveryProviderHost,_serviceDiscoveryProviderPort); + return new ServiceProviderConfiguration(_serviceDiscoveryProviderHost,_serviceDiscoveryProviderPort); } } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs index cd6e54ff..bffb8392 100644 --- a/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs +++ b/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs @@ -26,8 +26,6 @@ namespace Ocelot.Configuration.Creator private readonly IOptions _options; private readonly IConfigurationValidator _configurationValidator; private readonly IOcelotLogger _logger; - private readonly IQoSProviderFactory _qoSProviderFactory; - private readonly IQosProviderHouse _qosProviderHouse; private readonly IClaimsToThingCreator _claimsToThingCreator; private readonly IAuthenticationOptionsCreator _authOptionsCreator; private readonly IUpstreamTemplatePatternCreator _upstreamTemplatePatternCreator; @@ -43,8 +41,6 @@ namespace Ocelot.Configuration.Creator IOptions options, IConfigurationValidator configurationValidator, IOcelotLoggerFactory loggerFactory, - IQoSProviderFactory qoSProviderFactory, - IQosProviderHouse qosProviderHouse, IClaimsToThingCreator claimsToThingCreator, IAuthenticationOptionsCreator authOptionsCreator, IUpstreamTemplatePatternCreator upstreamTemplatePatternCreator, @@ -62,8 +58,6 @@ namespace Ocelot.Configuration.Creator _requestIdKeyCreator = requestIdKeyCreator; _upstreamTemplatePatternCreator = upstreamTemplatePatternCreator; _authOptionsCreator = authOptionsCreator; - _qoSProviderFactory = qoSProviderFactory; - _qosProviderHouse = qosProviderHouse; _options = options; _configurationValidator = configurationValidator; _logger = loggerFactory.CreateLogger(); @@ -108,7 +102,7 @@ namespace Ocelot.Configuration.Creator foreach (var reRoute in fileConfiguration.ReRoutes) { - var ocelotReRoute = await SetUpReRoute(reRoute, fileConfiguration.GlobalConfiguration); + var ocelotReRoute = SetUpReRoute(reRoute, fileConfiguration.GlobalConfiguration); reRoutes.Add(ocelotReRoute); } @@ -117,7 +111,7 @@ namespace Ocelot.Configuration.Creator return new OcelotConfiguration(reRoutes, fileConfiguration.GlobalConfiguration.AdministrationPath, serviceProviderConfiguration); } - private async Task SetUpReRoute(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration) + private ReRoute SetUpReRoute(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration) { var fileReRouteOptions = _fileReRouteOptionsCreator.Create(fileReRoute); @@ -162,7 +156,7 @@ namespace Ocelot.Configuration.Creator .WithLoadBalancer(fileReRoute.LoadBalancer) .WithDownstreamHost(fileReRoute.DownstreamHost) .WithDownstreamPort(fileReRoute.DownstreamPort) - .WithLoadBalancerKey(reRouteKey) + .WithReRouteKey(reRouteKey) .WithIsQos(fileReRouteOptions.IsQos) .WithQosOptions(qosOptions) .WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting) @@ -172,7 +166,6 @@ namespace Ocelot.Configuration.Creator .WithUseServiceDiscovery(fileReRoute.UseServiceDiscovery) .Build(); - SetupQosProvider(reRoute); return reRoute; } @@ -182,11 +175,5 @@ namespace Ocelot.Configuration.Creator var loadBalancerKey = $"{fileReRoute.UpstreamPathTemplate}|{string.Join(",", fileReRoute.UpstreamHttpMethod)}"; return loadBalancerKey; } - - private void SetupQosProvider(ReRoute reRoute) - { - var loadBalancer = _qoSProviderFactory.Get(reRoute); - _qosProviderHouse.Add(reRoute.ReRouteKey, loadBalancer); - } } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/Creator/ServiceProviderConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/ServiceProviderConfigurationCreator.cs index a29e285c..4980ae69 100644 --- a/src/Ocelot/Configuration/Creator/ServiceProviderConfigurationCreator.cs +++ b/src/Ocelot/Configuration/Creator/ServiceProviderConfigurationCreator.cs @@ -10,7 +10,6 @@ namespace Ocelot.Configuration.Creator var serviceProviderPort = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0; return new ServiceProviderConfigurationBuilder() - .WithServiceDiscoveryProvider(globalConfiguration?.ServiceDiscoveryProvider?.Provider) .WithServiceDiscoveryProviderHost(globalConfiguration?.ServiceDiscoveryProvider?.Host) .WithServiceDiscoveryProviderPort(serviceProviderPort) .Build(); diff --git a/src/Ocelot/Configuration/File/FileServiceDiscoveryProvider.cs b/src/Ocelot/Configuration/File/FileServiceDiscoveryProvider.cs index 70a3c42f..37cac26f 100644 --- a/src/Ocelot/Configuration/File/FileServiceDiscoveryProvider.cs +++ b/src/Ocelot/Configuration/File/FileServiceDiscoveryProvider.cs @@ -2,8 +2,6 @@ namespace Ocelot.Configuration.File { public class FileServiceDiscoveryProvider { - - public string Provider {get;set;} public string Host {get;set;} public int Port { get; set; } } diff --git a/src/Ocelot/Configuration/Repository/ConsulOcelotConfigurationRepository.cs b/src/Ocelot/Configuration/Repository/ConsulOcelotConfigurationRepository.cs index 25c5b00a..c7de98d2 100644 --- a/src/Ocelot/Configuration/Repository/ConsulOcelotConfigurationRepository.cs +++ b/src/Ocelot/Configuration/Repository/ConsulOcelotConfigurationRepository.cs @@ -11,19 +11,19 @@ namespace Ocelot.Configuration.Repository public class ConsulOcelotConfigurationRepository : IOcelotConfigurationRepository { private readonly ConsulClient _consul; - private ConsulRegistryConfiguration _configuration; private string _ocelotConfiguration = "OcelotConfiguration"; - private Cache.IOcelotCache _cache; + private readonly Cache.IOcelotCache _cache; - public ConsulOcelotConfigurationRepository(ConsulRegistryConfiguration consulRegistryConfiguration, Cache.IOcelotCache cache) + + public ConsulOcelotConfigurationRepository(Cache.IOcelotCache cache, ServiceProviderConfiguration serviceProviderConfig) { - var consulHost = string.IsNullOrEmpty(consulRegistryConfiguration?.HostName) ? "localhost" : consulRegistryConfiguration.HostName; - var consulPort = consulRegistryConfiguration?.Port ?? 8500; - _configuration = new ConsulRegistryConfiguration(consulHost, consulPort, consulRegistryConfiguration?.ServiceName); + var consulHost = string.IsNullOrEmpty(serviceProviderConfig?.ServiceProviderHost) ? "localhost" : serviceProviderConfig?.ServiceProviderHost; + var consulPort = serviceProviderConfig?.ServiceProviderPort ?? 8500; + var configuration = new ConsulRegistryConfiguration(consulHost, consulPort, _ocelotConfiguration); _cache = cache; - _consul = new ConsulClient(config => + _consul = new ConsulClient(c => { - config.Address = new Uri($"http://{_configuration.HostName}:{_configuration.Port}"); + c.Address = new Uri($"http://{configuration.HostName}:{configuration.Port}"); }); } diff --git a/src/Ocelot/Configuration/ServiceProviderConfiguraion.cs b/src/Ocelot/Configuration/ServiceProviderConfiguraion.cs index 46351044..d5ddea6a 100644 --- a/src/Ocelot/Configuration/ServiceProviderConfiguraion.cs +++ b/src/Ocelot/Configuration/ServiceProviderConfiguraion.cs @@ -2,14 +2,12 @@ { public class ServiceProviderConfiguration { - public ServiceProviderConfiguration(string serviceDiscoveryProvider, string serviceProviderHost, int serviceProviderPort) + public ServiceProviderConfiguration(string serviceProviderHost, int serviceProviderPort) { - ServiceDiscoveryProvider = serviceDiscoveryProvider; ServiceProviderHost = serviceProviderHost; ServiceProviderPort = serviceProviderPort; } - public string ServiceDiscoveryProvider { get; } public string ServiceProviderHost { get; private set; } public int ServiceProviderPort { get; private set; } } diff --git a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs index 33f6dabb..32e29c04 100644 --- a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs @@ -45,20 +45,39 @@ using IdentityServer4.AccessTokenValidation; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Ocelot.Configuration; +using Ocelot.Configuration.Builder; using FileConfigurationProvider = Ocelot.Configuration.Provider.FileConfigurationProvider; -using Ocelot.LoadBalancer; namespace Ocelot.DependencyInjection { public static class ServiceCollectionExtensions { - public static IServiceCollection AddOcelotStoreConfigurationInConsul(this IServiceCollection services, ConsulRegistryConfiguration consulConfig) + public static IServiceCollection AddStoreOcelotConfigurationInConsul(this IServiceCollection services, IConfigurationRoot configurationRoot) { - services.AddSingleton(consulConfig); + var serviceDiscoveryPort = configurationRoot.GetValue("GlobalConfiguration:ServiceDiscoveryProvider:Port", 0); + var serviceDiscoveryHost = configurationRoot.GetValue("GlobalConfiguration:ServiceDiscoveryProvider:Host", string.Empty); + + var config = new ServiceProviderConfigurationBuilder() + .WithServiceDiscoveryProviderPort(serviceDiscoveryPort) + .WithServiceDiscoveryProviderHost(serviceDiscoveryHost) + .Build(); + + services.AddSingleton(config); services.AddSingleton(); return services; } + public static IServiceCollection AddOcelot(this IServiceCollection services, + IConfigurationRoot configurationRoot) + { + Action defaultCachingSettings = x => + { + x.WithDictionaryHandle(); + }; + + return services.AddOcelot(configurationRoot, defaultCachingSettings); + } + public static IServiceCollection AddOcelot(this IServiceCollection services, IConfigurationRoot configurationRoot, Action settings) { var cacheManagerOutputCache = CacheFactory.Build("OcelotOutputCache", settings); diff --git a/src/Ocelot/LoadBalancer/LoadBalancers/LeastConnectionLoadBalancer.cs b/src/Ocelot/LoadBalancer/LoadBalancers/LeastConnection.cs similarity index 96% rename from src/Ocelot/LoadBalancer/LoadBalancers/LeastConnectionLoadBalancer.cs rename to src/Ocelot/LoadBalancer/LoadBalancers/LeastConnection.cs index cd56ef91..0e136b4a 100644 --- a/src/Ocelot/LoadBalancer/LoadBalancers/LeastConnectionLoadBalancer.cs +++ b/src/Ocelot/LoadBalancer/LoadBalancers/LeastConnection.cs @@ -8,14 +8,14 @@ using Ocelot.Values; namespace Ocelot.LoadBalancer.LoadBalancers { - public class LeastConnectionLoadBalancer : ILoadBalancer + public class LeastConnection : ILoadBalancer { private readonly Func>> _services; private readonly List _leases; private readonly string _serviceName; private static readonly object _syncLock = new object(); - public LeastConnectionLoadBalancer(Func>> services, string serviceName) + public LeastConnection(Func>> services, string serviceName) { _services = services; _serviceName = serviceName; diff --git a/src/Ocelot/LoadBalancer/LoadBalancers/LoadBalancerFactory.cs b/src/Ocelot/LoadBalancer/LoadBalancers/LoadBalancerFactory.cs index 596a1c22..b3d68672 100644 --- a/src/Ocelot/LoadBalancer/LoadBalancers/LoadBalancerFactory.cs +++ b/src/Ocelot/LoadBalancer/LoadBalancers/LoadBalancerFactory.cs @@ -19,9 +19,9 @@ namespace Ocelot.LoadBalancer.LoadBalancers switch (reRoute.LoadBalancer) { case "RoundRobin": - return new RoundRobinLoadBalancer(async () => await serviceProvider.Get()); + return new RoundRobin(async () => await serviceProvider.Get()); case "LeastConnection": - return new LeastConnectionLoadBalancer(async () => await serviceProvider.Get(), reRoute.ServiceName); + return new LeastConnection(async () => await serviceProvider.Get(), reRoute.ServiceName); default: return new NoLoadBalancer(await serviceProvider.Get()); } diff --git a/src/Ocelot/LoadBalancer/LoadBalancers/LoadBalancerHouse.cs b/src/Ocelot/LoadBalancer/LoadBalancers/LoadBalancerHouse.cs index d4a54bd7..9e0ef296 100644 --- a/src/Ocelot/LoadBalancer/LoadBalancers/LoadBalancerHouse.cs +++ b/src/Ocelot/LoadBalancer/LoadBalancers/LoadBalancerHouse.cs @@ -22,16 +22,11 @@ namespace Ocelot.LoadBalancer.LoadBalancers { try { - ILoadBalancer loadBalancer; - - if(_loadBalancers.TryGetValue(reRoute.ReRouteKey, out loadBalancer)) + if(_loadBalancers.TryGetValue(reRoute.ReRouteKey, out var loadBalancer)) { loadBalancer = _loadBalancers[reRoute.ReRouteKey]; - //todo - we have some duplicate namey type logic in the LoadBalancerFactory...maybe we can do something - //about this.. - if((reRoute.LoadBalancer == "RoundRobin" && loadBalancer.GetType() != typeof(RoundRobinLoadBalancer)) - || (reRoute.LoadBalancer == "LeastConnection" && loadBalancer.GetType() != typeof(LeastConnectionLoadBalancer))) + if(reRoute.LoadBalancer != loadBalancer.GetType().Name) { loadBalancer = await _factory.Get(reRoute, config); AddLoadBalancer(reRoute.ReRouteKey, loadBalancer); @@ -55,18 +50,7 @@ namespace Ocelot.LoadBalancer.LoadBalancers private void AddLoadBalancer(string key, ILoadBalancer loadBalancer) { - _loadBalancers.AddOrUpdate(key, loadBalancer, (x, y) => { - return loadBalancer; - }); - - // if (!_loadBalancers.ContainsKey(key)) - // { - // _loadBalancers.TryAdd(key, loadBalancer); - // } - - // ILoadBalancer old; - // _loadBalancers.Remove(key, out old); - // _loadBalancers.TryAdd(key, loadBalancer); + _loadBalancers.AddOrUpdate(key, loadBalancer, (x, y) => loadBalancer); } } } diff --git a/src/Ocelot/LoadBalancer/LoadBalancers/RoundRobinLoadBalancer.cs b/src/Ocelot/LoadBalancer/LoadBalancers/RoundRobin.cs similarity index 85% rename from src/Ocelot/LoadBalancer/LoadBalancers/RoundRobinLoadBalancer.cs rename to src/Ocelot/LoadBalancer/LoadBalancers/RoundRobin.cs index 4bc78915..817a1b8f 100644 --- a/src/Ocelot/LoadBalancer/LoadBalancers/RoundRobinLoadBalancer.cs +++ b/src/Ocelot/LoadBalancer/LoadBalancers/RoundRobin.cs @@ -6,13 +6,13 @@ using System; namespace Ocelot.LoadBalancer.LoadBalancers { - public class RoundRobinLoadBalancer : ILoadBalancer + public class RoundRobin : ILoadBalancer { private readonly Func>> _services; private int _last; - public RoundRobinLoadBalancer(Func>> services) + public RoundRobin(Func>> services) { _services = services; } diff --git a/src/Ocelot/Request/Middleware/HttpRequestBuilderMiddleware.cs b/src/Ocelot/Request/Middleware/HttpRequestBuilderMiddleware.cs index 8e05f2ea..d04e76e2 100644 --- a/src/Ocelot/Request/Middleware/HttpRequestBuilderMiddleware.cs +++ b/src/Ocelot/Request/Middleware/HttpRequestBuilderMiddleware.cs @@ -32,7 +32,7 @@ namespace Ocelot.Request.Middleware { _logger.LogDebug("started calling request builder middleware"); - var qosProvider = _qosProviderHouse.Get(DownstreamRoute.ReRoute.ReRouteKey); + var qosProvider = _qosProviderHouse.Get(DownstreamRoute.ReRoute); if (qosProvider.IsError) { diff --git a/src/Ocelot/Requester/QoS/CircuitBreaker.cs b/src/Ocelot/Requester/QoS/CircuitBreaker.cs new file mode 100644 index 00000000..4b1a0d79 --- /dev/null +++ b/src/Ocelot/Requester/QoS/CircuitBreaker.cs @@ -0,0 +1,17 @@ +using Polly.CircuitBreaker; +using Polly.Timeout; + +namespace Ocelot.Requester.QoS +{ + public class CircuitBreaker + { + public CircuitBreaker(CircuitBreakerPolicy circuitBreakerPolicy, TimeoutPolicy timeoutPolicy) + { + CircuitBreakerPolicy = circuitBreakerPolicy; + TimeoutPolicy = timeoutPolicy; + } + + public CircuitBreakerPolicy CircuitBreakerPolicy { get; private set; } + public TimeoutPolicy TimeoutPolicy { get; private set; } + } +} \ No newline at end of file diff --git a/src/Ocelot/Requester/QoS/IQoSProvider.cs b/src/Ocelot/Requester/QoS/IQoSProvider.cs new file mode 100644 index 00000000..75fc48e3 --- /dev/null +++ b/src/Ocelot/Requester/QoS/IQoSProvider.cs @@ -0,0 +1,7 @@ +namespace Ocelot.Requester.QoS +{ + public interface IQoSProvider + { + CircuitBreaker CircuitBreaker { get; } + } +} \ No newline at end of file diff --git a/src/Ocelot/Requester/QoS/IQoSProviderFactory.cs b/src/Ocelot/Requester/QoS/IQoSProviderFactory.cs index feabfc09..ae23c397 100644 --- a/src/Ocelot/Requester/QoS/IQoSProviderFactory.cs +++ b/src/Ocelot/Requester/QoS/IQoSProviderFactory.cs @@ -1,13 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Net.Http; -using Ocelot.Configuration; +using Ocelot.Configuration; using Ocelot.LoadBalancer.LoadBalancers; -using Ocelot.Logging; -using Ocelot.Responses; -using Polly; -using Polly.CircuitBreaker; -using Polly.Timeout; namespace Ocelot.Requester.QoS { @@ -15,131 +7,4 @@ namespace Ocelot.Requester.QoS { IQoSProvider Get(ReRoute reRoute); } - - public class QoSProviderFactory : IQoSProviderFactory - { - private readonly IOcelotLoggerFactory _loggerFactory; - - public QoSProviderFactory(IOcelotLoggerFactory loggerFactory) - { - _loggerFactory = loggerFactory; - } - - public IQoSProvider Get(ReRoute reRoute) - { - if (reRoute.IsQos) - { - return new PollyQoSProvider(reRoute, _loggerFactory); - } - - return new NoQoSProvider(); - } - } - - public interface IQoSProvider - { - CircuitBreaker CircuitBreaker { get; } - } - - public class NoQoSProvider : IQoSProvider - { - public CircuitBreaker CircuitBreaker { get; } - } - - public class PollyQoSProvider : IQoSProvider - { - private readonly CircuitBreakerPolicy _circuitBreakerPolicy; - private readonly TimeoutPolicy _timeoutPolicy; - private readonly IOcelotLogger _logger; - private readonly CircuitBreaker _circuitBreaker; - - public PollyQoSProvider(ReRoute reRoute, IOcelotLoggerFactory loggerFactory) - { - _logger = loggerFactory.CreateLogger(); - - _timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromMilliseconds(reRoute.QosOptionsOptions.TimeoutValue), reRoute.QosOptionsOptions.TimeoutStrategy); - - _circuitBreakerPolicy = Policy - .Handle() - .Or() - .Or() - .CircuitBreakerAsync( - exceptionsAllowedBeforeBreaking: reRoute.QosOptionsOptions.ExceptionsAllowedBeforeBreaking, - durationOfBreak: TimeSpan.FromMilliseconds(reRoute.QosOptionsOptions.DurationOfBreak), - onBreak: (ex, breakDelay) => - { - _logger.LogError( - ".Breaker logging: Breaking the circuit for " + breakDelay.TotalMilliseconds + "ms!", ex); - }, - onReset: () => - { - _logger.LogDebug(".Breaker logging: Call ok! Closed the circuit again."); - }, - onHalfOpen: () => - { - _logger.LogDebug(".Breaker logging: Half-open; next call is a trial."); - } - ); - - _circuitBreaker = new CircuitBreaker(_circuitBreakerPolicy, _timeoutPolicy); - } - - public CircuitBreaker CircuitBreaker => _circuitBreaker; - } - - public class CircuitBreaker - { - public CircuitBreaker(CircuitBreakerPolicy circuitBreakerPolicy, TimeoutPolicy timeoutPolicy) - { - CircuitBreakerPolicy = circuitBreakerPolicy; - TimeoutPolicy = timeoutPolicy; - } - - public CircuitBreakerPolicy CircuitBreakerPolicy { get; private set; } - public TimeoutPolicy TimeoutPolicy { get; private set; } - } - - - public interface IQosProviderHouse - { - Response Get(string key); - Response Add(string key, IQoSProvider loadBalancer); - } - - public class QosProviderHouse : IQosProviderHouse - { - private readonly Dictionary _qoSProviders; - - public QosProviderHouse() - { - _qoSProviders = new Dictionary(); - } - - public Response Get(string key) - { - IQoSProvider qoSProvider; - - if (_qoSProviders.TryGetValue(key, out qoSProvider)) - { - return new OkResponse(_qoSProviders[key]); - } - - return new ErrorResponse(new List() - { - new UnableToFindQoSProviderError($"unabe to find qos provider for {key}") - }); - } - - public Response Add(string key, IQoSProvider loadBalancer) - { - if (!_qoSProviders.ContainsKey(key)) - { - _qoSProviders.Add(key, loadBalancer); - } - - _qoSProviders.Remove(key); - _qoSProviders.Add(key, loadBalancer); - return new OkResponse(); - } - } } diff --git a/src/Ocelot/Requester/QoS/IQosProviderHouse.cs b/src/Ocelot/Requester/QoS/IQosProviderHouse.cs new file mode 100644 index 00000000..1ec0cf73 --- /dev/null +++ b/src/Ocelot/Requester/QoS/IQosProviderHouse.cs @@ -0,0 +1,10 @@ +using Ocelot.Configuration; +using Ocelot.Responses; + +namespace Ocelot.Requester.QoS +{ + public interface IQosProviderHouse + { + Response Get(ReRoute reRoute); + } +} \ No newline at end of file diff --git a/src/Ocelot/Requester/QoS/NoQoSProvider.cs b/src/Ocelot/Requester/QoS/NoQoSProvider.cs new file mode 100644 index 00000000..51d879de --- /dev/null +++ b/src/Ocelot/Requester/QoS/NoQoSProvider.cs @@ -0,0 +1,7 @@ +namespace Ocelot.Requester.QoS +{ + public class NoQoSProvider : IQoSProvider + { + public CircuitBreaker CircuitBreaker { get; } + } +} \ No newline at end of file diff --git a/src/Ocelot/Requester/QoS/PollyQoSProvider.cs b/src/Ocelot/Requester/QoS/PollyQoSProvider.cs new file mode 100644 index 00000000..69f7e608 --- /dev/null +++ b/src/Ocelot/Requester/QoS/PollyQoSProvider.cs @@ -0,0 +1,51 @@ +using System; +using System.Net.Http; +using Ocelot.Configuration; +using Ocelot.Logging; +using Polly; +using Polly.CircuitBreaker; +using Polly.Timeout; + +namespace Ocelot.Requester.QoS +{ + public class PollyQoSProvider : IQoSProvider + { + private readonly CircuitBreakerPolicy _circuitBreakerPolicy; + private readonly TimeoutPolicy _timeoutPolicy; + private readonly IOcelotLogger _logger; + private readonly CircuitBreaker _circuitBreaker; + + public PollyQoSProvider(ReRoute reRoute, IOcelotLoggerFactory loggerFactory) + { + _logger = loggerFactory.CreateLogger(); + + _timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromMilliseconds(reRoute.QosOptionsOptions.TimeoutValue), reRoute.QosOptionsOptions.TimeoutStrategy); + + _circuitBreakerPolicy = Policy + .Handle() + .Or() + .Or() + .CircuitBreakerAsync( + exceptionsAllowedBeforeBreaking: reRoute.QosOptionsOptions.ExceptionsAllowedBeforeBreaking, + durationOfBreak: TimeSpan.FromMilliseconds(reRoute.QosOptionsOptions.DurationOfBreak), + onBreak: (ex, breakDelay) => + { + _logger.LogError( + ".Breaker logging: Breaking the circuit for " + breakDelay.TotalMilliseconds + "ms!", ex); + }, + onReset: () => + { + _logger.LogDebug(".Breaker logging: Call ok! Closed the circuit again."); + }, + onHalfOpen: () => + { + _logger.LogDebug(".Breaker logging: Half-open; next call is a trial."); + } + ); + + _circuitBreaker = new CircuitBreaker(_circuitBreakerPolicy, _timeoutPolicy); + } + + public CircuitBreaker CircuitBreaker => _circuitBreaker; + } +} \ No newline at end of file diff --git a/src/Ocelot/Requester/QoS/QoSProviderFactory.cs b/src/Ocelot/Requester/QoS/QoSProviderFactory.cs new file mode 100644 index 00000000..59ce123e --- /dev/null +++ b/src/Ocelot/Requester/QoS/QoSProviderFactory.cs @@ -0,0 +1,25 @@ +using Ocelot.Configuration; +using Ocelot.Logging; + +namespace Ocelot.Requester.QoS +{ + public class QoSProviderFactory : IQoSProviderFactory + { + private readonly IOcelotLoggerFactory _loggerFactory; + + public QoSProviderFactory(IOcelotLoggerFactory loggerFactory) + { + _loggerFactory = loggerFactory; + } + + public IQoSProvider Get(ReRoute reRoute) + { + if (reRoute.IsQos) + { + return new PollyQoSProvider(reRoute, _loggerFactory); + } + + return new NoQoSProvider(); + } + } +} \ No newline at end of file diff --git a/src/Ocelot/Requester/QoS/QosProviderHouse.cs b/src/Ocelot/Requester/QoS/QosProviderHouse.cs new file mode 100644 index 00000000..780f8181 --- /dev/null +++ b/src/Ocelot/Requester/QoS/QosProviderHouse.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using Ocelot.Configuration; +using Ocelot.Responses; + +namespace Ocelot.Requester.QoS +{ + public class QosProviderHouse : IQosProviderHouse + { + private readonly ConcurrentDictionary _qoSProviders; + private readonly IQoSProviderFactory _qoSProviderFactory; + + public QosProviderHouse(IQoSProviderFactory qoSProviderFactory) + { + _qoSProviderFactory = qoSProviderFactory; + _qoSProviders = new ConcurrentDictionary(); + } + + public Response Get(ReRoute reRoute) + { + try + { + if (_qoSProviders.TryGetValue(reRoute.ReRouteKey, out var qosProvider)) + { + if (reRoute.IsQos && qosProvider.CircuitBreaker == null) + { + qosProvider = _qoSProviderFactory.Get(reRoute); + Add(reRoute.ReRouteKey, qosProvider); + } + + return new OkResponse(_qoSProviders[reRoute.ReRouteKey]); + } + + qosProvider = _qoSProviderFactory.Get(reRoute); + Add(reRoute.ReRouteKey, qosProvider); + return new OkResponse(qosProvider); + } + catch (Exception ex) + { + return new ErrorResponse(new List() + { + new UnableToFindQoSProviderError($"unabe to find qos provider for {reRoute.ReRouteKey}, exception was {ex}") + }); + } + } + + private void Add(string key, IQoSProvider qosProvider) + { + _qoSProviders.AddOrUpdate(key, qosProvider, (x, y) => qosProvider); + } + } +} \ No newline at end of file diff --git a/src/Ocelot/ServiceDiscovery/ConsulRegistryConfiguration.cs b/src/Ocelot/ServiceDiscovery/ConsulRegistryConfiguration.cs index 8d496a85..e06c22bd 100644 --- a/src/Ocelot/ServiceDiscovery/ConsulRegistryConfiguration.cs +++ b/src/Ocelot/ServiceDiscovery/ConsulRegistryConfiguration.cs @@ -2,14 +2,14 @@ namespace Ocelot.ServiceDiscovery { public class ConsulRegistryConfiguration { - public ConsulRegistryConfiguration(string hostName, int port, string serviceName) + public ConsulRegistryConfiguration(string hostName, int port, string keyOfServiceInConsul) { HostName = hostName; Port = port; - ServiceName = serviceName; + KeyOfServiceInConsul = keyOfServiceInConsul; } - public string ServiceName { get; private set; } + public string KeyOfServiceInConsul { get; private set; } public string HostName { get; private set; } public int Port { get; private set; } } diff --git a/src/Ocelot/ServiceDiscovery/ConsulServiceDiscoveryProvider.cs b/src/Ocelot/ServiceDiscovery/ConsulServiceDiscoveryProvider.cs index c74c90f0..5dd906f9 100644 --- a/src/Ocelot/ServiceDiscovery/ConsulServiceDiscoveryProvider.cs +++ b/src/Ocelot/ServiceDiscovery/ConsulServiceDiscoveryProvider.cs @@ -10,7 +10,7 @@ namespace Ocelot.ServiceDiscovery { public class ConsulServiceDiscoveryProvider : IServiceDiscoveryProvider { - private readonly ConsulRegistryConfiguration _configuration; + private readonly ConsulRegistryConfiguration _consulConfig; private readonly ConsulClient _consul; private const string VersionPrefix = "version-"; @@ -18,17 +18,17 @@ namespace Ocelot.ServiceDiscovery { var consulHost = string.IsNullOrEmpty(consulRegistryConfiguration?.HostName) ? "localhost" : consulRegistryConfiguration.HostName; var consulPort = consulRegistryConfiguration?.Port ?? 8500; - _configuration = new ConsulRegistryConfiguration(consulHost, consulPort, consulRegistryConfiguration?.ServiceName); + _consulConfig = new ConsulRegistryConfiguration(consulHost, consulPort, consulRegistryConfiguration?.KeyOfServiceInConsul); _consul = new ConsulClient(config => { - config.Address = new Uri($"http://{_configuration.HostName}:{_configuration.Port}"); + config.Address = new Uri($"http://{_consulConfig.HostName}:{_consulConfig.Port}"); }); } public async Task> Get() { - var queryResult = await _consul.Health.Service(_configuration.ServiceName, string.Empty, true); + var queryResult = await _consul.Health.Service(_consulConfig.KeyOfServiceInConsul, string.Empty, true); var services = queryResult.Response.Select(BuildService); diff --git a/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs b/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs index 5dc4982a..cd724292 100644 --- a/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs +++ b/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs @@ -10,7 +10,7 @@ namespace Ocelot.ServiceDiscovery { if (reRoute.UseServiceDiscovery) { - return GetServiceDiscoveryProvider(reRoute.ServiceName, serviceConfig.ServiceDiscoveryProvider, serviceConfig.ServiceProviderHost, serviceConfig.ServiceProviderPort); + return GetServiceDiscoveryProvider(reRoute.ServiceName, serviceConfig.ServiceProviderHost, serviceConfig.ServiceProviderPort); } var services = new List() @@ -25,9 +25,9 @@ namespace Ocelot.ServiceDiscovery return new ConfigurationServiceProvider(services); } - private IServiceDiscoveryProvider GetServiceDiscoveryProvider(string serviceName, string serviceProviderName, string providerHostName, int providerPort) + private IServiceDiscoveryProvider GetServiceDiscoveryProvider(string keyOfServiceInConsul, string providerHostName, int providerPort) { - var consulRegistryConfiguration = new ConsulRegistryConfiguration(providerHostName, providerPort, serviceName); + var consulRegistryConfiguration = new ConsulRegistryConfiguration(providerHostName, providerPort, keyOfServiceInConsul); return new ConsulServiceDiscoveryProvider(consulRegistryConfiguration); } } diff --git a/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs b/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs index 90db18e3..aca07a3c 100644 --- a/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs +++ b/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.IO; using System.Net; using System.Text; -using System.Threading; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; @@ -11,7 +10,6 @@ using Newtonsoft.Json; using Ocelot.Configuration; using Ocelot.Configuration.Builder; using Ocelot.Configuration.File; -using Ocelot.ServiceDiscovery; using TestStack.BDDfy; using Xunit; @@ -50,7 +48,6 @@ namespace Ocelot.AcceptanceTests { ServiceDiscoveryProvider = new FileServiceDiscoveryProvider() { - Provider = "Consul", Host = "localhost", Port = 9500 } @@ -59,12 +56,10 @@ namespace Ocelot.AcceptanceTests var fakeConsulServiceDiscoveryUrl = "http://localhost:9500"; - var consulConfig = new ConsulRegistryConfiguration("localhost", 9500, "Ocelot"); - this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl)) .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51779", "", 200, "Hello from Laura")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfig(consulConfig)) + .And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfig()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) @@ -73,31 +68,25 @@ namespace Ocelot.AcceptanceTests [Fact] public void should_fix_issue_142() - { + { + var consulPort = 8500; var configuration = new FileConfiguration { - ReRoutes = new List - { - }, GlobalConfiguration = new FileGlobalConfiguration() { ServiceDiscoveryProvider = new FileServiceDiscoveryProvider() { - Provider = "Consul", Host = "localhost", - Port = 9500 + Port = consulPort } } }; - var fakeConsulServiceDiscoveryUrl = "http://localhost:9500"; - - var consulConfig = new ConsulRegistryConfiguration("localhost", 9500, "Ocelot"); + var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}"; var serviceProviderConfig = new ServiceProviderConfigurationBuilder() - .WithServiceDiscoveryProvider("Consul") .WithServiceDiscoveryProviderHost("localhost") - .WithServiceDiscoveryProviderPort(8500) + .WithServiceDiscoveryProviderPort(consulPort) .Build(); var reRoute = new ReRouteBuilder() @@ -108,10 +97,8 @@ namespace Ocelot.AcceptanceTests .WithDownstreamPort(51779) .WithUpstreamPathTemplate("/cs/status") .WithUpstreamHttpMethod(new List {"Get"}) - .WithLoadBalancer("LeastConnection") - .WithLoadBalancerKey("/cs/status|Get") - .WithServiceName("") - .WithUseServiceDiscovery(true) + .WithReRouteKey("/cs/status|Get") + .WithHttpHandlerOptions(new HttpHandlerOptions(true, false)) .Build(); var reRoutes = new List { reRoute }; @@ -122,7 +109,7 @@ namespace Ocelot.AcceptanceTests .And(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl)) .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51779", "/status", 200, "Hello from Laura")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfig(consulConfig)) + .And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfig()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/cs/status")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) diff --git a/test/Ocelot.AcceptanceTests/ServiceDiscoveryTests.cs b/test/Ocelot.AcceptanceTests/ServiceDiscoveryTests.cs index a856656e..2c7b6b56 100644 --- a/test/Ocelot.AcceptanceTests/ServiceDiscoveryTests.cs +++ b/test/Ocelot.AcceptanceTests/ServiceDiscoveryTests.cs @@ -33,10 +33,11 @@ namespace Ocelot.AcceptanceTests [Fact] public void should_use_service_discovery_and_load_balance_request() { + var consulPort = 8501; var serviceName = "product"; var downstreamServiceOneUrl = "http://localhost:50879"; var downstreamServiceTwoUrl = "http://localhost:50880"; - var fakeConsulServiceDiscoveryUrl = "http://localhost:8500"; + var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}"; var serviceEntryOne = new ServiceEntry() { Service = new AgentService() @@ -79,9 +80,8 @@ namespace Ocelot.AcceptanceTests { ServiceDiscoveryProvider = new FileServiceDiscoveryProvider() { - Provider = "Consul", Host = "localhost", - Port = 8500 + Port = consulPort } } }; diff --git a/test/Ocelot.AcceptanceTests/Startup.cs b/test/Ocelot.AcceptanceTests/Startup.cs index 3a53bfaa..1dacaec2 100644 --- a/test/Ocelot.AcceptanceTests/Startup.cs +++ b/test/Ocelot.AcceptanceTests/Startup.cs @@ -44,4 +44,39 @@ namespace Ocelot.AcceptanceTests app.UseOcelot().Wait(); } } + + public class ConsulStartup + { + public ConsulStartup(IHostingEnvironment env) + { + var builder = new ConfigurationBuilder() + .SetBasePath(env.ContentRootPath) + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) + .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) + .AddJsonFile("configuration.json") + .AddEnvironmentVariables(); + + Configuration = builder.Build(); + } + + public IConfigurationRoot Configuration { get; } + + public void ConfigureServices(IServiceCollection services) + { + Action settings = (x) => + { + x.WithDictionaryHandle(); + }; + + services.AddOcelot(Configuration, settings); + services.AddStoreOcelotConfigurationInConsul(Configuration); + } + + public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) + { + loggerFactory.AddConsole(Configuration.GetSection("Logging")); + + app.UseOcelot().Wait(); + } + } } diff --git a/test/Ocelot.AcceptanceTests/Steps.cs b/test/Ocelot.AcceptanceTests/Steps.cs index 80a3e68e..04f8343e 100644 --- a/test/Ocelot.AcceptanceTests/Steps.cs +++ b/test/Ocelot.AcceptanceTests/Steps.cs @@ -107,18 +107,17 @@ namespace Ocelot.AcceptanceTests _ocelotClient = _ocelotServer.CreateClient(); } - public void GivenOcelotIsRunningUsingConsulToStoreConfig(ConsulRegistryConfiguration consulConfig) + public void GivenOcelotIsRunningUsingConsulToStoreConfig(/*ConsulRegistryConfiguration consulConfig*/) { _webHostBuilder = new WebHostBuilder(); _webHostBuilder.ConfigureServices(s => { s.AddSingleton(_webHostBuilder); - s.AddOcelotStoreConfigurationInConsul(consulConfig); }); _ocelotServer = new TestServer(_webHostBuilder - .UseStartup()); + .UseStartup()); _ocelotClient = _ocelotServer.CreateClient(); } @@ -131,7 +130,6 @@ namespace Ocelot.AcceptanceTests response.GlobalConfiguration.RequestIdKey.ShouldBe(expected.GlobalConfiguration.RequestIdKey); response.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Host); response.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Port); - response.GlobalConfiguration.ServiceDiscoveryProvider.Provider.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Provider); for(var i = 0; i < response.ReRoutes.Count; i++) { diff --git a/test/Ocelot.IntegrationTests/AdministrationTests.cs b/test/Ocelot.IntegrationTests/AdministrationTests.cs index 7cc88ed8..240b7c25 100644 --- a/test/Ocelot.IntegrationTests/AdministrationTests.cs +++ b/test/Ocelot.IntegrationTests/AdministrationTests.cs @@ -107,7 +107,6 @@ namespace Ocelot.IntegrationTests ServiceDiscoveryProvider = new FileServiceDiscoveryProvider { Host = "127.0.0.1", - Provider = "test" } }, @@ -332,7 +331,6 @@ namespace Ocelot.IntegrationTests response.GlobalConfiguration.RequestIdKey.ShouldBe(expected.GlobalConfiguration.RequestIdKey); response.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Host); response.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Port); - response.GlobalConfiguration.ServiceDiscoveryProvider.Provider.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Provider); for (var i = 0; i < response.ReRoutes.Count; i++) { diff --git a/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs index b9264cee..09489523 100644 --- a/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Moq; using Ocelot.Cache; @@ -8,9 +7,7 @@ using Ocelot.Configuration.Builder; using Ocelot.Configuration.Creator; using Ocelot.Configuration.File; using Ocelot.Configuration.Validator; -using Ocelot.LoadBalancer.LoadBalancers; using Ocelot.Logging; -using Ocelot.Requester.QoS; using Ocelot.Responses; using Shouldly; using TestStack.BDDfy; @@ -18,8 +15,6 @@ using Xunit; namespace Ocelot.UnitTests.Configuration { - using System.Collections; - using Ocelot.LoadBalancer; using Ocelot.UnitTests.TestData; public class FileConfigurationCreatorTests @@ -30,10 +25,6 @@ namespace Ocelot.UnitTests.Configuration private FileConfiguration _fileConfiguration; private readonly Mock _logger; private readonly FileOcelotConfigurationCreator _ocelotConfigurationCreator; - private readonly Mock _loadBalancer; - private readonly Mock _qosProviderFactory; - private readonly Mock _qosProviderHouse; - private readonly Mock _qosProvider; private Mock _claimsToThingCreator; private Mock _authOptionsCreator; private Mock _upstreamTemplatePatternCreator; @@ -47,13 +38,9 @@ namespace Ocelot.UnitTests.Configuration public FileConfigurationCreatorTests() { - _qosProviderFactory = new Mock(); - _qosProviderHouse = new Mock(); - _qosProvider = new Mock(); _logger = new Mock(); _validator = new Mock(); _fileConfig = new Mock>(); - _loadBalancer = new Mock(); _claimsToThingCreator = new Mock(); _authOptionsCreator = new Mock(); _upstreamTemplatePatternCreator = new Mock(); @@ -67,7 +54,7 @@ namespace Ocelot.UnitTests.Configuration _ocelotConfigurationCreator = new FileOcelotConfigurationCreator( _fileConfig.Object, _validator.Object, _logger.Object, - _qosProviderFactory.Object, _qosProviderHouse.Object, _claimsToThingCreator.Object, + _claimsToThingCreator.Object, _authOptionsCreator.Object, _upstreamTemplatePatternCreator.Object, _requestIdKeyCreator.Object, _serviceProviderConfigCreator.Object, _qosOptionsCreator.Object, _fileReRouteOptionsCreator.Object, _rateLimitOptions.Object, _regionCreator.Object, _httpHandlerOptionsCreator.Object); @@ -86,7 +73,6 @@ namespace Ocelot.UnitTests.Configuration { Host = "localhost", Port = 8500, - Provider = "consul" } } })) @@ -201,12 +187,9 @@ namespace Ocelot.UnitTests.Configuration })) .And(x => x.GivenTheConfigIsValid()) .And(x => x.GivenTheFollowingOptionsAreReturned(serviceOptions)) - .And(x => x.GivenTheQosProviderFactoryReturns()) .And(x => x.GivenTheQosOptionsCreatorReturns(expected)) .When(x => x.WhenICreateTheConfig()) .Then(x => x.ThenTheQosOptionsAre(expected)) - .And(x => x.TheQosProviderFactoryIsCalledCorrectly()) - .And(x => x.ThenTheQosProviderHouseIsCalledCorrectly()) .BDDfy(); } @@ -301,7 +284,6 @@ namespace Ocelot.UnitTests.Configuration { ServiceDiscoveryProvider = new FileServiceDiscoveryProvider { - Provider = "consul", Host = "127.0.0.1" } } @@ -603,25 +585,6 @@ namespace Ocelot.UnitTests.Configuration } } - private void GivenTheQosProviderFactoryReturns() - { - _qosProviderFactory - .Setup(x => x.Get(It.IsAny())) - .Returns(_qosProvider.Object); - } - - private void TheQosProviderFactoryIsCalledCorrectly() - { - _qosProviderFactory - .Verify(x => x.Get(It.IsAny()), Times.Once); - } - - private void ThenTheQosProviderHouseIsCalledCorrectly() - { - _qosProviderHouse - .Verify(x => x.Add(It.IsAny(), _qosProvider.Object), Times.Once); - } - private void GivenTheClaimsToThingCreatorReturns(List claimsToThing) { _claimsToThingCreator diff --git a/test/Ocelot.UnitTests/Configuration/FileConfigurationRepositoryTests.cs b/test/Ocelot.UnitTests/Configuration/FileConfigurationRepositoryTests.cs index dfa8f67a..33e95910 100644 --- a/test/Ocelot.UnitTests/Configuration/FileConfigurationRepositoryTests.cs +++ b/test/Ocelot.UnitTests/Configuration/FileConfigurationRepositoryTests.cs @@ -43,7 +43,6 @@ namespace Ocelot.UnitTests.Configuration AdministrationPath = "testy", ServiceDiscoveryProvider = new FileServiceDiscoveryProvider { - Provider = "consul", Port = 198, Host = "blah" } @@ -78,7 +77,6 @@ namespace Ocelot.UnitTests.Configuration AdministrationPath = "asdas", ServiceDiscoveryProvider = new FileServiceDiscoveryProvider { - Provider = "consul", Port = 198, Host = "blah" } @@ -111,7 +109,6 @@ namespace Ocelot.UnitTests.Configuration _result.GlobalConfiguration.RequestIdKey.ShouldBe(expected.GlobalConfiguration.RequestIdKey); _result.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Host); _result.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Port); - _result.GlobalConfiguration.ServiceDiscoveryProvider.Provider.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Provider); for(var i = 0; i < _result.ReRoutes.Count; i++) { @@ -147,7 +144,6 @@ namespace Ocelot.UnitTests.Configuration _result.GlobalConfiguration.RequestIdKey.ShouldBe(expected.GlobalConfiguration.RequestIdKey); _result.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Host); _result.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Port); - _result.GlobalConfiguration.ServiceDiscoveryProvider.Provider.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Provider); for(var i = 0; i < _result.ReRoutes.Count; i++) { diff --git a/test/Ocelot.UnitTests/Configuration/ServiceProviderCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/ServiceProviderCreatorTests.cs index 8c33b4e5..2d9fe3a2 100644 --- a/test/Ocelot.UnitTests/Configuration/ServiceProviderCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/ServiceProviderCreatorTests.cs @@ -29,14 +29,12 @@ namespace Ocelot.UnitTests.Configuration { ServiceDiscoveryProvider = new FileServiceDiscoveryProvider { - Provider = "consul", Host = "127.0.0.1", Port = 1234 } }; var expected = new ServiceProviderConfigurationBuilder() - .WithServiceDiscoveryProvider("consul") .WithServiceDiscoveryProviderHost("127.0.0.1") .WithServiceDiscoveryProviderPort(1234) .Build(); @@ -65,7 +63,6 @@ namespace Ocelot.UnitTests.Configuration private void ThenTheConfigIs(ServiceProviderConfiguration expected) { - _result.ServiceDiscoveryProvider.ShouldBe(expected.ServiceDiscoveryProvider); _result.ServiceProviderHost.ShouldBe(expected.ServiceProviderHost); _result.ServiceProviderPort.ShouldBe(expected.ServiceProviderPort); } diff --git a/test/Ocelot.UnitTests/LoadBalancer/LeastConnectionTests.cs b/test/Ocelot.UnitTests/LoadBalancer/LeastConnectionTests.cs index 07002ce3..936a57e8 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/LeastConnectionTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/LeastConnectionTests.cs @@ -14,7 +14,7 @@ namespace Ocelot.UnitTests.LoadBalancer { private HostAndPort _hostAndPort; private Response _result; - private LeastConnectionLoadBalancer _leastConnection; + private LeastConnection _leastConnection; private List _services; private Random _random; @@ -35,7 +35,7 @@ namespace Ocelot.UnitTests.LoadBalancer }; _services = availableServices; - _leastConnection = new LeastConnectionLoadBalancer(() => Task.FromResult(_services), serviceName); + _leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName); var tasks = new Task[100]; @@ -86,7 +86,7 @@ namespace Ocelot.UnitTests.LoadBalancer }; _services = availableServices; - _leastConnection = new LeastConnectionLoadBalancer(() => Task.FromResult(_services), serviceName); + _leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName); var response = _leastConnection.Lease().Result; @@ -113,7 +113,7 @@ namespace Ocelot.UnitTests.LoadBalancer }; _services = availableServices; - _leastConnection = new LeastConnectionLoadBalancer(() => Task.FromResult(_services), serviceName); + _leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName); var response = _leastConnection.Lease().Result; @@ -144,7 +144,7 @@ namespace Ocelot.UnitTests.LoadBalancer }; _services = availableServices; - _leastConnection = new LeastConnectionLoadBalancer(() => Task.FromResult(_services), serviceName); + _leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName); var response = _leastConnection.Lease().Result; @@ -211,7 +211,7 @@ namespace Ocelot.UnitTests.LoadBalancer private void GivenTheLoadBalancerStarts(List services, string serviceName) { _services = services; - _leastConnection = new LeastConnectionLoadBalancer(() => Task.FromResult(_services), serviceName); + _leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName); } private void WhenTheLoadBalancerStarts(List services, string serviceName) diff --git a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerFactoryTests.cs b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerFactoryTests.cs index 9fde2f78..d630393b 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerFactoryTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerFactoryTests.cs @@ -53,7 +53,7 @@ namespace Ocelot.UnitTests.LoadBalancer .And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build())) .And(x => x.GivenTheServiceProviderFactoryReturns()) .When(x => x.WhenIGetTheLoadBalancer()) - .Then(x => x.ThenTheLoadBalancerIsReturned()) + .Then(x => x.ThenTheLoadBalancerIsReturned()) .BDDfy(); } @@ -69,7 +69,7 @@ namespace Ocelot.UnitTests.LoadBalancer .And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build())) .And(x => x.GivenTheServiceProviderFactoryReturns()) .When(x => x.WhenIGetTheLoadBalancer()) - .Then(x => x.ThenTheLoadBalancerIsReturned()) + .Then(x => x.ThenTheLoadBalancerIsReturned()) .BDDfy(); } diff --git a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerHouseTests.cs b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerHouseTests.cs index ccfb32ff..a5211859 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerHouseTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerHouseTests.cs @@ -32,7 +32,7 @@ namespace Ocelot.UnitTests.LoadBalancer [Fact] public void should_store_load_balancer_on_first_request() { - var reRoute = new ReRouteBuilder().WithLoadBalancerKey("test").Build(); + var reRoute = new ReRouteBuilder().WithReRouteKey("test").Build(); this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer())) .Then(x => x.ThenItIsAdded()) @@ -42,7 +42,7 @@ namespace Ocelot.UnitTests.LoadBalancer [Fact] public void should_not_store_load_balancer_on_second_request() { - var reRoute = new ReRouteBuilder().WithLoadBalancerKey("test").Build(); + var reRoute = new ReRouteBuilder().WithLoadBalancer("FakeLoadBalancer").WithReRouteKey("test").Build(); this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer())) .When(x => x.WhenWeGetTheLoadBalancer(reRoute)) @@ -53,8 +53,8 @@ namespace Ocelot.UnitTests.LoadBalancer [Fact] public void should_store_load_balancers_by_key() { - var reRoute = new ReRouteBuilder().WithLoadBalancerKey("test").Build(); - var reRouteTwo = new ReRouteBuilder().WithLoadBalancerKey("testtwo").Build(); + var reRoute = new ReRouteBuilder().WithReRouteKey("test").Build(); + var reRouteTwo = new ReRouteBuilder().WithReRouteKey("testtwo").Build(); this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer())) .And(x => x.GivenThereIsALoadBalancer(reRouteTwo, new FakeRoundRobinLoadBalancer())) @@ -78,22 +78,22 @@ namespace Ocelot.UnitTests.LoadBalancer [Fact] public void should_get_new_load_balancer_if_reroute_load_balancer_has_changed() { - var reRoute = new ReRouteBuilder().WithLoadBalancerKey("test").Build(); + var reRoute = new ReRouteBuilder().WithLoadBalancer("FakeLoadBalancer").WithReRouteKey("test").Build(); - var reRouteTwo = new ReRouteBuilder().WithLoadBalancer("LeastConnection").WithLoadBalancerKey("test").Build(); + var reRouteTwo = new ReRouteBuilder().WithLoadBalancer("LeastConnection").WithReRouteKey("test").Build(); this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer())) .When(x => x.WhenWeGetTheLoadBalancer(reRoute)) .Then(x => x.ThenTheLoadBalancerIs()) .When(x => x.WhenIGetTheReRouteWithTheSameKeyButDifferentLoadBalancer(reRouteTwo)) - .Then(x => x.ThenTheLoadBalancerIs()) + .Then(x => x.ThenTheLoadBalancerIs()) .BDDfy(); } private void WhenIGetTheReRouteWithTheSameKeyButDifferentLoadBalancer(ReRoute reRoute) { _reRoute = reRoute; - _factory.Setup(x => x.Get(_reRoute, _serviceProviderConfig)).ReturnsAsync(new LeastConnectionLoadBalancer(null, null)); + _factory.Setup(x => x.Get(_reRoute, _serviceProviderConfig)).ReturnsAsync(new LeastConnection(null, null)); _getResult = _loadBalancerHouse.Get(_reRoute, _serviceProviderConfig).Result; } diff --git a/test/Ocelot.UnitTests/LoadBalancer/RoundRobinTests.cs b/test/Ocelot.UnitTests/LoadBalancer/RoundRobinTests.cs index 0820b8be..458df669 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/RoundRobinTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/RoundRobinTests.cs @@ -12,7 +12,7 @@ namespace Ocelot.UnitTests.LoadBalancer { public class RoundRobinTests { - private readonly RoundRobinLoadBalancer _roundRobin; + private readonly RoundRobin _roundRobin; private readonly List _services; private Response _hostAndPort; @@ -25,7 +25,7 @@ namespace Ocelot.UnitTests.LoadBalancer new Service("product", new HostAndPort("127.0.0.1", 5001), string.Empty, string.Empty, new string[0]) }; - _roundRobin = new RoundRobinLoadBalancer(() => Task.FromResult(_services)); + _roundRobin = new RoundRobin(() => Task.FromResult(_services)); } [Fact] diff --git a/test/Ocelot.UnitTests/Request/HttpRequestBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/Request/HttpRequestBuilderMiddlewareTests.cs index 807c35a5..4c72d137 100644 --- a/test/Ocelot.UnitTests/Request/HttpRequestBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Request/HttpRequestBuilderMiddlewareTests.cs @@ -1,122 +1,122 @@ -namespace Ocelot.UnitTests.Request -{ - using System.Collections.Generic; - using System.Net.Http; - using Microsoft.Extensions.DependencyInjection; - using Moq; - using Ocelot.Configuration.Builder; - using Ocelot.DownstreamRouteFinder; - using Ocelot.DownstreamRouteFinder.UrlMatcher; - using Ocelot.Infrastructure.RequestData; - using Ocelot.Logging; - using Ocelot.Request.Builder; - using Ocelot.Request.Middleware; - using Ocelot.Responses; - using TestStack.BDDfy; - using Xunit; - using Ocelot.Requester.QoS; - using Ocelot.Configuration; +namespace Ocelot.UnitTests.Request +{ + using System.Collections.Generic; + using System.Net.Http; + using Microsoft.Extensions.DependencyInjection; + using Moq; + using Ocelot.Configuration.Builder; + using Ocelot.DownstreamRouteFinder; + using Ocelot.DownstreamRouteFinder.UrlMatcher; + using Ocelot.Infrastructure.RequestData; + using Ocelot.Logging; + using Ocelot.Request.Builder; + using Ocelot.Request.Middleware; + using Ocelot.Responses; + using TestStack.BDDfy; + using Xunit; + using Ocelot.Requester.QoS; + using Ocelot.Configuration; using Microsoft.AspNetCore.Builder; - public class HttpRequestBuilderMiddlewareTests : ServerHostedMiddlewareTest - { - private readonly Mock _requestBuilder; - private readonly Mock _scopedRepository; - private readonly Mock _qosProviderHouse; - private readonly HttpRequestMessage _downstreamRequest; - private OkResponse _request; - private OkResponse _downstreamUrl; - private OkResponse _downstreamRoute; - - public HttpRequestBuilderMiddlewareTests() - { - _qosProviderHouse = new Mock(); - _requestBuilder = new Mock(); - _scopedRepository = new Mock(); - - _downstreamRequest = new HttpRequestMessage(); - - _scopedRepository - .Setup(sr => sr.Get("DownstreamRequest")) - .Returns(new OkResponse(_downstreamRequest)); - - GivenTheTestServerIsConfigured(); - } - - [Fact] - public void should_call_scoped_data_repository_correctly() - { - - var downstreamRoute = new DownstreamRoute(new List(), - new ReRouteBuilder() - .WithRequestIdKey("LSRequestId") - .WithUpstreamHttpMethod(new List { "Get" }) - .WithHttpHandlerOptions(new HttpHandlerOptions(true, true)) - .Build()); - - this.Given(x => x.GivenTheDownStreamUrlIs("any old string")) - .And(x => x.GivenTheQosProviderHouseReturns(new OkResponse(new NoQoSProvider()))) - .And(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) - .And(x => x.GivenTheRequestBuilderReturns(new Ocelot.Request.Request(new HttpRequestMessage(), true, new NoQoSProvider(), false, false))) - .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) - .BDDfy(); - } - - protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services) - { - services.AddSingleton(); - services.AddLogging(); - services.AddSingleton(_qosProviderHouse.Object); - services.AddSingleton(_requestBuilder.Object); - services.AddSingleton(_scopedRepository.Object); - } - - protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) - { - app.UseHttpRequestBuilderMiddleware(); - } - - private void GivenTheDownStreamUrlIs(string downstreamUrl) - { - _downstreamUrl = new OkResponse(downstreamUrl); - _scopedRepository - .Setup(x => x.Get(It.IsAny())) - .Returns(_downstreamUrl); - } - - private void GivenTheQosProviderHouseReturns(Response qosProvider) - { - _qosProviderHouse - .Setup(x => x.Get(It.IsAny())) - .Returns(qosProvider); - } - - private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) - { - _downstreamRoute = new OkResponse(downstreamRoute); - _scopedRepository - .Setup(x => x.Get(It.IsAny())) - .Returns(_downstreamRoute); - } - - private void GivenTheRequestBuilderReturns(Ocelot.Request.Request request) - { - _request = new OkResponse(request); - - _requestBuilder - .Setup(x => x.Build(It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny())) - .ReturnsAsync(_request); - } - - private void ThenTheScopedDataRepositoryIsCalledCorrectly() - { - _scopedRepository - .Verify(x => x.Add("Request", _request.Data), Times.Once()); - } - } -} + public class HttpRequestBuilderMiddlewareTests : ServerHostedMiddlewareTest + { + private readonly Mock _requestBuilder; + private readonly Mock _scopedRepository; + private readonly Mock _qosProviderHouse; + private readonly HttpRequestMessage _downstreamRequest; + private OkResponse _request; + private OkResponse _downstreamUrl; + private OkResponse _downstreamRoute; + + public HttpRequestBuilderMiddlewareTests() + { + _qosProviderHouse = new Mock(); + _requestBuilder = new Mock(); + _scopedRepository = new Mock(); + + _downstreamRequest = new HttpRequestMessage(); + + _scopedRepository + .Setup(sr => sr.Get("DownstreamRequest")) + .Returns(new OkResponse(_downstreamRequest)); + + GivenTheTestServerIsConfigured(); + } + + [Fact] + public void should_call_scoped_data_repository_correctly() + { + + var downstreamRoute = new DownstreamRoute(new List(), + new ReRouteBuilder() + .WithRequestIdKey("LSRequestId") + .WithUpstreamHttpMethod(new List { "Get" }) + .WithHttpHandlerOptions(new HttpHandlerOptions(true, true)) + .Build()); + + this.Given(x => x.GivenTheDownStreamUrlIs("any old string")) + .And(x => x.GivenTheQosProviderHouseReturns(new OkResponse(new NoQoSProvider()))) + .And(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) + .And(x => x.GivenTheRequestBuilderReturns(new Ocelot.Request.Request(new HttpRequestMessage(), true, new NoQoSProvider(), false, false))) + .When(x => x.WhenICallTheMiddleware()) + .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) + .BDDfy(); + } + + protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services) + { + services.AddSingleton(); + services.AddLogging(); + services.AddSingleton(_qosProviderHouse.Object); + services.AddSingleton(_requestBuilder.Object); + services.AddSingleton(_scopedRepository.Object); + } + + protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) + { + app.UseHttpRequestBuilderMiddleware(); + } + + private void GivenTheDownStreamUrlIs(string downstreamUrl) + { + _downstreamUrl = new OkResponse(downstreamUrl); + _scopedRepository + .Setup(x => x.Get(It.IsAny())) + .Returns(_downstreamUrl); + } + + private void GivenTheQosProviderHouseReturns(Response qosProvider) + { + _qosProviderHouse + .Setup(x => x.Get(It.IsAny())) + .Returns(qosProvider); + } + + private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) + { + _downstreamRoute = new OkResponse(downstreamRoute); + _scopedRepository + .Setup(x => x.Get(It.IsAny())) + .Returns(_downstreamRoute); + } + + private void GivenTheRequestBuilderReturns(Ocelot.Request.Request request) + { + _request = new OkResponse(request); + + _requestBuilder + .Setup(x => x.Build(It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())) + .ReturnsAsync(_request); + } + + private void ThenTheScopedDataRepositoryIsCalledCorrectly() + { + _scopedRepository + .Verify(x => x.Add("Request", _request.Data), Times.Once()); + } + } +} diff --git a/test/Ocelot.UnitTests/Requester/QosProviderHouseTests.cs b/test/Ocelot.UnitTests/Requester/QosProviderHouseTests.cs index 1e76a027..4756ae8f 100644 --- a/test/Ocelot.UnitTests/Requester/QosProviderHouseTests.cs +++ b/test/Ocelot.UnitTests/Requester/QosProviderHouseTests.cs @@ -1,5 +1,10 @@ -using Ocelot.Requester.QoS; +using Moq; +using Ocelot.Configuration; +using Ocelot.Configuration.Builder; +using Ocelot.LoadBalancer.LoadBalancers; +using Ocelot.Requester.QoS; using Ocelot.Responses; +using Ocelot.UnitTests.LoadBalancer; using Shouldly; using TestStack.BDDfy; using Xunit; @@ -12,31 +17,32 @@ namespace Ocelot.UnitTests.Requester private readonly QosProviderHouse _qosProviderHouse; private Response _addResult; private Response _getResult; - private string _key; + private ReRoute _reRoute; + private readonly Mock _factory; public QosProviderHouseTests() { - _qosProviderHouse = new QosProviderHouse(); + _factory = new Mock(); + _qosProviderHouse = new QosProviderHouse(_factory.Object); } [Fact] - public void should_store_qos_provider() + public void should_store_qos_provider_on_first_request() { - var key = "test"; + var reRoute = new ReRouteBuilder().WithReRouteKey("test").Build(); - this.Given(x => x.GivenThereIsAQoSProvider(key, new FakeQoSProvider())) - .When(x => x.WhenIAddTheQoSProvider()) + this.Given(x => x.GivenThereIsAQoSProvider(reRoute, new FakeQoSProvider())) .Then(x => x.ThenItIsAdded()) .BDDfy(); } [Fact] - public void should_get_qos_provider() + public void should_not_store_qos_provider_on_first_request() { - var key = "test"; + var reRoute = new ReRouteBuilder().WithReRouteKey("test").Build(); - this.Given(x => x.GivenThereIsAQoSProvider(key, new FakeQoSProvider())) - .When(x => x.WhenWeGetTheQoSProvider(key)) + this.Given(x => x.GivenThereIsAQoSProvider(reRoute, new FakeQoSProvider())) + .When(x => x.WhenWeGetTheQoSProvider(reRoute)) .Then(x => x.ThenItIsReturned()) .BDDfy(); } @@ -44,14 +50,14 @@ namespace Ocelot.UnitTests.Requester [Fact] public void should_store_qos_providers_by_key() { - var key = "test"; - var keyTwo = "testTwo"; + var reRoute = new ReRouteBuilder().WithReRouteKey("test").Build(); + var reRouteTwo = new ReRouteBuilder().WithReRouteKey("testTwo").Build(); - this.Given(x => x.GivenThereIsAQoSProvider(key, new FakeQoSProvider())) - .And(x => x.GivenThereIsAQoSProvider(keyTwo, new FakePollyQoSProvider())) - .When(x => x.WhenWeGetTheQoSProvider(key)) + this.Given(x => x.GivenThereIsAQoSProvider(reRoute, new FakeQoSProvider())) + .And(x => x.GivenThereIsAQoSProvider(reRouteTwo, new FakePollyQoSProvider())) + .When(x => x.WhenWeGetTheQoSProvider(reRoute)) .Then(x => x.ThenTheQoSProviderIs()) - .When(x => x.WhenWeGetTheQoSProvider(keyTwo)) + .When(x => x.WhenWeGetTheQoSProvider(reRouteTwo)) .Then(x => x.ThenTheQoSProviderIs()) .BDDfy(); } @@ -59,11 +65,35 @@ namespace Ocelot.UnitTests.Requester [Fact] public void should_return_error_if_no_qos_provider_with_key() { - this.When(x => x.WhenWeGetTheQoSProvider("test")) + var reRoute = new ReRouteBuilder().Build(); + + this.When(x => x.WhenWeGetTheQoSProvider(reRoute)) .Then(x => x.ThenAnErrorIsReturned()) .BDDfy(); } + [Fact] + public void should_get_new_qos_provider_if_reroute_qos_provider_has_changed() + { + var reRoute = new ReRouteBuilder().WithReRouteKey("test").Build(); + + var reRouteTwo = new ReRouteBuilder().WithReRouteKey("test").WithIsQos(true).Build(); + + this.Given(x => x.GivenThereIsAQoSProvider(reRoute, new FakeQoSProvider())) + .When(x => x.WhenWeGetTheQoSProvider(reRoute)) + .Then(x => x.ThenTheQoSProviderIs()) + .When(x => x.WhenIGetTheReRouteWithTheSameKeyButDifferentQosProvider(reRouteTwo)) + .Then(x => x.ThenTheQoSProviderIs()) + .BDDfy(); + } + + private void WhenIGetTheReRouteWithTheSameKeyButDifferentQosProvider(ReRoute reRoute) + { + _reRoute = reRoute; + _factory.Setup(x => x.Get(_reRoute)).Returns(new FakePollyQoSProvider()); + _getResult = _qosProviderHouse.Get(_reRoute); + } + private void ThenAnErrorIsReturned() { _getResult.IsError.ShouldBeTrue(); @@ -77,31 +107,30 @@ namespace Ocelot.UnitTests.Requester private void ThenItIsAdded() { - _addResult.IsError.ShouldBe(false); - _addResult.ShouldBeOfType(); - } - - private void WhenIAddTheQoSProvider() - { - _addResult = _qosProviderHouse.Add(_key, _qoSProvider); + _getResult.IsError.ShouldBe(false); + _getResult.ShouldBeOfType>(); + _factory.Verify(x => x.Get(_reRoute), Times.Once); + _getResult.Data.ShouldBe(_qoSProvider); } - private void GivenThereIsAQoSProvider(string key, IQoSProvider qoSProvider) + private void GivenThereIsAQoSProvider(ReRoute reRoute, IQoSProvider qoSProvider) { - _key = key; + _reRoute = reRoute; _qoSProvider = qoSProvider; - WhenIAddTheQoSProvider(); + _factory.Setup(x => x.Get(_reRoute)).Returns(_qoSProvider); + _getResult = _qosProviderHouse.Get(reRoute); } - private void WhenWeGetTheQoSProvider(string key) + private void WhenWeGetTheQoSProvider(ReRoute reRoute) { - _getResult = _qosProviderHouse.Get(key); + _getResult = _qosProviderHouse.Get(reRoute); } private void ThenItIsReturned() { _getResult.Data.ShouldBe(_qoSProvider); + _factory.Verify(x => x.Get(_reRoute), Times.Once); } class FakeQoSProvider : IQoSProvider diff --git a/test/Ocelot.UnitTests/ServiceDiscovery/ServiceProviderFactoryTests.cs b/test/Ocelot.UnitTests/ServiceDiscovery/ServiceProviderFactoryTests.cs index 71ed1430..f1db9f80 100644 --- a/test/Ocelot.UnitTests/ServiceDiscovery/ServiceProviderFactoryTests.cs +++ b/test/Ocelot.UnitTests/ServiceDiscovery/ServiceProviderFactoryTests.cs @@ -42,7 +42,6 @@ namespace Ocelot.UnitTests.ServiceDiscovery .Build(); var serviceConfig = new ServiceProviderConfigurationBuilder() - .WithServiceDiscoveryProvider("Consul") .Build(); this.Given(x => x.GivenTheReRoute(serviceConfig, reRoute)) From 88e51971c5fda0afebe7bc5d5e13de047b5174cf Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Fri, 10 Nov 2017 18:07:08 +0000 Subject: [PATCH 10/11] only get config once in a request...could make this its own middleware one day? --- .../Finder/DownstreamRouteFinder.cs | 11 ++++----- .../Finder/IDownstreamRouteFinder.cs | 3 ++- .../DownstreamRouteFinderMiddleware.cs | 19 +++++++++++++-- .../Middleware/LoadBalancingMiddleware.cs | 9 ++----- src/Ocelot/Middleware/OcelotMiddleware.cs | 8 +++++++ .../DownstreamRouteFinderMiddlewareTests.cs | 24 +++++++++++++++++-- .../DownstreamRouteFinderTests.cs | 11 ++++----- .../LoadBalancerMiddlewareTests.cs | 7 ++---- 8 files changed, 61 insertions(+), 31 deletions(-) diff --git a/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs b/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs index d6509b23..e39fffc6 100644 --- a/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs +++ b/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Ocelot.Configuration; using Ocelot.Configuration.Provider; using Ocelot.DownstreamRouteFinder.UrlMatcher; using Ocelot.Errors; @@ -12,24 +13,20 @@ namespace Ocelot.DownstreamRouteFinder.Finder { public class DownstreamRouteFinder : IDownstreamRouteFinder { - private readonly IOcelotConfigurationProvider _configProvider; private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; private readonly IUrlPathPlaceholderNameAndValueFinder _urlPathPlaceholderNameAndValueFinder; - public DownstreamRouteFinder(IOcelotConfigurationProvider configProvider, IUrlPathToUrlTemplateMatcher urlMatcher, IUrlPathPlaceholderNameAndValueFinder urlPathPlaceholderNameAndValueFinder) + public DownstreamRouteFinder(IUrlPathToUrlTemplateMatcher urlMatcher, IUrlPathPlaceholderNameAndValueFinder urlPathPlaceholderNameAndValueFinder) { - _configProvider = configProvider; _urlMatcher = urlMatcher; _urlPathPlaceholderNameAndValueFinder = urlPathPlaceholderNameAndValueFinder; } - public async Task> FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod) + public Response FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod, IOcelotConfiguration configuration) { upstreamUrlPath = upstreamUrlPath.SetLastCharacterAs('/'); - var configuration = await _configProvider.Get(); - - var applicableReRoutes = configuration.Data.ReRoutes.Where(r => r.UpstreamHttpMethod.Count == 0 || r.UpstreamHttpMethod.Select(x => x.Method.ToLower()).Contains(upstreamHttpMethod.ToLower())); + var applicableReRoutes = configuration.ReRoutes.Where(r => r.UpstreamHttpMethod.Count == 0 || r.UpstreamHttpMethod.Select(x => x.Method.ToLower()).Contains(upstreamHttpMethod.ToLower())); foreach (var reRoute in applicableReRoutes) { diff --git a/src/Ocelot/DownstreamRouteFinder/Finder/IDownstreamRouteFinder.cs b/src/Ocelot/DownstreamRouteFinder/Finder/IDownstreamRouteFinder.cs index 7ae3ff79..eda3acac 100644 --- a/src/Ocelot/DownstreamRouteFinder/Finder/IDownstreamRouteFinder.cs +++ b/src/Ocelot/DownstreamRouteFinder/Finder/IDownstreamRouteFinder.cs @@ -1,10 +1,11 @@ using System.Threading.Tasks; +using Ocelot.Configuration; using Ocelot.Responses; namespace Ocelot.DownstreamRouteFinder.Finder { public interface IDownstreamRouteFinder { - Task> FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod); + Response FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod, IOcelotConfiguration configuration); } } diff --git a/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs b/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs index f421d6d8..b5351e2a 100644 --- a/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs +++ b/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; +using Ocelot.Configuration.Provider; using Ocelot.DownstreamRouteFinder.Finder; using Ocelot.Infrastructure.Extensions; using Ocelot.Infrastructure.RequestData; @@ -16,13 +17,17 @@ namespace Ocelot.DownstreamRouteFinder.Middleware private readonly RequestDelegate _next; private readonly IDownstreamRouteFinder _downstreamRouteFinder; private readonly IOcelotLogger _logger; + private readonly IOcelotConfigurationProvider _configProvider; + public DownstreamRouteFinderMiddleware(RequestDelegate next, IOcelotLoggerFactory loggerFactory, IDownstreamRouteFinder downstreamRouteFinder, - IRequestScopedDataRepository requestScopedDataRepository) + IRequestScopedDataRepository requestScopedDataRepository, + IOcelotConfigurationProvider configProvider) :base(requestScopedDataRepository) { + _configProvider = configProvider; _next = next; _downstreamRouteFinder = downstreamRouteFinder; _logger = loggerFactory.CreateLogger(); @@ -32,9 +37,19 @@ namespace Ocelot.DownstreamRouteFinder.Middleware { var upstreamUrlPath = context.Request.Path.ToString(); + //todo make this getting config its own middleware one day? + var configuration = await _configProvider.Get(); + if(configuration.IsError) + { + _logger.LogError($"{MiddlewareName} setting pipeline errors. IOcelotConfigurationProvider returned {configuration.Errors.ToErrorString()}"); + SetPipelineError(configuration.Errors); + } + + SetServiceProviderConfigurationForThisRequest(configuration.Data.ServiceProviderConfiguration); + _logger.LogDebug("upstream url path is {upstreamUrlPath}", upstreamUrlPath); - var downstreamRoute = await _downstreamRouteFinder.FindDownstreamRoute(upstreamUrlPath, context.Request.Method); + var downstreamRoute = _downstreamRouteFinder.FindDownstreamRoute(upstreamUrlPath, context.Request.Method, configuration.Data); if (downstreamRoute.IsError) { diff --git a/src/Ocelot/LoadBalancer/Middleware/LoadBalancingMiddleware.cs b/src/Ocelot/LoadBalancer/Middleware/LoadBalancingMiddleware.cs index 079f3584..dc3b1a8f 100644 --- a/src/Ocelot/LoadBalancer/Middleware/LoadBalancingMiddleware.cs +++ b/src/Ocelot/LoadBalancer/Middleware/LoadBalancingMiddleware.cs @@ -12,7 +12,6 @@ namespace Ocelot.LoadBalancer.Middleware { public class LoadBalancingMiddleware : OcelotMiddleware { - private readonly IOcelotConfigurationProvider _configProvider; private readonly RequestDelegate _next; private readonly IOcelotLogger _logger; private readonly ILoadBalancerHouse _loadBalancerHouse; @@ -20,11 +19,9 @@ namespace Ocelot.LoadBalancer.Middleware public LoadBalancingMiddleware(RequestDelegate next, IOcelotLoggerFactory loggerFactory, IRequestScopedDataRepository requestScopedDataRepository, - ILoadBalancerHouse loadBalancerHouse, - IOcelotConfigurationProvider configProvider) + ILoadBalancerHouse loadBalancerHouse) : base(requestScopedDataRepository) { - _configProvider = configProvider; _next = next; _logger = loggerFactory.CreateLogger(); _loadBalancerHouse = loadBalancerHouse; @@ -32,9 +29,7 @@ namespace Ocelot.LoadBalancer.Middleware public async Task Invoke(HttpContext context) { - var configuration = await _configProvider.Get(); - - var loadBalancer = await _loadBalancerHouse.Get(DownstreamRoute.ReRoute, configuration.Data.ServiceProviderConfiguration); + var loadBalancer = await _loadBalancerHouse.Get(DownstreamRoute.ReRoute, ServiceProviderConfiguration); if(loadBalancer.IsError) { _logger.LogDebug("there was an error retriving the loadbalancer, setting pipeline error"); diff --git a/src/Ocelot/Middleware/OcelotMiddleware.cs b/src/Ocelot/Middleware/OcelotMiddleware.cs index 0060cbb3..50d5baa5 100644 --- a/src/Ocelot/Middleware/OcelotMiddleware.cs +++ b/src/Ocelot/Middleware/OcelotMiddleware.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Net.Http; +using Ocelot.Configuration; using Ocelot.DownstreamRouteFinder; using Ocelot.Errors; using Ocelot.Infrastructure.RequestData; @@ -30,11 +31,18 @@ namespace Ocelot.Middleware public HttpResponseMessage HttpResponseMessage => _requestScopedDataRepository.Get("HttpResponseMessage").Data; + public ServiceProviderConfiguration ServiceProviderConfiguration => _requestScopedDataRepository.Get("ServiceProviderConfiguration").Data; + public void SetDownstreamRouteForThisRequest(DownstreamRoute downstreamRoute) { _requestScopedDataRepository.Add("DownstreamRoute", downstreamRoute); } + public void SetServiceProviderConfigurationForThisRequest(ServiceProviderConfiguration serviceProviderConfiguration) + { + _requestScopedDataRepository.Add("ServiceProviderConfiguration", serviceProviderConfiguration); + } + public void SetUpstreamRequestForThisRequest(Request.Request request) { _requestScopedDataRepository.Add("Request", request); diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs index fb312e21..9b241fbe 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs @@ -4,7 +4,9 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Moq; + using Ocelot.Configuration; using Ocelot.Configuration.Builder; + using Ocelot.Configuration.Provider; using Ocelot.DownstreamRouteFinder; using Ocelot.DownstreamRouteFinder.Finder; using Ocelot.DownstreamRouteFinder.Middleware; @@ -17,10 +19,13 @@ public class DownstreamRouteFinderMiddlewareTests : ServerHostedMiddlewareTest { private readonly Mock _downstreamRouteFinder; + private readonly Mock _provider; private Response _downstreamRoute; + private IOcelotConfiguration _config; public DownstreamRouteFinderMiddlewareTests() { + _provider = new Mock(); _downstreamRouteFinder = new Mock(); GivenTheTestServerIsConfigured(); @@ -29,6 +34,8 @@ [Fact] public void should_call_scoped_data_repository_correctly() { + var config = new OcelotConfiguration(null, null, new ServiceProviderConfigurationBuilder().Build()); + this.Given(x => x.GivenTheDownStreamRouteFinderReturns( new DownstreamRoute( new List(), @@ -36,16 +43,26 @@ .WithDownstreamPathTemplate("any old string") .WithUpstreamHttpMethod(new List { "Get" }) .Build()))) + .And(x => GivenTheFollowingConfig(config)) .When(x => x.WhenICallTheMiddleware()) .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) .BDDfy(); } + private void GivenTheFollowingConfig(IOcelotConfiguration config) + { + _config = config; + _provider + .Setup(x => x.Get()) + .ReturnsAsync(new OkResponse(_config)); + } + protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services) { services.AddSingleton(); services.AddLogging(); services.AddSingleton(_downstreamRouteFinder.Object); + services.AddSingleton(_provider.Object); services.AddSingleton(ScopedRepository.Object); } @@ -58,14 +75,17 @@ { _downstreamRoute = new OkResponse(downstreamRoute); _downstreamRouteFinder - .Setup(x => x.FindDownstreamRoute(It.IsAny(), It.IsAny())) - .ReturnsAsync(_downstreamRoute); + .Setup(x => x.FindDownstreamRoute(It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(_downstreamRoute); } private void ThenTheScopedDataRepositoryIsCalledCorrectly() { ScopedRepository .Verify(x => x.Add("DownstreamRoute", _downstreamRoute.Data), Times.Once()); + + ScopedRepository + .Verify(x => x.Add("ServiceProviderConfiguration", _config.ServiceProviderConfiguration), Times.Once()); } } } diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs index 2ae88eb3..2e586c23 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs @@ -16,21 +16,20 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder public class DownstreamRouteFinderTests { private readonly IDownstreamRouteFinder _downstreamRouteFinder; - private readonly Mock _mockConfig; private readonly Mock _mockMatcher; private readonly Mock _finder; private string _upstreamUrlPath; private Response _result; private List _reRoutesConfig; + private OcelotConfiguration _config; private Response _match; private string _upstreamHttpMethod; public DownstreamRouteFinderTests() { - _mockConfig = new Mock(); _mockMatcher = new Mock(); _finder = new Mock(); - _downstreamRouteFinder = new Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteFinder(_mockConfig.Object, _mockMatcher.Object, _finder.Object); + _downstreamRouteFinder = new Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteFinder(_mockMatcher.Object, _finder.Object); } [Fact] @@ -341,9 +340,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder private void GivenTheConfigurationIs(List reRoutesConfig, string adminPath, ServiceProviderConfiguration serviceProviderConfig) { _reRoutesConfig = reRoutesConfig; - _mockConfig - .Setup(x => x.Get()) - .ReturnsAsync(new OkResponse(new OcelotConfiguration(_reRoutesConfig, adminPath, serviceProviderConfig))); + _config = new OcelotConfiguration(_reRoutesConfig, adminPath, serviceProviderConfig); } private void GivenThereIsAnUpstreamUrlPath(string upstreamUrlPath) @@ -353,7 +350,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder private void WhenICallTheFinder() { - _result = _downstreamRouteFinder.FindDownstreamRoute(_upstreamUrlPath, _upstreamHttpMethod).Result; + _result = _downstreamRouteFinder.FindDownstreamRoute(_upstreamUrlPath, _upstreamHttpMethod, _config); } private void ThenTheFollowingIsReturned(DownstreamRoute expected) diff --git a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs index 987b75ea..002e64a0 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs @@ -23,7 +23,6 @@ namespace Ocelot.UnitTests.LoadBalancer { private readonly Mock _loadBalancerHouse; private readonly Mock _loadBalancer; - private readonly Mock _configProvider; private HostAndPort _hostAndPort; private OkResponse _downstreamRoute; private ErrorResponse _getLoadBalancerHouseError; @@ -33,7 +32,6 @@ namespace Ocelot.UnitTests.LoadBalancer public LoadBalancerMiddlewareTests() { - _configProvider = new Mock(); _loadBalancerHouse = new Mock(); _loadBalancer = new Mock(); _loadBalancerHouse = new Mock(); @@ -111,8 +109,8 @@ namespace Ocelot.UnitTests.LoadBalancer private void GivenTheConfigurationIs(ServiceProviderConfiguration config) { _config = config; - _configProvider - .Setup(x => x.Get()).ReturnsAsync(new OkResponse(new OcelotConfiguration(null, null, _config))); + ScopedRepository + .Setup(x => x.Get("ServiceProviderConfiguration")).Returns(new OkResponse(config)); } protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services) @@ -120,7 +118,6 @@ namespace Ocelot.UnitTests.LoadBalancer services.AddSingleton(); services.AddLogging(); services.AddSingleton(_loadBalancerHouse.Object); - services.AddSingleton(_configProvider.Object); services.AddSingleton(ScopedRepository.Object); } From 24c2ba10dec6794fbda78e7c4630541fe7d18334 Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Fri, 10 Nov 2017 18:11:50 +0000 Subject: [PATCH 11/11] found missing tests --- .../AuthenticationOptionsCreatorTests.cs | 179 ++++++------------ 1 file changed, 54 insertions(+), 125 deletions(-) diff --git a/test/Ocelot.UnitTests/Configuration/AuthenticationOptionsCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/AuthenticationOptionsCreatorTests.cs index a4fe8a16..d6c62df0 100644 --- a/test/Ocelot.UnitTests/Configuration/AuthenticationOptionsCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/AuthenticationOptionsCreatorTests.cs @@ -1,133 +1,62 @@ -// using System.Collections.Generic; -// using Ocelot.Configuration; -// using Ocelot.Configuration.Builder; -// using Ocelot.Configuration.Creator; -// using Ocelot.Configuration.File; -// using Shouldly; -// using TestStack.BDDfy; -// using Xunit; +using System.Collections.Generic; +using Ocelot.Configuration; +using Ocelot.Configuration.Builder; +using Ocelot.Configuration.Creator; +using Ocelot.Configuration.File; +using Shouldly; +using TestStack.BDDfy; +using Xunit; -// namespace Ocelot.UnitTests.Configuration -// { -// public class AuthenticationOptionsCreatorTests -// { -// private readonly AuthenticationOptionsCreator _authOptionsCreator; -// private FileReRoute _fileReRoute; -// private AuthenticationOptions _result; +namespace Ocelot.UnitTests.Configuration +{ + public class AuthenticationOptionsCreatorTests + { + private readonly AuthenticationOptionsCreator _authOptionsCreator; + private FileReRoute _fileReRoute; + private AuthenticationOptions _result; -// public AuthenticationOptionsCreatorTests() -// { -// _authOptionsCreator = new AuthenticationOptionsCreator(new AuthenticationProviderConfigCreator()); -// } + public AuthenticationOptionsCreatorTests() + { + _authOptionsCreator = new AuthenticationOptionsCreator(); + } -// [Fact] -// public void should_return_auth_options() -// { -// var fileReRoute = new FileReRoute() -// { -// AuthenticationOptions = new FileAuthenticationOptions -// { -// Provider = "Geoff", -// IdentityServerConfig = new FileIdentityServerConfig() -// { -// ProviderRootUrl = "http://www.bbc.co.uk/", -// ApiName = "Laura", -// RequireHttps = true, -// ApiSecret = "secret" -// }, -// AllowedScopes = new List { "cheese" }, - -// } -// }; + [Fact] + public void should_return_auth_options() + { + var fileReRoute = new FileReRoute() + { + AuthenticationOptions = new FileAuthenticationOptions + { + AuthenticationProviderKey = "Test", + AllowedScopes = new List { "cheese" }, + } + }; -// var authenticationConfig = new IdentityServerConfigBuilder() -// .WithProviderRootUrl(fileReRoute.AuthenticationOptions?.IdentityServerConfig?.ProviderRootUrl) -// .WithApiName(fileReRoute.AuthenticationOptions?.IdentityServerConfig?.ApiName) -// .WithRequireHttps(fileReRoute.AuthenticationOptions.IdentityServerConfig.RequireHttps) -// .WithApiSecret(fileReRoute.AuthenticationOptions?.IdentityServerConfig?.ApiSecret) -// .Build(); + var expected = new AuthenticationOptionsBuilder() + .WithAllowedScopes(fileReRoute.AuthenticationOptions?.AllowedScopes) + .WithAuthenticationProviderKey("Test") + .Build(); -// var expected = new AuthenticationOptionsBuilder() -// .WithProvider(fileReRoute.AuthenticationOptions?.Provider) -// .WithAllowedScopes(fileReRoute.AuthenticationOptions?.AllowedScopes) -// .WithConfig(authenticationConfig) -// .Build(); + this.Given(x => x.GivenTheFollowing(fileReRoute)) + .When(x => x.WhenICreateTheAuthenticationOptions()) + .Then(x => x.ThenTheFollowingConfigIsReturned(expected)) + .BDDfy(); + } -// this.Given(x => x.GivenTheFollowing(fileReRoute)) -// .When(x => x.WhenICreateTheAuthenticationOptions()) -// .Then(x => x.ThenTheFollowingIdentityServerConfigIsReturned(expected)) -// .BDDfy(); -// } + private void GivenTheFollowing(FileReRoute fileReRoute) + { + _fileReRoute = fileReRoute; + } -// [Fact] -// public void should_return_Jwt_auth_options() -// { -// var fileReRoute = new FileReRoute() -// { -// AuthenticationOptions = new FileAuthenticationOptions -// { -// Provider = "Jwt", -// JwtConfig = new FileJwtConfig() -// { -// Audience = "Audience", -// Authority = "Authority" -// }, -// AllowedScopes = new List { "cheese" } -// } -// }; + private void WhenICreateTheAuthenticationOptions() + { + _result = _authOptionsCreator.Create(_fileReRoute); + } -// var authenticationConfig = new JwtConfigBuilder() -// .WithAudience(fileReRoute.AuthenticationOptions?.JwtConfig?.Audience) -// .WithAuthority(fileReRoute.AuthenticationOptions?.JwtConfig?.Authority) -// .Build(); - -// var expected = new AuthenticationOptionsBuilder() -// .WithProvider(fileReRoute.AuthenticationOptions?.Provider) -// .WithAllowedScopes(fileReRoute.AuthenticationOptions?.AllowedScopes) -// .WithConfig(authenticationConfig) -// .Build(); - -// this.Given(x => x.GivenTheFollowing(fileReRoute)) -// .When(x => x.WhenICreateTheAuthenticationOptions()) -// .Then(x => x.ThenTheFollowingJwtConfigIsReturned(expected)) -// .BDDfy(); -// } - -// private void GivenTheFollowing(FileReRoute fileReRoute) -// { -// _fileReRoute = fileReRoute; -// } - -// private void WhenICreateTheAuthenticationOptions() -// { -// _result = _authOptionsCreator.Create(_fileReRoute); -// } - -// private void ThenTheFollowingJwtConfigIsReturned(AuthenticationOptions expected) -// { -// _result.AllowedScopes.ShouldBe(expected.AllowedScopes); -// _result.Provider.ShouldBe(expected.Provider); - -// var _resultSettings = _result.Config as JwtConfig; -// var expectedSettngs = expected.Config as JwtConfig; - -// _resultSettings.Audience.ShouldBe(expectedSettngs.Audience); -// _resultSettings.Authority.ShouldBe(expectedSettngs.Authority); - -// } - -// private void ThenTheFollowingIdentityServerConfigIsReturned(AuthenticationOptions expected) -// { -// _result.AllowedScopes.ShouldBe(expected.AllowedScopes); -// _result.Provider.ShouldBe(expected.Provider); - -// var _resultSettings = _result.Config as IdentityServerConfig; -// var expectedSettngs = expected.Config as IdentityServerConfig; - -// _resultSettings.ProviderRootUrl.ShouldBe(expectedSettngs.ProviderRootUrl); -// _resultSettings.RequireHttps.ShouldBe(expectedSettngs.RequireHttps); -// _resultSettings.ApiName.ShouldBe(expectedSettngs.ApiName); -// _resultSettings.ApiSecret.ShouldBe(expectedSettngs.ApiSecret); -// } -// } -// } \ No newline at end of file + private void ThenTheFollowingConfigIsReturned(AuthenticationOptions expected) + { + _result.AllowedScopes.ShouldBe(expected.AllowedScopes); + _result.AuthenticationProviderKey.ShouldBe(expected.AuthenticationProviderKey); + } + } +} \ No newline at end of file