mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 10:35:28 +08:00 
			
		
		
		
	@@ -4,9 +4,7 @@
 | 
			
		||||
 | 
			
		||||
[](https://coveralls.io/github/TomPallister/Ocelot?branch=develop)
 | 
			
		||||
 | 
			
		||||
Attempt at a .NET Api Gateway
 | 
			
		||||
 | 
			
		||||
This project is aimed at people using .NET running 
 | 
			
		||||
Ocelot is a .NET Api Gateway. This project is aimed at people using .NET running 
 | 
			
		||||
a micro services / service orientated architecture 
 | 
			
		||||
that need a unified point of entry into their system.
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "projects": [ "src", "test" ],
 | 
			
		||||
  "sdk": {
 | 
			
		||||
    "version": "2.0.0"
 | 
			
		||||
    "version": "2.0.2"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -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)
 | 
			
		||||
        {
 | 
			
		||||
@@ -148,18 +149,12 @@ namespace Ocelot.Configuration.Builder
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
       
 | 
			
		||||
        public ReRouteBuilder WithLoadBalancerKey(string loadBalancerKey)
 | 
			
		||||
        public ReRouteBuilder WithReRouteKey(string loadBalancerKey)
 | 
			
		||||
        {
 | 
			
		||||
            _loadBalancerKey = loadBalancerKey;
 | 
			
		||||
            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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,44 +2,9 @@ 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;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ServiceProviderConfigurationBuilder WithServiceDiscoveryProviderHost(string serviceDiscoveryProviderHost)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceDiscoveryProviderHost = serviceDiscoveryProviderHost;
 | 
			
		||||
@@ -52,11 +17,9 @@ namespace Ocelot.Configuration.Builder
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        public ServiceProviderConfiguration Build()
 | 
			
		||||
        {
 | 
			
		||||
            return new ServiceProviderConfiguration(_serviceName, _downstreamHost, _downstreamPort, _userServiceDiscovery,
 | 
			
		||||
            _serviceDiscoveryProvider, _serviceDiscoveryProviderHost,_serviceDiscoveryProviderPort);
 | 
			
		||||
            return new ServiceProviderConfiguration(_serviceDiscoveryProviderHost,_serviceDiscoveryProviderPort);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -9,11 +9,11 @@ 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;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Ocelot.Utilities;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Creator
 | 
			
		||||
{
 | 
			
		||||
@@ -25,10 +25,6 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
        private readonly IOptions<FileConfiguration> _options;
 | 
			
		||||
        private readonly IConfigurationValidator _configurationValidator;
 | 
			
		||||
        private readonly IOcelotLogger _logger;
 | 
			
		||||
        private readonly ILoadBalancerFactory _loadBalanceFactory;
 | 
			
		||||
        private readonly ILoadBalancerHouse _loadBalancerHouse;
 | 
			
		||||
        private readonly IQoSProviderFactory _qoSProviderFactory;
 | 
			
		||||
        private readonly IQosProviderHouse _qosProviderHouse;
 | 
			
		||||
        private readonly IClaimsToThingCreator _claimsToThingCreator;
 | 
			
		||||
        private readonly IAuthenticationOptionsCreator _authOptionsCreator;
 | 
			
		||||
        private readonly IUpstreamTemplatePatternCreator _upstreamTemplatePatternCreator;
 | 
			
		||||
@@ -44,10 +40,6 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
            IOptions<FileConfiguration> options, 
 | 
			
		||||
            IConfigurationValidator configurationValidator,
 | 
			
		||||
            IOcelotLoggerFactory loggerFactory,
 | 
			
		||||
            ILoadBalancerFactory loadBalancerFactory,
 | 
			
		||||
            ILoadBalancerHouse loadBalancerHouse, 
 | 
			
		||||
            IQoSProviderFactory qoSProviderFactory, 
 | 
			
		||||
            IQosProviderHouse qosProviderHouse,
 | 
			
		||||
            IClaimsToThingCreator claimsToThingCreator,
 | 
			
		||||
            IAuthenticationOptionsCreator authOptionsCreator,
 | 
			
		||||
            IUpstreamTemplatePatternCreator upstreamTemplatePatternCreator,
 | 
			
		||||
@@ -65,10 +57,6 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
            _requestIdKeyCreator = requestIdKeyCreator;
 | 
			
		||||
            _upstreamTemplatePatternCreator = upstreamTemplatePatternCreator;
 | 
			
		||||
            _authOptionsCreator = authOptionsCreator;
 | 
			
		||||
            _loadBalanceFactory = loadBalancerFactory;
 | 
			
		||||
            _loadBalancerHouse = loadBalancerHouse;
 | 
			
		||||
            _qoSProviderFactory = qoSProviderFactory;
 | 
			
		||||
            _qosProviderHouse = qosProviderHouse;
 | 
			
		||||
            _options = options;
 | 
			
		||||
            _configurationValidator = configurationValidator;
 | 
			
		||||
            _logger = loggerFactory.CreateLogger<FileOcelotConfigurationCreator>();
 | 
			
		||||
@@ -78,49 +66,38 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
            _fileReRouteOptionsCreator = fileReRouteOptionsCreator;
 | 
			
		||||
            _httpHandlerOptionsCreator = httpHandlerOptionsCreator;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<Response<IOcelotConfiguration>> Create()
 | 
			
		||||
        {     
 | 
			
		||||
            var config = await SetUpConfiguration(_options.Value);
 | 
			
		||||
 | 
			
		||||
            return new OkResponse<IOcelotConfiguration>(config);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        public async Task<Response<IOcelotConfiguration>> Create(FileConfiguration fileConfiguration)
 | 
			
		||||
        {     
 | 
			
		||||
            var config = await SetUpConfiguration(fileConfiguration);
 | 
			
		||||
 | 
			
		||||
            return new OkResponse<IOcelotConfiguration>(config);
 | 
			
		||||
            return config;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task<IOcelotConfiguration> SetUpConfiguration(FileConfiguration fileConfiguration)
 | 
			
		||||
        private async Task<Response<IOcelotConfiguration>> SetUpConfiguration(FileConfiguration fileConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            var response = await _configurationValidator.IsValid(fileConfiguration);
 | 
			
		||||
 | 
			
		||||
            if (response.Data.IsError)
 | 
			
		||||
            {
 | 
			
		||||
                var errorBuilder = new StringBuilder();
 | 
			
		||||
 | 
			
		||||
                foreach (var error in response.Errors)
 | 
			
		||||
                {
 | 
			
		||||
                    errorBuilder.AppendLine(error.Message);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                throw new Exception($"Unable to start Ocelot..configuration, errors were {errorBuilder}");
 | 
			
		||||
                return new ErrorResponse<IOcelotConfiguration>(response.Data.Errors);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var reRoutes = new List<ReRoute>();
 | 
			
		||||
 | 
			
		||||
            foreach (var reRoute in fileConfiguration.ReRoutes)
 | 
			
		||||
            {
 | 
			
		||||
                var ocelotReRoute = await SetUpReRoute(reRoute, fileConfiguration.GlobalConfiguration);
 | 
			
		||||
                var ocelotReRoute = SetUpReRoute(reRoute, fileConfiguration.GlobalConfiguration);
 | 
			
		||||
                reRoutes.Add(ocelotReRoute);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var serviceProviderConfiguration = _serviceProviderConfigCreator.Create(fileConfiguration.GlobalConfiguration);
 | 
			
		||||
            
 | 
			
		||||
            return new OcelotConfiguration(reRoutes, fileConfiguration.GlobalConfiguration.AdministrationPath);
 | 
			
		||||
            var config = new OcelotConfiguration(reRoutes, fileConfiguration.GlobalConfiguration.AdministrationPath, serviceProviderConfiguration);
 | 
			
		||||
 | 
			
		||||
            return new OkResponse<IOcelotConfiguration>(config);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task<ReRoute> SetUpReRoute(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration)
 | 
			
		||||
        private ReRoute SetUpReRoute(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            var fileReRouteOptions = _fileReRouteOptionsCreator.Create(fileReRoute);
 | 
			
		||||
 | 
			
		||||
@@ -130,8 +107,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);
 | 
			
		||||
@@ -167,17 +142,16 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
                .WithLoadBalancer(fileReRoute.LoadBalancer)
 | 
			
		||||
                .WithDownstreamHost(fileReRoute.DownstreamHost)
 | 
			
		||||
                .WithDownstreamPort(fileReRoute.DownstreamPort)
 | 
			
		||||
                .WithLoadBalancerKey(reRouteKey)
 | 
			
		||||
                .WithServiceProviderConfiguraion(serviceProviderConfiguration)
 | 
			
		||||
                .WithReRouteKey(reRouteKey)
 | 
			
		||||
                .WithIsQos(fileReRouteOptions.IsQos)
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting)
 | 
			
		||||
                .WithRateLimitOptions(rateLimitOption)
 | 
			
		||||
                .WithHttpHandlerOptions(httpHandlerOptions)
 | 
			
		||||
                .WithServiceName(fileReRoute.ServiceName)
 | 
			
		||||
                .WithUseServiceDiscovery(fileReRoute.UseServiceDiscovery)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            await SetupLoadBalancer(reRoute);
 | 
			
		||||
            SetupQosProvider(reRoute);
 | 
			
		||||
            return reRoute;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -187,17 +161,5 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
            var loadBalancerKey = $"{fileReRoute.UpstreamPathTemplate}|{string.Join(",", fileReRoute.UpstreamHttpMethod)}";
 | 
			
		||||
            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);
 | 
			
		||||
            _qosProviderHouse.Add(reRoute.ReRouteKey, loadBalancer);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -6,7 +6,6 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
{
 | 
			
		||||
    public interface IOcelotConfigurationCreator
 | 
			
		||||
    {
 | 
			
		||||
        Task<Response<IOcelotConfiguration>> Create();
 | 
			
		||||
        Task<Response<IOcelotConfiguration>> Create(FileConfiguration fileConfiguration);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -4,6 +4,6 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
{
 | 
			
		||||
    public interface IServiceProviderConfigurationCreator
 | 
			
		||||
    {
 | 
			
		||||
        ServiceProviderConfiguration Create(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration);
 | 
			
		||||
        ServiceProviderConfiguration Create(FileGlobalConfiguration globalConfiguration);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -5,19 +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)
 | 
			
		||||
                    .Build();
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,11 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using Ocelot.Utilities;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Creator
 | 
			
		||||
{
 | 
			
		||||
    public class UpstreamTemplatePatternCreator : IUpstreamTemplatePatternCreator
 | 
			
		||||
    {
 | 
			
		||||
        private const string RegExMatchEverything = ".*";
 | 
			
		||||
        private const string RegExMatchEverything = "[0-9a-zA-Z].*";
 | 
			
		||||
        private const string RegExMatchEndString = "$";
 | 
			
		||||
        private const string RegExIgnoreCase = "(?i)";
 | 
			
		||||
        private const string RegExForwardSlashOnly = "^/$";
 | 
			
		||||
@@ -15,8 +14,6 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
        {
 | 
			
		||||
            var upstreamTemplate = reRoute.UpstreamPathTemplate;
 | 
			
		||||
 | 
			
		||||
            upstreamTemplate = upstreamTemplate.SetLastCharacterAs('/');
 | 
			
		||||
 | 
			
		||||
            var placeholders = new List<string>();
 | 
			
		||||
 | 
			
		||||
            for (var i = 0; i < upstreamTemplate.Length; i++)
 | 
			
		||||
@@ -40,6 +37,11 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
                return RegExForwardSlashOnly;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if(upstreamTemplate.EndsWith("/"))
 | 
			
		||||
            {
 | 
			
		||||
                upstreamTemplate = upstreamTemplate.Remove(upstreamTemplate.Length -1, 1) + "(/|)";
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var route = reRoute.ReRouteIsCaseSensitive 
 | 
			
		||||
                ? $"^{upstreamTemplate}{RegExMatchEndString}" 
 | 
			
		||||
                : $"^{RegExIgnoreCase}{upstreamTemplate}{RegExMatchEndString}";
 | 
			
		||||
 
 | 
			
		||||
@@ -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;}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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; }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -6,5 +6,6 @@ namespace Ocelot.Configuration
 | 
			
		||||
    {
 | 
			
		||||
        List<ReRoute> ReRoutes { get; }
 | 
			
		||||
        string AdministrationPath {get;}
 | 
			
		||||
        ServiceProviderConfiguration ServiceProviderConfiguration {get;}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -4,13 +4,15 @@ namespace Ocelot.Configuration
 | 
			
		||||
{
 | 
			
		||||
    public class OcelotConfiguration : IOcelotConfiguration
 | 
			
		||||
    {
 | 
			
		||||
        public OcelotConfiguration(List<ReRoute> reRoutes, string administrationPath)
 | 
			
		||||
        public OcelotConfiguration(List<ReRoute> reRoutes, string administrationPath, ServiceProviderConfiguration serviceProviderConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            ReRoutes = reRoutes;
 | 
			
		||||
            AdministrationPath = administrationPath;
 | 
			
		||||
            ServiceProviderConfiguration = serviceProviderConfiguration;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public List<ReRoute> ReRoutes { get; }
 | 
			
		||||
        public string AdministrationPath {get;}
 | 
			
		||||
        public ServiceProviderConfiguration ServiceProviderConfiguration {get;}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Newtonsoft.Json;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using Ocelot.Configuration.Repository;
 | 
			
		||||
@@ -16,9 +17,9 @@ namespace Ocelot.Configuration.Provider
 | 
			
		||||
            _repo = repo;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public Response<FileConfiguration> Get()
 | 
			
		||||
        public async Task<Response<FileConfiguration>> Get()
 | 
			
		||||
        {
 | 
			
		||||
            var fileConfig = _repo.Get();
 | 
			
		||||
            var fileConfig = await _repo.Get();
 | 
			
		||||
            return new OkResponse<FileConfiguration>(fileConfig.Data);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
 | 
			
		||||
@@ -5,6 +6,6 @@ namespace Ocelot.Configuration.Provider
 | 
			
		||||
{
 | 
			
		||||
    public interface IFileConfigurationProvider
 | 
			
		||||
    {
 | 
			
		||||
        Response<FileConfiguration> Get();
 | 
			
		||||
        Task<Response<FileConfiguration>> Get();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Provider
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using Ocelot.Configuration.Repository;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
 | 
			
		||||
@@ -9,16 +10,16 @@ namespace Ocelot.Configuration.Provider
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public class OcelotConfigurationProvider : IOcelotConfigurationProvider
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IOcelotConfigurationRepository _repo;
 | 
			
		||||
        private readonly IOcelotConfigurationRepository _config;
 | 
			
		||||
 | 
			
		||||
        public OcelotConfigurationProvider(IOcelotConfigurationRepository repo)
 | 
			
		||||
        {
 | 
			
		||||
            _repo = repo;
 | 
			
		||||
            _config = repo;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<Response<IOcelotConfiguration>> Get()
 | 
			
		||||
        {
 | 
			
		||||
            var repoConfig = await _repo.Get();
 | 
			
		||||
            var repoConfig = await _config.Get();
 | 
			
		||||
 | 
			
		||||
            if (repoConfig.IsError)
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -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;}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,80 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Newtonsoft.Json;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using Ocelot.Configuration.Setter;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Repository
 | 
			
		||||
{
 | 
			
		||||
    public class ConsulFileConfigurationPoller : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private IOcelotLogger _logger; 
 | 
			
		||||
        private IFileConfigurationRepository _repo;
 | 
			
		||||
        private IFileConfigurationSetter _setter;
 | 
			
		||||
        private string _previousAsJson;
 | 
			
		||||
        private Timer _timer;
 | 
			
		||||
        private bool _polling;
 | 
			
		||||
 | 
			
		||||
        public ConsulFileConfigurationPoller(IOcelotLoggerFactory factory, IFileConfigurationRepository repo, IFileConfigurationSetter setter)
 | 
			
		||||
        {
 | 
			
		||||
            _setter = setter;
 | 
			
		||||
            _logger = factory.CreateLogger<ConsulFileConfigurationPoller>();
 | 
			
		||||
            _repo = repo;
 | 
			
		||||
            _previousAsJson = "";
 | 
			
		||||
            _timer = new Timer(async x =>
 | 
			
		||||
            {
 | 
			
		||||
                if(_polling)
 | 
			
		||||
                {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                _polling = true;
 | 
			
		||||
                await Poll();
 | 
			
		||||
                _polling = false;
 | 
			
		||||
 | 
			
		||||
            }, null, 0, 1000);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        private async Task Poll()
 | 
			
		||||
        {
 | 
			
		||||
            _logger.LogDebug("Started polling consul");
 | 
			
		||||
 | 
			
		||||
            var fileConfig = await _repo.Get();
 | 
			
		||||
 | 
			
		||||
            if(fileConfig.IsError)
 | 
			
		||||
            {
 | 
			
		||||
                _logger.LogDebug($"error geting file config, errors are {string.Join(",", fileConfig.Errors.Select(x => x.Message))}");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var asJson = ToJson(fileConfig.Data);
 | 
			
		||||
 | 
			
		||||
            if(!fileConfig.IsError && asJson != _previousAsJson)
 | 
			
		||||
            {
 | 
			
		||||
                await _setter.Set(fileConfig.Data);
 | 
			
		||||
                _previousAsJson = asJson;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            _logger.LogDebug("Finished polling consul");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// We could do object comparison here but performance isnt really a problem. This might be an issue one day!
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="config"></param>
 | 
			
		||||
        /// <returns></returns>
 | 
			
		||||
        private string ToJson(FileConfiguration config)
 | 
			
		||||
        {
 | 
			
		||||
            var currentHash = JsonConvert.SerializeObject(config);
 | 
			
		||||
            return currentHash;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            _timer.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -3,56 +3,57 @@ using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Consul;
 | 
			
		||||
using Newtonsoft.Json;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Ocelot.ServiceDiscovery;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Repository
 | 
			
		||||
{
 | 
			
		||||
    public class ConsulOcelotConfigurationRepository : IOcelotConfigurationRepository
 | 
			
		||||
 | 
			
		||||
    public class ConsulFileConfigurationRepository : IFileConfigurationRepository
 | 
			
		||||
    {
 | 
			
		||||
        private readonly ConsulClient _consul;
 | 
			
		||||
        private ConsulRegistryConfiguration _configuration;
 | 
			
		||||
        private string _ocelotConfiguration = "OcelotConfiguration";
 | 
			
		||||
        private Cache.IOcelotCache<IOcelotConfiguration> _cache;
 | 
			
		||||
        private readonly Cache.IOcelotCache<FileConfiguration> _cache;
 | 
			
		||||
 | 
			
		||||
        public ConsulOcelotConfigurationRepository(ConsulRegistryConfiguration consulRegistryConfiguration, Cache.IOcelotCache<IOcelotConfiguration> cache)
 | 
			
		||||
        public ConsulFileConfigurationRepository(Cache.IOcelotCache<FileConfiguration> 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}");
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<Response<IOcelotConfiguration>> Get()
 | 
			
		||||
        public async Task<Response<FileConfiguration>> Get()
 | 
			
		||||
        {
 | 
			
		||||
            var config = _cache.Get(_ocelotConfiguration, _ocelotConfiguration);
 | 
			
		||||
 | 
			
		||||
            if (config != null)
 | 
			
		||||
            {
 | 
			
		||||
                return new OkResponse<IOcelotConfiguration>(config);
 | 
			
		||||
                return new OkResponse<FileConfiguration>(config);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var queryResult = await _consul.KV.Get(_ocelotConfiguration);
 | 
			
		||||
 | 
			
		||||
            if (queryResult.Response == null)
 | 
			
		||||
            {
 | 
			
		||||
                return new OkResponse<IOcelotConfiguration>(null);
 | 
			
		||||
                return new OkResponse<FileConfiguration>(null);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var bytes = queryResult.Response.Value;
 | 
			
		||||
 | 
			
		||||
            var json = Encoding.UTF8.GetString(bytes);
 | 
			
		||||
 | 
			
		||||
            var consulConfig = JsonConvert.DeserializeObject<OcelotConfiguration>(json);
 | 
			
		||||
            var consulConfig = JsonConvert.DeserializeObject<FileConfiguration>(json);
 | 
			
		||||
 | 
			
		||||
            return new OkResponse<IOcelotConfiguration>(consulConfig);
 | 
			
		||||
            return new OkResponse<FileConfiguration>(consulConfig);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<Response> AddOrReplace(IOcelotConfiguration ocelotConfiguration)
 | 
			
		||||
        public async Task<Response> Set(FileConfiguration ocelotConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            var json = JsonConvert.SerializeObject(ocelotConfiguration);
 | 
			
		||||
 | 
			
		||||
@@ -72,7 +73,7 @@ namespace Ocelot.Configuration.Repository
 | 
			
		||||
                return new OkResponse();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return new ErrorResponse(new UnableToSetConfigInConsulError("Unable to set config in consul"));
 | 
			
		||||
            return new ErrorResponse(new UnableToSetConfigInConsulError($"Unable to set FileConfiguration in consul, response status code from consul was {result.StatusCode}"));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Microsoft.AspNetCore.Hosting;
 | 
			
		||||
using Newtonsoft.Json;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
@@ -7,33 +9,41 @@ namespace Ocelot.Configuration.Repository
 | 
			
		||||
{
 | 
			
		||||
    public class FileConfigurationRepository : IFileConfigurationRepository
 | 
			
		||||
    {
 | 
			
		||||
        private readonly string _configFilePath;
 | 
			
		||||
 | 
			
		||||
        private static readonly object _lock = new object();
 | 
			
		||||
        public Response<FileConfiguration> Get()
 | 
			
		||||
        
 | 
			
		||||
        public FileConfigurationRepository(IHostingEnvironment hostingEnvironment)
 | 
			
		||||
        {
 | 
			
		||||
            var configFilePath = $"{AppContext.BaseDirectory}/configuration.json";
 | 
			
		||||
            string json = string.Empty;
 | 
			
		||||
            _configFilePath = $"{AppContext.BaseDirectory}/configuration{(string.IsNullOrEmpty(hostingEnvironment.EnvironmentName) ? string.Empty : ".")}{hostingEnvironment.EnvironmentName}.json";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<Response<FileConfiguration>> Get()
 | 
			
		||||
        {
 | 
			
		||||
            string jsonConfiguration;
 | 
			
		||||
 | 
			
		||||
            lock(_lock)
 | 
			
		||||
            {
 | 
			
		||||
                json = System.IO.File.ReadAllText(configFilePath);
 | 
			
		||||
                jsonConfiguration = System.IO.File.ReadAllText(_configFilePath);
 | 
			
		||||
            }
 | 
			
		||||
            var fileConfiguration = JsonConvert.DeserializeObject<FileConfiguration>(json);
 | 
			
		||||
 | 
			
		||||
            var fileConfiguration = JsonConvert.DeserializeObject<FileConfiguration>(jsonConfiguration);
 | 
			
		||||
 | 
			
		||||
            return new OkResponse<FileConfiguration>(fileConfiguration);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Response Set(FileConfiguration fileConfiguration)
 | 
			
		||||
        public async Task<Response> Set(FileConfiguration fileConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            var configurationPath = $"{AppContext.BaseDirectory}/configuration.json";
 | 
			
		||||
 | 
			
		||||
            var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration);
 | 
			
		||||
            string jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration);
 | 
			
		||||
 | 
			
		||||
            lock(_lock)
 | 
			
		||||
            {
 | 
			
		||||
                if (System.IO.File.Exists(configurationPath))
 | 
			
		||||
                if (System.IO.File.Exists(_configFilePath))
 | 
			
		||||
                {
 | 
			
		||||
                    System.IO.File.Delete(configurationPath);
 | 
			
		||||
                    System.IO.File.Delete(_configFilePath);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                System.IO.File.WriteAllText(configurationPath, jsonConfiguration);
 | 
			
		||||
                System.IO.File.WriteAllText(_configFilePath, jsonConfiguration);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            return new OkResponse();
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
 | 
			
		||||
@@ -5,7 +6,7 @@ namespace Ocelot.Configuration.Repository
 | 
			
		||||
{
 | 
			
		||||
    public interface IFileConfigurationRepository
 | 
			
		||||
    {
 | 
			
		||||
        Response<FileConfiguration> Get();
 | 
			
		||||
        Response Set(FileConfiguration fileConfiguration);
 | 
			
		||||
        Task<Response<FileConfiguration>> Get();
 | 
			
		||||
        Task<Response> Set(FileConfiguration fileConfiguration);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Repository
 | 
			
		||||
 
 | 
			
		||||
@@ -2,23 +2,12 @@
 | 
			
		||||
{
 | 
			
		||||
    public class ServiceProviderConfiguration
 | 
			
		||||
    {
 | 
			
		||||
        public ServiceProviderConfiguration(string serviceName, string downstreamHost,
 | 
			
		||||
            int downstreamPort, bool useServiceDiscovery, string serviceDiscoveryProvider, string serviceProviderHost, int serviceProviderPort)
 | 
			
		||||
        public ServiceProviderConfiguration(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; }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@ namespace Ocelot.Configuration.Setter
 | 
			
		||||
 | 
			
		||||
        public async Task<Response> Set(FileConfiguration fileConfig)
 | 
			
		||||
        {
 | 
			
		||||
            var response = _repo.Set(fileConfig);
 | 
			
		||||
            var response = await _repo.Set(fileConfig);
 | 
			
		||||
 | 
			
		||||
            if(response.IsError)
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -21,9 +21,9 @@ namespace Ocelot.Controllers
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [HttpGet]
 | 
			
		||||
        public IActionResult Get()
 | 
			
		||||
        public async Task<IActionResult> Get()
 | 
			
		||||
        {
 | 
			
		||||
            var response = _configGetter.Get();
 | 
			
		||||
            var response = await _configGetter.Get();
 | 
			
		||||
 | 
			
		||||
            if(response.IsError)
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								src/Ocelot/DependencyInjection/IOcelotBuilder.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/Ocelot/DependencyInjection/IOcelotBuilder.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
using CacheManager.Core;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.DependencyInjection
 | 
			
		||||
{
 | 
			
		||||
    public interface IOcelotBuilder
 | 
			
		||||
    {
 | 
			
		||||
        IOcelotBuilder AddStoreOcelotConfigurationInConsul();
 | 
			
		||||
        IOcelotBuilder AddCacheManager(Action<ConfigurationBuilderCachePart> settings);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										262
									
								
								src/Ocelot/DependencyInjection/OcelotBuilder.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										262
									
								
								src/Ocelot/DependencyInjection/OcelotBuilder.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,262 @@
 | 
			
		||||
using CacheManager.Core;
 | 
			
		||||
using IdentityServer4.Models;
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Microsoft.Extensions.Configuration;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using Ocelot.Authorisation;
 | 
			
		||||
using Ocelot.Cache;
 | 
			
		||||
using Ocelot.Claims;
 | 
			
		||||
using Ocelot.Configuration.Authentication;
 | 
			
		||||
using Ocelot.Configuration.Creator;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using Ocelot.Configuration.Parser;
 | 
			
		||||
using Ocelot.Configuration.Provider;
 | 
			
		||||
using Ocelot.Configuration.Repository;
 | 
			
		||||
using Ocelot.Configuration.Setter;
 | 
			
		||||
using Ocelot.Configuration.Validator;
 | 
			
		||||
using Ocelot.Controllers;
 | 
			
		||||
using Ocelot.DownstreamRouteFinder.Finder;
 | 
			
		||||
using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
			
		||||
using Ocelot.DownstreamUrlCreator;
 | 
			
		||||
using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer;
 | 
			
		||||
using Ocelot.Headers;
 | 
			
		||||
using Ocelot.Infrastructure.Claims.Parser;
 | 
			
		||||
using Ocelot.Infrastructure.RequestData;
 | 
			
		||||
using Ocelot.LoadBalancer.LoadBalancers;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Ocelot.QueryStrings;
 | 
			
		||||
using Ocelot.RateLimit;
 | 
			
		||||
using Ocelot.Request.Builder;
 | 
			
		||||
using Ocelot.Request.Mapper;
 | 
			
		||||
using Ocelot.Requester;
 | 
			
		||||
using Ocelot.Requester.QoS;
 | 
			
		||||
using Ocelot.Responder;
 | 
			
		||||
using Ocelot.ServiceDiscovery;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.IdentityModel.Tokens.Jwt;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using System.Security.Cryptography.X509Certificates;
 | 
			
		||||
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 Microsoft.Extensions.DependencyInjection.Extensions;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.DependencyInjection
 | 
			
		||||
{
 | 
			
		||||
    public class OcelotBuilder : IOcelotBuilder
 | 
			
		||||
    {
 | 
			
		||||
        private IServiceCollection _services;
 | 
			
		||||
        private IConfigurationRoot _configurationRoot;
 | 
			
		||||
        
 | 
			
		||||
        public OcelotBuilder(IServiceCollection services, IConfigurationRoot configurationRoot)
 | 
			
		||||
        {
 | 
			
		||||
            _configurationRoot = configurationRoot;
 | 
			
		||||
            _services = services;    
 | 
			
		||||
            
 | 
			
		||||
            //add default cache settings...
 | 
			
		||||
            Action<ConfigurationBuilderCachePart> defaultCachingSettings = x =>
 | 
			
		||||
            {
 | 
			
		||||
                x.WithDictionaryHandle();
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            AddCacheManager(defaultCachingSettings);
 | 
			
		||||
 | 
			
		||||
            //add ocelot services...
 | 
			
		||||
            _services.Configure<FileConfiguration>(configurationRoot);
 | 
			
		||||
            _services.TryAddSingleton<IOcelotConfigurationCreator, FileOcelotConfigurationCreator>();
 | 
			
		||||
            _services.TryAddSingleton<IOcelotConfigurationRepository, InMemoryOcelotConfigurationRepository>();
 | 
			
		||||
            _services.TryAddSingleton<IConfigurationValidator, FileConfigurationValidator>();
 | 
			
		||||
            _services.TryAddSingleton<IClaimsToThingCreator, ClaimsToThingCreator>();
 | 
			
		||||
            _services.TryAddSingleton<IAuthenticationOptionsCreator, AuthenticationOptionsCreator>();
 | 
			
		||||
            _services.TryAddSingleton<IUpstreamTemplatePatternCreator, UpstreamTemplatePatternCreator>();
 | 
			
		||||
            _services.TryAddSingleton<IRequestIdKeyCreator, RequestIdKeyCreator>();
 | 
			
		||||
            _services.TryAddSingleton<IServiceProviderConfigurationCreator,ServiceProviderConfigurationCreator>();
 | 
			
		||||
            _services.TryAddSingleton<IQoSOptionsCreator, QoSOptionsCreator>();
 | 
			
		||||
            _services.TryAddSingleton<IReRouteOptionsCreator, ReRouteOptionsCreator>();
 | 
			
		||||
            _services.TryAddSingleton<IRateLimitOptionsCreator, RateLimitOptionsCreator>();
 | 
			
		||||
            _services.TryAddSingleton<IBaseUrlFinder, BaseUrlFinder>();
 | 
			
		||||
            _services.TryAddSingleton<IRegionCreator, RegionCreator>();
 | 
			
		||||
            _services.TryAddSingleton<IFileConfigurationRepository, FileConfigurationRepository>();
 | 
			
		||||
            _services.TryAddSingleton<IFileConfigurationSetter, FileConfigurationSetter>();
 | 
			
		||||
            _services.TryAddSingleton<IFileConfigurationProvider, FileConfigurationProvider>();
 | 
			
		||||
            _services.TryAddSingleton<IQosProviderHouse, QosProviderHouse>();
 | 
			
		||||
            _services.TryAddSingleton<IQoSProviderFactory, QoSProviderFactory>();
 | 
			
		||||
            _services.TryAddSingleton<IServiceDiscoveryProviderFactory, ServiceDiscoveryProviderFactory>();
 | 
			
		||||
            _services.TryAddSingleton<ILoadBalancerFactory, LoadBalancerFactory>();
 | 
			
		||||
            _services.TryAddSingleton<ILoadBalancerHouse, LoadBalancerHouse>();
 | 
			
		||||
            _services.TryAddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
 | 
			
		||||
            _services.TryAddSingleton<IUrlBuilder, UrlBuilder>();
 | 
			
		||||
            _services.TryAddSingleton<IRemoveOutputHeaders, RemoveOutputHeaders>();
 | 
			
		||||
            _services.TryAddSingleton<IOcelotConfigurationProvider, OcelotConfigurationProvider>();
 | 
			
		||||
            _services.TryAddSingleton<IClaimToThingConfigurationParser, ClaimToThingConfigurationParser>();
 | 
			
		||||
            _services.TryAddSingleton<IClaimsAuthoriser, ClaimsAuthoriser>();
 | 
			
		||||
            _services.TryAddSingleton<IScopesAuthoriser, ScopesAuthoriser>();
 | 
			
		||||
            _services.TryAddSingleton<IAddClaimsToRequest, AddClaimsToRequest>();
 | 
			
		||||
            _services.TryAddSingleton<IAddHeadersToRequest, AddHeadersToRequest>();
 | 
			
		||||
            _services.TryAddSingleton<IAddQueriesToRequest, AddQueriesToRequest>();
 | 
			
		||||
            _services.TryAddSingleton<IClaimsParser, ClaimsParser>();
 | 
			
		||||
            _services.TryAddSingleton<IUrlPathToUrlTemplateMatcher, RegExUrlMatcher>();
 | 
			
		||||
            _services.TryAddSingleton<IUrlPathPlaceholderNameAndValueFinder, UrlPathPlaceholderNameAndValueFinder>();
 | 
			
		||||
            _services.TryAddSingleton<IDownstreamPathPlaceholderReplacer, DownstreamTemplatePathPlaceholderReplacer>();
 | 
			
		||||
            _services.TryAddSingleton<IDownstreamRouteFinder, DownstreamRouteFinder.Finder.DownstreamRouteFinder>();
 | 
			
		||||
            _services.TryAddSingleton<IHttpRequester, HttpClientHttpRequester>();
 | 
			
		||||
            _services.TryAddSingleton<IHttpResponder, HttpContextResponder>();
 | 
			
		||||
            _services.TryAddSingleton<IRequestCreator, HttpRequestCreator>();
 | 
			
		||||
            _services.TryAddSingleton<IErrorsToHttpStatusCodeMapper, ErrorsToHttpStatusCodeMapper>();
 | 
			
		||||
            _services.TryAddSingleton<IRateLimitCounterHandler, MemoryCacheRateLimitCounterHandler>();
 | 
			
		||||
            _services.TryAddSingleton<IHttpClientCache, MemoryHttpClientCache>();
 | 
			
		||||
            _services.TryAddSingleton<IRequestMapper, RequestMapper>();
 | 
			
		||||
            _services.TryAddSingleton<IHttpHandlerOptionsCreator, HttpHandlerOptionsCreator>();
 | 
			
		||||
            // see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc
 | 
			
		||||
            // could maybe use a scoped data repository
 | 
			
		||||
            _services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
 | 
			
		||||
            _services.TryAddScoped<IRequestScopedDataRepository, HttpDataRepository>();
 | 
			
		||||
            _services.AddMemoryCache();
 | 
			
		||||
            _services.TryAddSingleton<OcelotDiagnosticListener>();
 | 
			
		||||
 | 
			
		||||
            //add identity server for admin area
 | 
			
		||||
            var identityServerConfiguration = IdentityServerConfigurationCreator.GetIdentityServerConfiguration();
 | 
			
		||||
 | 
			
		||||
            if (identityServerConfiguration != null)
 | 
			
		||||
            {
 | 
			
		||||
                AddIdentityServer(identityServerConfiguration);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //add asp.net services..
 | 
			
		||||
            var assembly = typeof(FileConfigurationController).GetTypeInfo().Assembly;
 | 
			
		||||
 | 
			
		||||
            _services.AddMvcCore()
 | 
			
		||||
                .AddApplicationPart(assembly)
 | 
			
		||||
                .AddControllersAsServices()
 | 
			
		||||
                .AddAuthorization()
 | 
			
		||||
                .AddJsonFormatters();
 | 
			
		||||
 | 
			
		||||
            _services.AddLogging();
 | 
			
		||||
            _services.AddMiddlewareAnalysis();
 | 
			
		||||
            _services.AddWebEncoders();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IOcelotBuilder AddStoreOcelotConfigurationInConsul()
 | 
			
		||||
        {
 | 
			
		||||
            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<ServiceProviderConfiguration>(config);
 | 
			
		||||
            _services.AddSingleton<ConsulFileConfigurationPoller>();
 | 
			
		||||
            _services.AddSingleton<IFileConfigurationRepository, ConsulFileConfigurationRepository>();
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IOcelotBuilder AddCacheManager(Action<ConfigurationBuilderCachePart> settings)
 | 
			
		||||
        {
 | 
			
		||||
            var cacheManagerOutputCache = CacheFactory.Build<HttpResponseMessage>("OcelotOutputCache", settings);
 | 
			
		||||
            var ocelotOutputCacheManager = new OcelotCacheManagerCache<HttpResponseMessage>(cacheManagerOutputCache);
 | 
			
		||||
 | 
			
		||||
            _services.RemoveAll(typeof(ICacheManager<HttpResponseMessage>));
 | 
			
		||||
            _services.RemoveAll(typeof(IOcelotCache<HttpResponseMessage>));
 | 
			
		||||
            _services.AddSingleton<ICacheManager<HttpResponseMessage>>(cacheManagerOutputCache);
 | 
			
		||||
            _services.AddSingleton<IOcelotCache<HttpResponseMessage>>(ocelotOutputCacheManager);
 | 
			
		||||
 | 
			
		||||
            var ocelotConfigCacheManagerOutputCache = CacheFactory.Build<IOcelotConfiguration>("OcelotConfigurationCache", settings);
 | 
			
		||||
            var ocelotConfigCacheManager = new OcelotCacheManagerCache<IOcelotConfiguration>(ocelotConfigCacheManagerOutputCache);
 | 
			
		||||
            _services.RemoveAll(typeof(ICacheManager<IOcelotConfiguration>));
 | 
			
		||||
            _services.RemoveAll(typeof(IOcelotCache<IOcelotConfiguration>));
 | 
			
		||||
            _services.AddSingleton<ICacheManager<IOcelotConfiguration>>(ocelotConfigCacheManagerOutputCache);
 | 
			
		||||
            _services.AddSingleton<IOcelotCache<IOcelotConfiguration>>(ocelotConfigCacheManager);
 | 
			
		||||
 | 
			
		||||
            var fileConfigCacheManagerOutputCache = CacheFactory.Build<FileConfiguration>("FileConfigurationCache", settings);
 | 
			
		||||
            var fileConfigCacheManager = new OcelotCacheManagerCache<FileConfiguration>(fileConfigCacheManagerOutputCache);
 | 
			
		||||
            _services.RemoveAll(typeof(ICacheManager<FileConfiguration>));
 | 
			
		||||
            _services.RemoveAll(typeof(IOcelotCache<FileConfiguration>));
 | 
			
		||||
            _services.AddSingleton<ICacheManager<FileConfiguration>>(fileConfigCacheManagerOutputCache);
 | 
			
		||||
            _services.AddSingleton<IOcelotCache<FileConfiguration>>(fileConfigCacheManager);
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void AddIdentityServer(IIdentityServerConfiguration identityServerConfiguration) 
 | 
			
		||||
        {
 | 
			
		||||
            _services.TryAddSingleton<IIdentityServerConfiguration>(identityServerConfiguration);
 | 
			
		||||
            _services.TryAddSingleton<IHashMatcher, HashMatcher>();
 | 
			
		||||
            var identityServerBuilder = _services
 | 
			
		||||
                .AddIdentityServer(o => {
 | 
			
		||||
                    o.IssuerUri = "Ocelot";
 | 
			
		||||
                })
 | 
			
		||||
                .AddInMemoryApiResources(Resources(identityServerConfiguration))
 | 
			
		||||
                .AddInMemoryClients(Client(identityServerConfiguration))
 | 
			
		||||
                .AddResourceOwnerValidator<OcelotResourceOwnerPasswordValidator>();
 | 
			
		||||
 | 
			
		||||
            //todo - refactor a method so we know why this is happening
 | 
			
		||||
            var whb = _services.First(x => x.ServiceType == typeof(IWebHostBuilder));
 | 
			
		||||
            var urlFinder = new BaseUrlFinder((IWebHostBuilder)whb.ImplementationInstance);
 | 
			
		||||
            var baseSchemeUrlAndPort = urlFinder.Find();
 | 
			
		||||
            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
 | 
			
		||||
 | 
			
		||||
            _services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
 | 
			
		||||
                .AddIdentityServerAuthentication(o =>
 | 
			
		||||
                {
 | 
			
		||||
                    var adminPath = _configurationRoot.GetValue("GlobalConfiguration:AdministrationPath", string.Empty);
 | 
			
		||||
                    o.Authority = baseSchemeUrlAndPort + adminPath;
 | 
			
		||||
                    o.ApiName = identityServerConfiguration.ApiName;
 | 
			
		||||
                    o.RequireHttpsMetadata = identityServerConfiguration.RequireHttps;
 | 
			
		||||
                    o.SupportedTokens = SupportedTokens.Both;
 | 
			
		||||
                    o.ApiSecret = identityServerConfiguration.ApiSecret;
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                //todo - refactor naming..
 | 
			
		||||
                if (string.IsNullOrEmpty(identityServerConfiguration.CredentialsSigningCertificateLocation) || string.IsNullOrEmpty(identityServerConfiguration.CredentialsSigningCertificatePassword))
 | 
			
		||||
                {
 | 
			
		||||
                    identityServerBuilder.AddDeveloperSigningCredential();
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    //todo - refactor so calls method?
 | 
			
		||||
                    var cert = new X509Certificate2(identityServerConfiguration.CredentialsSigningCertificateLocation, identityServerConfiguration.CredentialsSigningCertificatePassword);
 | 
			
		||||
                    identityServerBuilder.AddSigningCredential(cert);
 | 
			
		||||
                }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private List<ApiResource> Resources(IIdentityServerConfiguration identityServerConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            return new List<ApiResource>
 | 
			
		||||
            {
 | 
			
		||||
                new ApiResource(identityServerConfiguration.ApiName, identityServerConfiguration.ApiName)
 | 
			
		||||
                {
 | 
			
		||||
                    ApiSecrets = new List<Secret>
 | 
			
		||||
                    {
 | 
			
		||||
                        new Secret
 | 
			
		||||
                        {
 | 
			
		||||
                            Value = identityServerConfiguration.ApiSecret.Sha256()
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private List<Client> Client(IIdentityServerConfiguration identityServerConfiguration) 
 | 
			
		||||
        {
 | 
			
		||||
            return new List<Client>
 | 
			
		||||
            {
 | 
			
		||||
                new Client
 | 
			
		||||
                {
 | 
			
		||||
                    ClientId = identityServerConfiguration.ApiName,
 | 
			
		||||
                    AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
 | 
			
		||||
                    ClientSecrets = new List<Secret> {new Secret(identityServerConfiguration.ApiSecret.Sha256())},
 | 
			
		||||
                    AllowedScopes = { identityServerConfiguration.ApiName }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,223 +1,16 @@
 | 
			
		||||
using CacheManager.Core;
 | 
			
		||||
using IdentityServer4.Models;
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Microsoft.Extensions.Configuration;
 | 
			
		||||
using Microsoft.Extensions.Configuration;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection.Extensions;
 | 
			
		||||
using Ocelot.Authorisation;
 | 
			
		||||
using Ocelot.Cache;
 | 
			
		||||
using Ocelot.Claims;
 | 
			
		||||
using Ocelot.Configuration.Authentication;
 | 
			
		||||
using Ocelot.Configuration.Creator;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using Ocelot.Configuration.Parser;
 | 
			
		||||
using Ocelot.Configuration.Provider;
 | 
			
		||||
using Ocelot.Configuration.Repository;
 | 
			
		||||
using Ocelot.Configuration.Setter;
 | 
			
		||||
using Ocelot.Configuration.Validator;
 | 
			
		||||
using Ocelot.Controllers;
 | 
			
		||||
using Ocelot.DownstreamRouteFinder.Finder;
 | 
			
		||||
using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
			
		||||
using Ocelot.DownstreamUrlCreator;
 | 
			
		||||
using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer;
 | 
			
		||||
using Ocelot.Headers;
 | 
			
		||||
using Ocelot.Infrastructure.Claims.Parser;
 | 
			
		||||
using Ocelot.Infrastructure.RequestData;
 | 
			
		||||
using Ocelot.LoadBalancer.LoadBalancers;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Ocelot.QueryStrings;
 | 
			
		||||
using Ocelot.RateLimit;
 | 
			
		||||
using Ocelot.Request.Builder;
 | 
			
		||||
using Ocelot.Request.Mapper;
 | 
			
		||||
using Ocelot.Requester;
 | 
			
		||||
using Ocelot.Requester.QoS;
 | 
			
		||||
using Ocelot.Responder;
 | 
			
		||||
using Ocelot.ServiceDiscovery;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.IdentityModel.Tokens.Jwt;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using System.Security.Cryptography.X509Certificates;
 | 
			
		||||
using IdentityServer4.AccessTokenValidation;
 | 
			
		||||
using Microsoft.AspNetCore.Builder;
 | 
			
		||||
using Microsoft.AspNetCore.Hosting;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using FileConfigurationProvider = Ocelot.Configuration.Provider.FileConfigurationProvider;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.DependencyInjection
 | 
			
		||||
{
 | 
			
		||||
    public static class ServiceCollectionExtensions
 | 
			
		||||
    {
 | 
			
		||||
        public static IServiceCollection AddOcelotStoreConfigurationInConsul(this IServiceCollection services, ConsulRegistryConfiguration consulConfig)
 | 
			
		||||
        public static IOcelotBuilder AddOcelot(this IServiceCollection services,
 | 
			
		||||
            IConfigurationRoot configurationRoot)
 | 
			
		||||
        {
 | 
			
		||||
            services.AddSingleton<ConsulRegistryConfiguration>(consulConfig);
 | 
			
		||||
            services.AddSingleton<IOcelotConfigurationRepository, ConsulOcelotConfigurationRepository>();
 | 
			
		||||
            return services;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static IServiceCollection AddOcelot(this IServiceCollection services, IConfigurationRoot configurationRoot, Action<ConfigurationBuilderCachePart> settings)
 | 
			
		||||
        {
 | 
			
		||||
            var cacheManagerOutputCache = CacheFactory.Build<HttpResponseMessage>("OcelotOutputCache", settings);
 | 
			
		||||
            var ocelotOutputCacheManager = new OcelotCacheManagerCache<HttpResponseMessage>(cacheManagerOutputCache);
 | 
			
		||||
            services.TryAddSingleton<ICacheManager<HttpResponseMessage>>(cacheManagerOutputCache);
 | 
			
		||||
            services.TryAddSingleton<IOcelotCache<HttpResponseMessage>>(ocelotOutputCacheManager);
 | 
			
		||||
 | 
			
		||||
            var ocelotConfigCacheManagerOutputCache = CacheFactory.Build<IOcelotConfiguration>("OcelotConfigurationCache", settings);
 | 
			
		||||
            var ocelotConfigCacheManager = new OcelotCacheManagerCache<IOcelotConfiguration>(ocelotConfigCacheManagerOutputCache);
 | 
			
		||||
            services.TryAddSingleton<ICacheManager<IOcelotConfiguration>>(ocelotConfigCacheManagerOutputCache);
 | 
			
		||||
            services.TryAddSingleton<IOcelotCache<IOcelotConfiguration>>(ocelotConfigCacheManager);
 | 
			
		||||
 | 
			
		||||
            services.Configure<FileConfiguration>(configurationRoot);
 | 
			
		||||
            services.TryAddSingleton<IOcelotConfigurationCreator, FileOcelotConfigurationCreator>();
 | 
			
		||||
            services.TryAddSingleton<IOcelotConfigurationRepository, InMemoryOcelotConfigurationRepository>();
 | 
			
		||||
            services.TryAddSingleton<IConfigurationValidator, FileConfigurationValidator>();
 | 
			
		||||
            services.TryAddSingleton<IClaimsToThingCreator, ClaimsToThingCreator>();
 | 
			
		||||
            services.TryAddSingleton<IAuthenticationOptionsCreator, AuthenticationOptionsCreator>();
 | 
			
		||||
            services.TryAddSingleton<IUpstreamTemplatePatternCreator, UpstreamTemplatePatternCreator>();
 | 
			
		||||
            services.TryAddSingleton<IRequestIdKeyCreator, RequestIdKeyCreator>();
 | 
			
		||||
            services.TryAddSingleton<IServiceProviderConfigurationCreator,ServiceProviderConfigurationCreator>();
 | 
			
		||||
            services.TryAddSingleton<IQoSOptionsCreator, QoSOptionsCreator>();
 | 
			
		||||
            services.TryAddSingleton<IReRouteOptionsCreator, ReRouteOptionsCreator>();
 | 
			
		||||
            services.TryAddSingleton<IRateLimitOptionsCreator, RateLimitOptionsCreator>();
 | 
			
		||||
            services.TryAddSingleton<IBaseUrlFinder, BaseUrlFinder>();
 | 
			
		||||
 | 
			
		||||
            var assembly = typeof(FileConfigurationController).GetTypeInfo().Assembly;
 | 
			
		||||
 | 
			
		||||
            services.AddMvcCore()
 | 
			
		||||
                .AddApplicationPart(assembly)
 | 
			
		||||
                .AddControllersAsServices()
 | 
			
		||||
                .AddAuthorization()
 | 
			
		||||
                .AddJsonFormatters();
 | 
			
		||||
 | 
			
		||||
            services.AddLogging();
 | 
			
		||||
            services.TryAddSingleton<IRegionCreator, RegionCreator>();
 | 
			
		||||
            services.TryAddSingleton<IFileConfigurationRepository, FileConfigurationRepository>();
 | 
			
		||||
            services.TryAddSingleton<IFileConfigurationSetter, FileConfigurationSetter>();
 | 
			
		||||
            services.TryAddSingleton<IFileConfigurationProvider, FileConfigurationProvider>();
 | 
			
		||||
            services.TryAddSingleton<IQosProviderHouse, QosProviderHouse>();
 | 
			
		||||
            services.TryAddSingleton<IQoSProviderFactory, QoSProviderFactory>();
 | 
			
		||||
            services.TryAddSingleton<IServiceDiscoveryProviderFactory, ServiceDiscoveryProviderFactory>();
 | 
			
		||||
            services.TryAddSingleton<ILoadBalancerFactory, LoadBalancerFactory>();
 | 
			
		||||
            services.TryAddSingleton<ILoadBalancerHouse, LoadBalancerHouse>();
 | 
			
		||||
            services.TryAddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
 | 
			
		||||
            services.TryAddSingleton<IUrlBuilder, UrlBuilder>();
 | 
			
		||||
            services.TryAddSingleton<IRemoveOutputHeaders, RemoveOutputHeaders>();
 | 
			
		||||
            services.TryAddSingleton<IOcelotConfigurationProvider, OcelotConfigurationProvider>();
 | 
			
		||||
            services.TryAddSingleton<IClaimToThingConfigurationParser, ClaimToThingConfigurationParser>();
 | 
			
		||||
            services.TryAddSingleton<IClaimsAuthoriser, ClaimsAuthoriser>();
 | 
			
		||||
            services.TryAddSingleton<IScopesAuthoriser, ScopesAuthoriser>();
 | 
			
		||||
            services.TryAddSingleton<IAddClaimsToRequest, AddClaimsToRequest>();
 | 
			
		||||
            services.TryAddSingleton<IAddHeadersToRequest, AddHeadersToRequest>();
 | 
			
		||||
            services.TryAddSingleton<IAddQueriesToRequest, AddQueriesToRequest>();
 | 
			
		||||
            services.TryAddSingleton<IClaimsParser, ClaimsParser>();
 | 
			
		||||
            services.TryAddSingleton<IUrlPathToUrlTemplateMatcher, RegExUrlMatcher>();
 | 
			
		||||
            services.TryAddSingleton<IUrlPathPlaceholderNameAndValueFinder, UrlPathPlaceholderNameAndValueFinder>();
 | 
			
		||||
            services.TryAddSingleton<IDownstreamPathPlaceholderReplacer, DownstreamTemplatePathPlaceholderReplacer>();
 | 
			
		||||
            services.TryAddSingleton<IDownstreamRouteFinder, DownstreamRouteFinder.Finder.DownstreamRouteFinder>();
 | 
			
		||||
            services.TryAddSingleton<IHttpRequester, HttpClientHttpRequester>();
 | 
			
		||||
            services.TryAddSingleton<IHttpResponder, HttpContextResponder>();
 | 
			
		||||
            services.TryAddSingleton<IRequestCreator, HttpRequestCreator>();
 | 
			
		||||
            services.TryAddSingleton<IErrorsToHttpStatusCodeMapper, ErrorsToHttpStatusCodeMapper>();
 | 
			
		||||
            services.TryAddSingleton<IRateLimitCounterHandler, MemoryCacheRateLimitCounterHandler>();
 | 
			
		||||
            services.TryAddSingleton<IHttpClientCache, MemoryHttpClientCache>();
 | 
			
		||||
            services.TryAddSingleton<IRequestMapper, RequestMapper>();
 | 
			
		||||
            services.TryAddSingleton<IHttpHandlerOptionsCreator, HttpHandlerOptionsCreator>();
 | 
			
		||||
 | 
			
		||||
            // see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc
 | 
			
		||||
            // could maybe use a scoped data repository
 | 
			
		||||
            services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
 | 
			
		||||
            services.TryAddScoped<IRequestScopedDataRepository, HttpDataRepository>();
 | 
			
		||||
            services.AddMemoryCache();
 | 
			
		||||
 | 
			
		||||
            //Used to log the the start and ending of middleware
 | 
			
		||||
            services.TryAddSingleton<OcelotDiagnosticListener>();
 | 
			
		||||
            services.AddMiddlewareAnalysis();
 | 
			
		||||
            services.AddWebEncoders();
 | 
			
		||||
 | 
			
		||||
            var identityServerConfiguration = IdentityServerConfigurationCreator.GetIdentityServerConfiguration();
 | 
			
		||||
 | 
			
		||||
            if (identityServerConfiguration != null)
 | 
			
		||||
            {
 | 
			
		||||
                services.AddIdentityServer(identityServerConfiguration, configurationRoot);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return services;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void AddIdentityServer(this IServiceCollection services, IIdentityServerConfiguration identityServerConfiguration, IConfigurationRoot configurationRoot) 
 | 
			
		||||
        {
 | 
			
		||||
            services.TryAddSingleton<IIdentityServerConfiguration>(identityServerConfiguration);
 | 
			
		||||
            services.TryAddSingleton<IHashMatcher, HashMatcher>();
 | 
			
		||||
            var identityServerBuilder = services
 | 
			
		||||
                .AddIdentityServer(o => {
 | 
			
		||||
                    o.IssuerUri = "Ocelot";
 | 
			
		||||
                })
 | 
			
		||||
                .AddInMemoryApiResources(Resources(identityServerConfiguration))
 | 
			
		||||
                .AddInMemoryClients(Client(identityServerConfiguration))
 | 
			
		||||
                .AddResourceOwnerValidator<OcelotResourceOwnerPasswordValidator>();
 | 
			
		||||
 | 
			
		||||
            //todo - refactor a method so we know why this is happening
 | 
			
		||||
            var whb = services.First(x => x.ServiceType == typeof(IWebHostBuilder));
 | 
			
		||||
            var urlFinder = new BaseUrlFinder((IWebHostBuilder)whb.ImplementationInstance);
 | 
			
		||||
            var baseSchemeUrlAndPort = urlFinder.Find();
 | 
			
		||||
            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
 | 
			
		||||
 | 
			
		||||
            services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
 | 
			
		||||
                .AddIdentityServerAuthentication(o =>
 | 
			
		||||
                {
 | 
			
		||||
                    var adminPath = configurationRoot.GetValue("GlobalConfiguration:AdministrationPath", string.Empty);
 | 
			
		||||
                    o.Authority = baseSchemeUrlAndPort + adminPath;
 | 
			
		||||
                    o.ApiName = identityServerConfiguration.ApiName;
 | 
			
		||||
                    o.RequireHttpsMetadata = identityServerConfiguration.RequireHttps;
 | 
			
		||||
                    o.SupportedTokens = SupportedTokens.Both;
 | 
			
		||||
                    o.ApiSecret = identityServerConfiguration.ApiSecret;
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                //todo - refactor naming..
 | 
			
		||||
                if (string.IsNullOrEmpty(identityServerConfiguration.CredentialsSigningCertificateLocation) || string.IsNullOrEmpty(identityServerConfiguration.CredentialsSigningCertificatePassword))
 | 
			
		||||
                {
 | 
			
		||||
                    identityServerBuilder.AddDeveloperSigningCredential();
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    //todo - refactor so calls method?
 | 
			
		||||
                    var cert = new X509Certificate2(identityServerConfiguration.CredentialsSigningCertificateLocation, identityServerConfiguration.CredentialsSigningCertificatePassword);
 | 
			
		||||
                    identityServerBuilder.AddSigningCredential(cert);
 | 
			
		||||
                }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static List<ApiResource> Resources(IIdentityServerConfiguration identityServerConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            return new List<ApiResource>
 | 
			
		||||
            {
 | 
			
		||||
                new ApiResource(identityServerConfiguration.ApiName, identityServerConfiguration.ApiName)
 | 
			
		||||
                {
 | 
			
		||||
                    ApiSecrets = new List<Secret>
 | 
			
		||||
                    {
 | 
			
		||||
                        new Secret
 | 
			
		||||
                        {
 | 
			
		||||
                            Value = identityServerConfiguration.ApiSecret.Sha256()
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static List<Client> Client(IIdentityServerConfiguration identityServerConfiguration) 
 | 
			
		||||
        {
 | 
			
		||||
            return new List<Client>
 | 
			
		||||
            {
 | 
			
		||||
                new Client
 | 
			
		||||
                {
 | 
			
		||||
                    ClientId = identityServerConfiguration.ApiName,
 | 
			
		||||
                    AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
 | 
			
		||||
                    ClientSecrets = new List<Secret> {new Secret(identityServerConfiguration.ApiSecret.Sha256())},
 | 
			
		||||
                    AllowedScopes = { identityServerConfiguration.ApiName }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
            return new OcelotBuilder(services, configurationRoot);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,34 +2,28 @@
 | 
			
		||||
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;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Ocelot.Utilities;
 | 
			
		||||
 | 
			
		||||
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<Response<DownstreamRoute>> FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod)
 | 
			
		||||
        public Response<DownstreamRoute> 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)
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,11 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.DownstreamRouteFinder.Finder
 | 
			
		||||
{
 | 
			
		||||
    public interface IDownstreamRouteFinder
 | 
			
		||||
    {
 | 
			
		||||
        Task<Response<DownstreamRoute>> FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod);
 | 
			
		||||
        Response<DownstreamRoute> FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod, IOcelotConfiguration configuration);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,12 +2,12 @@ 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;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Ocelot.Utilities;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.DownstreamRouteFinder.Middleware
 | 
			
		||||
{
 | 
			
		||||
@@ -16,13 +16,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<DownstreamRouteFinderMiddleware>();
 | 
			
		||||
@@ -32,9 +36,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)
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@ namespace Ocelot.DownstreamRouteFinder.UrlMatcher
 | 
			
		||||
         
 | 
			
		||||
            for (int counterForTemplate = 0; counterForTemplate < upstreamUrlPathTemplate.Length; counterForTemplate++)
 | 
			
		||||
            {
 | 
			
		||||
                if (CharactersDontMatch(upstreamUrlPathTemplate[counterForTemplate], upstreamUrlPath[counterForUrl]) && ContinueScanningUrl(counterForUrl,upstreamUrlPath.Length))
 | 
			
		||||
                if ((upstreamUrlPath.Length > counterForUrl) && CharactersDontMatch(upstreamUrlPathTemplate[counterForTemplate], upstreamUrlPath[counterForUrl]) && ContinueScanningUrl(counterForUrl,upstreamUrlPath.Length))
 | 
			
		||||
                {
 | 
			
		||||
                    if (IsPlaceholder(upstreamUrlPathTemplate[counterForTemplate]))
 | 
			
		||||
                    {
 | 
			
		||||
 
 | 
			
		||||
@@ -10,5 +10,10 @@ namespace Ocelot.Errors
 | 
			
		||||
 | 
			
		||||
        public string Message { get; private set; }
 | 
			
		||||
        public OcelotErrorCode Code { get; private set; }
 | 
			
		||||
 | 
			
		||||
        public override string ToString()
 | 
			
		||||
        {
 | 
			
		||||
            return Message;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -35,6 +35,14 @@ namespace Ocelot.Infrastructure.RequestData
 | 
			
		||||
        {
 | 
			
		||||
            object obj;
 | 
			
		||||
 | 
			
		||||
            if(_httpContextAccessor.HttpContext == null || _httpContextAccessor.HttpContext.Items == null)
 | 
			
		||||
            {
 | 
			
		||||
                return new ErrorResponse<T>(new List<Error>
 | 
			
		||||
                {
 | 
			
		||||
                    new CannotFindDataError($"Unable to find data for key: {key} because HttpContext or HttpContext.Items is null")
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if(_httpContextAccessor.HttpContext.Items.TryGetValue(key, out obj))
 | 
			
		||||
            {
 | 
			
		||||
                var data = (T) obj;
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,6 @@ namespace Ocelot.LoadBalancer.LoadBalancers
 | 
			
		||||
{
 | 
			
		||||
    public interface ILoadBalancerFactory
 | 
			
		||||
    {
 | 
			
		||||
        Task<ILoadBalancer> Get(ReRoute reRoute);
 | 
			
		||||
        Task<ILoadBalancer> Get(ReRoute reRoute, ServiceProviderConfiguration config);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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<ILoadBalancer> Get(string key);
 | 
			
		||||
        Response Add(string key, ILoadBalancer loadBalancer);
 | 
			
		||||
        Task<Response<ILoadBalancer>> Get(ReRoute reRoute, ServiceProviderConfiguration config);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -8,14 +8,14 @@ using Ocelot.Values;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.LoadBalancer.LoadBalancers
 | 
			
		||||
{
 | 
			
		||||
    public class LeastConnectionLoadBalancer : ILoadBalancer
 | 
			
		||||
    public class LeastConnection : ILoadBalancer
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Func<Task<List<Service>>> _services;
 | 
			
		||||
        private readonly List<Lease> _leases;
 | 
			
		||||
        private readonly string _serviceName;
 | 
			
		||||
        private static readonly object _syncLock = new object();
 | 
			
		||||
 | 
			
		||||
        public LeastConnectionLoadBalancer(Func<Task<List<Service>>> services, string serviceName)
 | 
			
		||||
        public LeastConnection(Func<Task<List<Service>>> services, string serviceName)
 | 
			
		||||
        {
 | 
			
		||||
            _services = services;
 | 
			
		||||
            _serviceName = serviceName;
 | 
			
		||||
@@ -12,16 +12,16 @@ namespace Ocelot.LoadBalancer.LoadBalancers
 | 
			
		||||
            _serviceProviderFactory = serviceProviderFactory;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<ILoadBalancer> Get(ReRoute reRoute)
 | 
			
		||||
        public async Task<ILoadBalancer> 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());
 | 
			
		||||
                    return new RoundRobin(async () => await serviceProvider.Get());
 | 
			
		||||
                case "LeastConnection":
 | 
			
		||||
                    return new LeastConnectionLoadBalancer(async () => await serviceProvider.Get(), reRoute.ServiceProviderConfiguraion.ServiceName);
 | 
			
		||||
                    return new LeastConnection(async () => await serviceProvider.Get(), reRoute.ServiceName);
 | 
			
		||||
                default:
 | 
			
		||||
                    return new NoLoadBalancer(await serviceProvider.Get());
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,42 +1,56 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.LoadBalancer.LoadBalancers
 | 
			
		||||
{
 | 
			
		||||
    public class LoadBalancerHouse : ILoadBalancerHouse
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Dictionary<string, ILoadBalancer> _loadBalancers;
 | 
			
		||||
        private readonly ILoadBalancerFactory _factory;
 | 
			
		||||
        private readonly ConcurrentDictionary<string, ILoadBalancer> _loadBalancers;
 | 
			
		||||
 | 
			
		||||
        public LoadBalancerHouse()
 | 
			
		||||
        public LoadBalancerHouse(ILoadBalancerFactory factory)
 | 
			
		||||
        {
 | 
			
		||||
            _loadBalancers = new Dictionary<string, ILoadBalancer>();
 | 
			
		||||
            _factory = factory;
 | 
			
		||||
            _loadBalancers = new ConcurrentDictionary<string, ILoadBalancer>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Response<ILoadBalancer> Get(string key)
 | 
			
		||||
        public async Task<Response<ILoadBalancer>> Get(ReRoute reRoute, ServiceProviderConfiguration config)
 | 
			
		||||
        {
 | 
			
		||||
            ILoadBalancer loadBalancer;
 | 
			
		||||
 | 
			
		||||
            if(_loadBalancers.TryGetValue(key, out loadBalancer))
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                return new OkResponse<ILoadBalancer>(_loadBalancers[key]);
 | 
			
		||||
            }
 | 
			
		||||
                if(_loadBalancers.TryGetValue(reRoute.ReRouteKey, out var loadBalancer))
 | 
			
		||||
                {
 | 
			
		||||
                    loadBalancer = _loadBalancers[reRoute.ReRouteKey];
 | 
			
		||||
 | 
			
		||||
                    if(reRoute.LoadBalancer != loadBalancer.GetType().Name)
 | 
			
		||||
                    {
 | 
			
		||||
                        loadBalancer = await _factory.Get(reRoute, config);
 | 
			
		||||
                        AddLoadBalancer(reRoute.ReRouteKey, loadBalancer);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return new OkResponse<ILoadBalancer>(loadBalancer);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                loadBalancer = await _factory.Get(reRoute, config);
 | 
			
		||||
                AddLoadBalancer(reRoute.ReRouteKey, loadBalancer);
 | 
			
		||||
                return new OkResponse<ILoadBalancer>(loadBalancer);
 | 
			
		||||
            }
 | 
			
		||||
            catch(Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                return new ErrorResponse<ILoadBalancer>(new List<Ocelot.Errors.Error>()
 | 
			
		||||
            {
 | 
			
		||||
                new UnableToFindLoadBalancerError($"unabe to find load balancer for {key}")
 | 
			
		||||
            });
 | 
			
		||||
                {
 | 
			
		||||
                    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))
 | 
			
		||||
            {
 | 
			
		||||
                _loadBalancers.Add(key, loadBalancer);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            _loadBalancers.Remove(key);
 | 
			
		||||
            _loadBalancers.Add(key, loadBalancer);
 | 
			
		||||
            return new OkResponse();
 | 
			
		||||
            _loadBalancers.AddOrUpdate(key, loadBalancer, (x, y) => loadBalancer);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,13 +6,13 @@ using System;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.LoadBalancer.LoadBalancers
 | 
			
		||||
{
 | 
			
		||||
    public class RoundRobinLoadBalancer : ILoadBalancer
 | 
			
		||||
    public class RoundRobin : ILoadBalancer
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Func<Task<List<Service>>> _services;
 | 
			
		||||
 | 
			
		||||
        private int _last;
 | 
			
		||||
 | 
			
		||||
        public RoundRobinLoadBalancer(Func<Task<List<Service>>> services)
 | 
			
		||||
        public RoundRobin(Func<Task<List<Service>>> services)
 | 
			
		||||
        {
 | 
			
		||||
            _services = services;
 | 
			
		||||
        }
 | 
			
		||||
@@ -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;
 | 
			
		||||
@@ -28,7 +29,7 @@ namespace Ocelot.LoadBalancer.Middleware
 | 
			
		||||
 | 
			
		||||
        public async Task Invoke(HttpContext context)
 | 
			
		||||
        {
 | 
			
		||||
            var loadBalancer = _loadBalancerHouse.Get(DownstreamRoute.ReRoute.ReRouteKey);
 | 
			
		||||
            var loadBalancer = await _loadBalancerHouse.Get(DownstreamRoute.ReRoute, ServiceProviderConfiguration);
 | 
			
		||||
            if(loadBalancer.IsError)
 | 
			
		||||
            {
 | 
			
		||||
                _logger.LogDebug("there was an error retriving the loadbalancer, setting pipeline error");
 | 
			
		||||
 
 | 
			
		||||
@@ -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>("HttpResponseMessage").Data;
 | 
			
		||||
 | 
			
		||||
        public ServiceProviderConfiguration ServiceProviderConfiguration => _requestScopedDataRepository.Get<ServiceProviderConfiguration>("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);
 | 
			
		||||
 
 | 
			
		||||
@@ -23,16 +23,20 @@ using Ocelot.RateLimit.Middleware;
 | 
			
		||||
namespace Ocelot.Middleware
 | 
			
		||||
{
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Linq;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using Authorisation.Middleware;
 | 
			
		||||
    using Microsoft.AspNetCore.Hosting;
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Microsoft.Extensions.Options;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Creator;
 | 
			
		||||
    using Ocelot.Configuration.File;
 | 
			
		||||
    using Ocelot.Configuration.Provider;
 | 
			
		||||
    using Ocelot.Configuration.Repository;
 | 
			
		||||
    using Ocelot.Configuration.Setter;
 | 
			
		||||
    using Ocelot.LoadBalancer.Middleware;
 | 
			
		||||
    using Ocelot.Responses;
 | 
			
		||||
 | 
			
		||||
    public static class OcelotMiddlewareExtensions
 | 
			
		||||
    {
 | 
			
		||||
@@ -56,7 +60,9 @@ namespace Ocelot.Middleware
 | 
			
		||||
        /// <returns></returns>
 | 
			
		||||
        public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder, OcelotMiddlewareConfiguration middlewareConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            await CreateAdministrationArea(builder);
 | 
			
		||||
            var configuration = await CreateConfiguration(builder);
 | 
			
		||||
            
 | 
			
		||||
            await CreateAdministrationArea(builder, configuration);
 | 
			
		||||
 | 
			
		||||
            ConfigureDiagnosticListener(builder);
 | 
			
		||||
 | 
			
		||||
@@ -145,38 +151,110 @@ namespace Ocelot.Middleware
 | 
			
		||||
 | 
			
		||||
        private static async Task<IOcelotConfiguration> CreateConfiguration(IApplicationBuilder builder)
 | 
			
		||||
        {
 | 
			
		||||
            var fileConfig = (IOptions<FileConfiguration>)builder.ApplicationServices.GetService(typeof(IOptions<FileConfiguration>));
 | 
			
		||||
            
 | 
			
		||||
            var configSetter = (IFileConfigurationSetter)builder.ApplicationServices.GetService(typeof(IFileConfigurationSetter));
 | 
			
		||||
            
 | 
			
		||||
            var configProvider = (IOcelotConfigurationProvider)builder.ApplicationServices.GetService(typeof(IOcelotConfigurationProvider));
 | 
			
		||||
            var deps = GetDependencies(builder);
 | 
			
		||||
 | 
			
		||||
            var ocelotConfiguration = await configProvider.Get();
 | 
			
		||||
            var ocelotConfiguration = await deps.provider.Get();
 | 
			
		||||
 | 
			
		||||
            if (ocelotConfiguration == null || ocelotConfiguration.Data == null || ocelotConfiguration.IsError)
 | 
			
		||||
            if (ConfigurationNotSetUp(ocelotConfiguration))
 | 
			
		||||
            {
 | 
			
		||||
                var config = await configSetter.Set(fileConfig.Value);
 | 
			
		||||
 | 
			
		||||
                if (config == null || config.IsError)
 | 
			
		||||
                var response = await SetConfig(builder, deps.fileConfiguration, deps.setter, deps.provider, deps.repo);
 | 
			
		||||
                
 | 
			
		||||
                if (UnableToSetConfig(response))
 | 
			
		||||
                {
 | 
			
		||||
                    throw new Exception("Unable to start Ocelot: configuration was not set up correctly.");
 | 
			
		||||
                    ThrowToStopOcelotStarting(response);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            ocelotConfiguration = await configProvider.Get();
 | 
			
		||||
            return await GetOcelotConfigAndReturn(deps.provider);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static async Task<Response> SetConfig(IApplicationBuilder builder, IOptions<FileConfiguration> fileConfiguration, IFileConfigurationSetter setter, IOcelotConfigurationProvider provider, IFileConfigurationRepository repo)
 | 
			
		||||
        {
 | 
			
		||||
            if (UsingConsul(repo))
 | 
			
		||||
            {
 | 
			
		||||
                return await SetUpConfigFromConsul(builder, repo, setter, fileConfiguration);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            return await setter.Set(fileConfiguration.Value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static bool UnableToSetConfig(Response response)
 | 
			
		||||
        {
 | 
			
		||||
            return response == null || response.IsError;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static bool ConfigurationNotSetUp(Response<IOcelotConfiguration> ocelotConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            return ocelotConfiguration == null || ocelotConfiguration.Data == null || ocelotConfiguration.IsError;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static (IOptions<FileConfiguration> fileConfiguration, IFileConfigurationSetter setter, IOcelotConfigurationProvider provider, IFileConfigurationRepository repo) GetDependencies(IApplicationBuilder builder)
 | 
			
		||||
        {
 | 
			
		||||
            var fileConfiguration = (IOptions<FileConfiguration>)builder.ApplicationServices.GetService(typeof(IOptions<FileConfiguration>));
 | 
			
		||||
            
 | 
			
		||||
            var setter = (IFileConfigurationSetter)builder.ApplicationServices.GetService(typeof(IFileConfigurationSetter));
 | 
			
		||||
            
 | 
			
		||||
            var provider = (IOcelotConfigurationProvider)builder.ApplicationServices.GetService(typeof(IOcelotConfigurationProvider));
 | 
			
		||||
 | 
			
		||||
            var repo = (IFileConfigurationRepository)builder.ApplicationServices.GetService(typeof(IFileConfigurationRepository));
 | 
			
		||||
 | 
			
		||||
            return (fileConfiguration, setter, provider, repo);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static async Task<IOcelotConfiguration> GetOcelotConfigAndReturn(IOcelotConfigurationProvider provider)
 | 
			
		||||
        {
 | 
			
		||||
            var ocelotConfiguration = await provider.Get();
 | 
			
		||||
 | 
			
		||||
            if(ocelotConfiguration == null || ocelotConfiguration.Data == null || ocelotConfiguration.IsError)
 | 
			
		||||
            {
 | 
			
		||||
                throw new Exception("Unable to start Ocelot: ocelot configuration was not returned by provider.");
 | 
			
		||||
                ThrowToStopOcelotStarting(ocelotConfiguration);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return ocelotConfiguration.Data;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static async Task CreateAdministrationArea(IApplicationBuilder builder)
 | 
			
		||||
        private static void ThrowToStopOcelotStarting(Response config)
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = await CreateConfiguration(builder);
 | 
			
		||||
            throw new Exception($"Unable to start Ocelot, errors are: {string.Join(",", config.Errors.Select(x => x.ToString()))}");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static bool UsingConsul(IFileConfigurationRepository fileConfigRepo)
 | 
			
		||||
        {
 | 
			
		||||
            return fileConfigRepo.GetType() == typeof(ConsulFileConfigurationRepository);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static async Task<Response> SetUpConfigFromConsul(IApplicationBuilder builder, IFileConfigurationRepository consulFileConfigRepo, IFileConfigurationSetter setter, IOptions<FileConfiguration> fileConfig)
 | 
			
		||||
        {
 | 
			
		||||
            Response config = null;
 | 
			
		||||
 | 
			
		||||
            var ocelotConfigurationRepository =
 | 
			
		||||
                (IOcelotConfigurationRepository) builder.ApplicationServices.GetService(
 | 
			
		||||
                    typeof(IOcelotConfigurationRepository));
 | 
			
		||||
            var ocelotConfigurationCreator =
 | 
			
		||||
                (IOcelotConfigurationCreator) builder.ApplicationServices.GetService(
 | 
			
		||||
                    typeof(IOcelotConfigurationCreator));
 | 
			
		||||
 | 
			
		||||
            var fileConfigFromConsul = await consulFileConfigRepo.Get();
 | 
			
		||||
            if (fileConfigFromConsul.Data == null)
 | 
			
		||||
            {
 | 
			
		||||
                config = await setter.Set(fileConfig.Value);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                var ocelotConfig = await ocelotConfigurationCreator.Create(fileConfigFromConsul.Data);
 | 
			
		||||
                if(ocelotConfig.IsError)
 | 
			
		||||
                {
 | 
			
		||||
                    return new ErrorResponse(ocelotConfig.Errors);
 | 
			
		||||
                }
 | 
			
		||||
                config = await ocelotConfigurationRepository.AddOrReplace(ocelotConfig.Data);
 | 
			
		||||
                var hack = builder.ApplicationServices.GetService(typeof(ConsulFileConfigurationPoller));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return new OkResponse();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static async Task CreateAdministrationArea(IApplicationBuilder builder, IOcelotConfiguration configuration)
 | 
			
		||||
        {
 | 
			
		||||
            var identityServerConfiguration = (IIdentityServerConfiguration)builder.ApplicationServices.GetService(typeof(IIdentityServerConfiguration));
 | 
			
		||||
 | 
			
		||||
            if(!string.IsNullOrEmpty(configuration.AdministrationPath) && identityServerConfiguration != null)
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,6 @@ namespace Ocelot.Requester
 | 
			
		||||
 | 
			
		||||
        private HttpMessageHandler CreateHttpMessageHandler(HttpMessageHandler httpMessageHandler)
 | 
			
		||||
        {            
 | 
			
		||||
   
 | 
			
		||||
            _handlers
 | 
			
		||||
                .OrderByDescending(handler => handler.Key)
 | 
			
		||||
                .Select(handler => handler.Value)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										17
									
								
								src/Ocelot/Requester/QoS/CircuitBreaker.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/Ocelot/Requester/QoS/CircuitBreaker.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								src/Ocelot/Requester/QoS/IQoSProvider.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/Ocelot/Requester/QoS/IQoSProvider.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
namespace Ocelot.Requester.QoS
 | 
			
		||||
{
 | 
			
		||||
    public interface IQoSProvider
 | 
			
		||||
    {
 | 
			
		||||
        CircuitBreaker CircuitBreaker { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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<PollyQoSProvider>();
 | 
			
		||||
 | 
			
		||||
            _timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromMilliseconds(reRoute.QosOptionsOptions.TimeoutValue), reRoute.QosOptionsOptions.TimeoutStrategy);
 | 
			
		||||
 | 
			
		||||
            _circuitBreakerPolicy = Policy
 | 
			
		||||
                .Handle<HttpRequestException>()
 | 
			
		||||
                .Or<TimeoutRejectedException>()
 | 
			
		||||
                .Or<TimeoutException>()
 | 
			
		||||
                .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<IQoSProvider> Get(string key);
 | 
			
		||||
        Response Add(string key, IQoSProvider loadBalancer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class QosProviderHouse : IQosProviderHouse
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Dictionary<string, IQoSProvider> _qoSProviders;
 | 
			
		||||
 | 
			
		||||
        public QosProviderHouse()
 | 
			
		||||
        {
 | 
			
		||||
            _qoSProviders = new Dictionary<string, IQoSProvider>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Response<IQoSProvider> Get(string key)
 | 
			
		||||
        {
 | 
			
		||||
            IQoSProvider qoSProvider;
 | 
			
		||||
 | 
			
		||||
            if (_qoSProviders.TryGetValue(key, out qoSProvider))
 | 
			
		||||
            {
 | 
			
		||||
                return new OkResponse<IQoSProvider>(_qoSProviders[key]);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return new ErrorResponse<IQoSProvider>(new List<Ocelot.Errors.Error>()
 | 
			
		||||
            {
 | 
			
		||||
                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();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								src/Ocelot/Requester/QoS/IQosProviderHouse.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/Ocelot/Requester/QoS/IQosProviderHouse.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Requester.QoS
 | 
			
		||||
{
 | 
			
		||||
    public interface IQosProviderHouse
 | 
			
		||||
    {
 | 
			
		||||
        Response<IQoSProvider> Get(ReRoute reRoute);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								src/Ocelot/Requester/QoS/NoQoSProvider.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/Ocelot/Requester/QoS/NoQoSProvider.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
namespace Ocelot.Requester.QoS
 | 
			
		||||
{
 | 
			
		||||
    public class NoQoSProvider : IQoSProvider
 | 
			
		||||
    {
 | 
			
		||||
        public CircuitBreaker CircuitBreaker { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										51
									
								
								src/Ocelot/Requester/QoS/PollyQoSProvider.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/Ocelot/Requester/QoS/PollyQoSProvider.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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<PollyQoSProvider>();
 | 
			
		||||
 | 
			
		||||
            _timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromMilliseconds(reRoute.QosOptionsOptions.TimeoutValue), reRoute.QosOptionsOptions.TimeoutStrategy);
 | 
			
		||||
 | 
			
		||||
            _circuitBreakerPolicy = Policy
 | 
			
		||||
                .Handle<HttpRequestException>()
 | 
			
		||||
                .Or<TimeoutRejectedException>()
 | 
			
		||||
                .Or<TimeoutException>()
 | 
			
		||||
                .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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								src/Ocelot/Requester/QoS/QoSProviderFactory.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/Ocelot/Requester/QoS/QoSProviderFactory.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										53
									
								
								src/Ocelot/Requester/QoS/QosProviderHouse.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/Ocelot/Requester/QoS/QosProviderHouse.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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<string, IQoSProvider> _qoSProviders;
 | 
			
		||||
        private readonly IQoSProviderFactory _qoSProviderFactory;
 | 
			
		||||
 | 
			
		||||
        public QosProviderHouse(IQoSProviderFactory qoSProviderFactory)
 | 
			
		||||
        {
 | 
			
		||||
            _qoSProviderFactory = qoSProviderFactory;
 | 
			
		||||
            _qoSProviders = new ConcurrentDictionary<string, IQoSProvider>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Response<IQoSProvider> 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<IQoSProvider>(_qoSProviders[reRoute.ReRouteKey]);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                qosProvider = _qoSProviderFactory.Get(reRoute);
 | 
			
		||||
                Add(reRoute.ReRouteKey, qosProvider);
 | 
			
		||||
                return new OkResponse<IQoSProvider>(qosProvider);
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                return new ErrorResponse<IQoSProvider>(new List<Ocelot.Errors.Error>()
 | 
			
		||||
                {
 | 
			
		||||
                    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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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; }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -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<List<Service>> 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);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,6 @@ namespace Ocelot.ServiceDiscovery
 | 
			
		||||
{
 | 
			
		||||
    public interface IServiceDiscoveryProviderFactory
 | 
			
		||||
    {
 | 
			
		||||
        IServiceDiscoveryProvider Get(ServiceProviderConfiguration serviceConfig);
 | 
			
		||||
        IServiceDiscoveryProvider Get(ServiceProviderConfiguration serviceConfig, ReRoute reRoute);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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.ServiceProviderHost, serviceConfig.ServiceProviderPort);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var services = new List<Service>()
 | 
			
		||||
            {
 | 
			
		||||
                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])
 | 
			
		||||
@@ -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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,17 +0,0 @@
 | 
			
		||||
namespace Ocelot.Utilities
 | 
			
		||||
{
 | 
			
		||||
    public static class StringExtensions
 | 
			
		||||
    {
 | 
			
		||||
        public static string SetLastCharacterAs(this string valueToSetLastChar, 
 | 
			
		||||
            char expectedLastChar)
 | 
			
		||||
        {
 | 
			
		||||
            var last = valueToSetLastChar[valueToSetLastChar.Length - 1];
 | 
			
		||||
 | 
			
		||||
            if (last != expectedLastChar)
 | 
			
		||||
            {
 | 
			
		||||
                valueToSetLastChar = $"{valueToSetLastChar}{expectedLastChar}";
 | 
			
		||||
            }
 | 
			
		||||
            return valueToSetLastChar;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										58
									
								
								test/Ocelot.AcceptanceTests/CannotStartOcelotTests.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								test/Ocelot.AcceptanceTests/CannotStartOcelotTests.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using Microsoft.AspNetCore.Hosting;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.AcceptanceTests
 | 
			
		||||
{
 | 
			
		||||
    public class CannotStartOcelotTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private IWebHost _builder;
 | 
			
		||||
        private readonly Steps _steps;
 | 
			
		||||
        private string _downstreamPath;
 | 
			
		||||
 | 
			
		||||
        public CannotStartOcelotTests()
 | 
			
		||||
        {
 | 
			
		||||
            _steps = new Steps();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_throw_exception_if_cannot_start()
 | 
			
		||||
        {
 | 
			
		||||
            var invalidConfig = new FileConfiguration()
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                {
 | 
			
		||||
                    new FileReRoute
 | 
			
		||||
                    {
 | 
			
		||||
                        UpstreamPathTemplate = "api",
 | 
			
		||||
                        DownstreamPathTemplate = "test"
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            Exception exception = null;
 | 
			
		||||
            _steps.GivenThereIsAConfiguration(invalidConfig);
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                _steps.GivenOcelotIsRunning();
 | 
			
		||||
            }
 | 
			
		||||
            catch(Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                exception = ex;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            exception.ShouldNotBeNull();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            _builder?.Dispose();
 | 
			
		||||
            _steps.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,28 +1,30 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
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;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.AcceptanceTests
 | 
			
		||||
{
 | 
			
		||||
    public class ConfigurationInConsul : IDisposable
 | 
			
		||||
    public class ConfigurationInConsulTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private IWebHost _builder;
 | 
			
		||||
        private readonly Steps _steps;
 | 
			
		||||
        private IWebHost _fakeConsulBuilder;
 | 
			
		||||
        private IOcelotConfiguration _config;
 | 
			
		||||
        private FileConfiguration _config;
 | 
			
		||||
 | 
			
		||||
        public ConfigurationInConsul()
 | 
			
		||||
        public ConfigurationInConsulTests()
 | 
			
		||||
        {
 | 
			
		||||
            _steps = new Steps();
 | 
			
		||||
        }
 | 
			
		||||
@@ -48,7 +50,6 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                {
 | 
			
		||||
                    ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
 | 
			
		||||
                    {
 | 
			
		||||
                        Provider = "Consul",
 | 
			
		||||
                        Host = "localhost",
 | 
			
		||||
                        Port = 9500
 | 
			
		||||
                    }
 | 
			
		||||
@@ -57,18 +58,162 @@ 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 => 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"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_load_configuration_out_of_consul()
 | 
			
		||||
        {
 | 
			
		||||
            var consulPort = 8500;
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                GlobalConfiguration = new FileGlobalConfiguration()
 | 
			
		||||
                {
 | 
			
		||||
                    ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
 | 
			
		||||
                    {
 | 
			
		||||
                        Host = "localhost",
 | 
			
		||||
                        Port = consulPort
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}";
 | 
			
		||||
 | 
			
		||||
            var consulConfig = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                {
 | 
			
		||||
                    new FileReRoute
 | 
			
		||||
                    {
 | 
			
		||||
                        DownstreamPathTemplate = "/status",
 | 
			
		||||
                        DownstreamScheme = "http",
 | 
			
		||||
                        DownstreamHost = "localhost",
 | 
			
		||||
                        DownstreamPort = 51779,
 | 
			
		||||
                        UpstreamPathTemplate = "/cs/status",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> {"Get"}
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                GlobalConfiguration = new FileGlobalConfiguration()
 | 
			
		||||
                {
 | 
			
		||||
                    ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
 | 
			
		||||
                    {
 | 
			
		||||
                        Host = "localhost",
 | 
			
		||||
                        Port = consulPort
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheConsulConfigurationIs(consulConfig))
 | 
			
		||||
                .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())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/cs/status"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_load_configuration_out_of_consul_if_it_is_changed()
 | 
			
		||||
        {
 | 
			
		||||
            var consulPort = 8506;
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                GlobalConfiguration = new FileGlobalConfiguration()
 | 
			
		||||
                {
 | 
			
		||||
                    ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
 | 
			
		||||
                    {
 | 
			
		||||
                        Host = "localhost",
 | 
			
		||||
                        Port = consulPort
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}";
 | 
			
		||||
 | 
			
		||||
            var consulConfig = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                {
 | 
			
		||||
                    new FileReRoute
 | 
			
		||||
                    {
 | 
			
		||||
                        DownstreamPathTemplate = "/status",
 | 
			
		||||
                        DownstreamScheme = "http",
 | 
			
		||||
                        DownstreamHost = "localhost",
 | 
			
		||||
                        DownstreamPort = 51779,
 | 
			
		||||
                        UpstreamPathTemplate = "/cs/status",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> {"Get"}
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                GlobalConfiguration = new FileGlobalConfiguration()
 | 
			
		||||
                {
 | 
			
		||||
                    ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
 | 
			
		||||
                    {
 | 
			
		||||
                        Host = "localhost",
 | 
			
		||||
                        Port = consulPort
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var secondConsulConfig = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                {
 | 
			
		||||
                    new FileReRoute
 | 
			
		||||
                    {
 | 
			
		||||
                        DownstreamPathTemplate = "/status",
 | 
			
		||||
                        DownstreamScheme = "http",
 | 
			
		||||
                        DownstreamHost = "localhost",
 | 
			
		||||
                        DownstreamPort = 51779,
 | 
			
		||||
                        UpstreamPathTemplate = "/cs/status/awesome",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> {"Get"}
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                GlobalConfiguration = new FileGlobalConfiguration()
 | 
			
		||||
                {
 | 
			
		||||
                    ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
 | 
			
		||||
                    {
 | 
			
		||||
                        Host = "localhost",
 | 
			
		||||
                        Port = consulPort
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheConsulConfigurationIs(consulConfig))
 | 
			
		||||
                .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())
 | 
			
		||||
                .And(x => _steps.WhenIGetUrlOnTheApiGateway("/cs/status"))
 | 
			
		||||
                .And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .And(x => GivenTheConsulConfigurationIs(secondConsulConfig))
 | 
			
		||||
                .And(x => GivenIWaitForTheConfigToReplicateToOcelot())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/cs/status/awesome"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenIWaitForTheConfigToReplicateToOcelot()
 | 
			
		||||
        {
 | 
			
		||||
            Thread.Sleep(10000);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheConsulConfigurationIs(FileConfiguration config)
 | 
			
		||||
        {
 | 
			
		||||
            _config = config;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url)
 | 
			
		||||
        {
 | 
			
		||||
            _fakeConsulBuilder = new WebHostBuilder()
 | 
			
		||||
@@ -102,7 +247,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
 | 
			
		||||
                                            var json = reader.ReadToEnd();
 | 
			
		||||
 | 
			
		||||
                                            _config = JsonConvert.DeserializeObject<OcelotConfiguration>(json);
 | 
			
		||||
                                            _config = JsonConvert.DeserializeObject<FileConfiguration>(json);
 | 
			
		||||
 | 
			
		||||
                                            var response = JsonConvert.SerializeObject(true);
 | 
			
		||||
 | 
			
		||||
@@ -137,7 +282,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 +292,8 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                .UseUrls(url)
 | 
			
		||||
                .Configure(app =>
 | 
			
		||||
                {
 | 
			
		||||
                    app.UsePathBase(basePath);
 | 
			
		||||
 | 
			
		||||
                    app.Run(async context =>
 | 
			
		||||
                    {
 | 
			
		||||
                        context.Response.StatusCode = statusCode;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										47
									
								
								test/Ocelot.AcceptanceTests/ConsulStartup.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								test/Ocelot.AcceptanceTests/ConsulStartup.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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 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<ConfigurationBuilderCachePart> settings = (x) =>
 | 
			
		||||
            {
 | 
			
		||||
                x.WithDictionaryHandle();
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            services.AddOcelot(Configuration).AddStoreOcelotConfigurationInConsul();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
 | 
			
		||||
        {
 | 
			
		||||
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
 | 
			
		||||
 | 
			
		||||
            app.UseOcelot().Wait();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -159,7 +159,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_care_about_no_trailing()
 | 
			
		||||
        public void should_return_ok_when_upstream_url_ends_with_forward_slash_but_template_does_not()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
@@ -187,7 +187,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_care_about_trailing()
 | 
			
		||||
        public void should_return_not_found_when_upstream_url_ends_with_forward_slash_but_template_does_not()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
@@ -209,8 +209,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/products/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -483,6 +482,41 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_fix_145()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/api/{url}",
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHost = "localhost",
 | 
			
		||||
                            DownstreamPort = 51899,
 | 
			
		||||
                            UpstreamPathTemplate = "/platform/{url}",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            QoSOptions = new FileQoSOptions {
 | 
			
		||||
                                ExceptionsAllowedBeforeBreaking = 3,
 | 
			
		||||
                                DurationOfBreak = 10,
 | 
			
		||||
                                TimeoutValue = 5000
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51899", "", 200, "Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/platform/swagger/lib/backbone-min.js"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .And(x => ThenTheDownstreamUrlPathShouldBe("/api/swagger/lib/backbone-min.js"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody)
 | 
			
		||||
        {
 | 
			
		||||
            _builder = new WebHostBuilder()
 | 
			
		||||
@@ -495,7 +529,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                    app.UsePathBase(basePath);
 | 
			
		||||
                    app.Run(async context =>
 | 
			
		||||
                    {   
 | 
			
		||||
                        _downstreamPath = context.Request.PathBase.Value;
 | 
			
		||||
                        _downstreamPath = !string.IsNullOrEmpty(context.Request.PathBase.Value) ? context.Request.PathBase.Value : context.Request.Path.Value;
 | 
			
		||||
                        context.Response.StatusCode = statusCode;
 | 
			
		||||
                        await context.Response.WriteAsync(responseBody);
 | 
			
		||||
                    });
 | 
			
		||||
 
 | 
			
		||||
@@ -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()
 | 
			
		||||
@@ -72,15 +73,15 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            ServiceName = serviceName,
 | 
			
		||||
                            LoadBalancer = "LeastConnection",
 | 
			
		||||
                            UseServiceDiscovery = true,
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    GlobalConfiguration = new FileGlobalConfiguration()
 | 
			
		||||
                    {
 | 
			
		||||
                        ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
 | 
			
		||||
                        {
 | 
			
		||||
                            Provider = "Consul",
 | 
			
		||||
                            Host = "localhost",
 | 
			
		||||
                            Port = 8500
 | 
			
		||||
                            Port = consulPort
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
@@ -99,8 +100,8 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
 | 
			
		||||
        private void ThenBothServicesCalledRealisticAmountOfTimes()
 | 
			
		||||
        {
 | 
			
		||||
            _counterOne.ShouldBe(25);
 | 
			
		||||
            _counterTwo.ShouldBe(25);
 | 
			
		||||
            _counterOne.ShouldBeInRange(24,26);
 | 
			
		||||
            _counterOne.ShouldBeInRange(24,26);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheTwoServicesShouldHaveBeenCalledTimes(int expected)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										47
									
								
								test/Ocelot.AcceptanceTests/Startup.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								test/Ocelot.AcceptanceTests/Startup.cs
									
									
									
									
									
										Normal file
									
								
							@@ -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<ConfigurationBuilderCachePart> settings = (x) =>
 | 
			
		||||
            {
 | 
			
		||||
                x.WithDictionaryHandle();
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            services.AddOcelot(Configuration);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
 | 
			
		||||
        {
 | 
			
		||||
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
 | 
			
		||||
 | 
			
		||||
            app.UseOcelot().Wait();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -107,18 +107,17 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
            _ocelotClient = _ocelotServer.CreateClient();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void GivenOcelotIsRunningUsingConsulToStoreConfig(ConsulRegistryConfiguration consulConfig)
 | 
			
		||||
        public void GivenOcelotIsRunningUsingConsulToStoreConfig()
 | 
			
		||||
        {
 | 
			
		||||
            _webHostBuilder = new WebHostBuilder();
 | 
			
		||||
 | 
			
		||||
            _webHostBuilder.ConfigureServices(s =>
 | 
			
		||||
            {
 | 
			
		||||
                s.AddSingleton(_webHostBuilder);
 | 
			
		||||
                s.AddOcelotStoreConfigurationInConsul(consulConfig);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            _ocelotServer = new TestServer(_webHostBuilder
 | 
			
		||||
                .UseStartup<Startup>());
 | 
			
		||||
                .UseStartup<ConsulStartup>());
 | 
			
		||||
 | 
			
		||||
            _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++)
 | 
			
		||||
            {
 | 
			
		||||
@@ -175,7 +173,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                        .WithDictionaryHandle();
 | 
			
		||||
                    };
 | 
			
		||||
                    
 | 
			
		||||
                    s.AddOcelot(configuration, settings);
 | 
			
		||||
                    s.AddOcelot(configuration);
 | 
			
		||||
                })
 | 
			
		||||
                .ConfigureLogging(l =>
 | 
			
		||||
                {
 | 
			
		||||
@@ -381,42 +379,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<ConfigurationBuilderCachePart> 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();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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++)
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@ namespace Ocelot.IntegrationTests
 | 
			
		||||
                    .WithDictionaryHandle();
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            services.AddOcelot(Configuration, settings);
 | 
			
		||||
            services.AddOcelot(Configuration);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
 | 
			
		||||
 
 | 
			
		||||
@@ -45,7 +45,7 @@ namespace Ocelot.ManualTest
 | 
			
		||||
                    x.Audience = "test";
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            services.AddOcelot(Configuration, settings);
 | 
			
		||||
            services.AddOcelot(Configuration);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
 | 
			
		||||
 
 | 
			
		||||
@@ -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<string> { "cheese" },
 | 
			
		||||
                    
 | 
			
		||||
//                 }
 | 
			
		||||
//             };
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_auth_options()
 | 
			
		||||
        {
 | 
			
		||||
            var fileReRoute = new FileReRoute()
 | 
			
		||||
            {
 | 
			
		||||
                AuthenticationOptions = new FileAuthenticationOptions
 | 
			
		||||
                {
 | 
			
		||||
                    AuthenticationProviderKey = "Test",
 | 
			
		||||
                    AllowedScopes = new List<string> { "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<string> { "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);
 | 
			
		||||
//         }
 | 
			
		||||
//     }
 | 
			
		||||
// }
 | 
			
		||||
        private void ThenTheFollowingConfigIsReturned(AuthenticationOptions expected)
 | 
			
		||||
        {
 | 
			
		||||
           _result.AllowedScopes.ShouldBe(expected.AllowedScopes);
 | 
			
		||||
            _result.AuthenticationProviderKey.ShouldBe(expected.AuthenticationProviderKey);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,89 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using Ocelot.Configuration.Repository;
 | 
			
		||||
using Ocelot.Configuration.Setter;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using static Ocelot.UnitTests.Wait;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
{
 | 
			
		||||
    public class ConsulFileConfigurationPollerTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private ConsulFileConfigurationPoller _poller;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _factory;
 | 
			
		||||
        private Mock<IFileConfigurationRepository> _repo;
 | 
			
		||||
        private Mock<IFileConfigurationSetter> _setter;
 | 
			
		||||
        private FileConfiguration _fileConfig;
 | 
			
		||||
 | 
			
		||||
        public ConsulFileConfigurationPollerTests()
 | 
			
		||||
        {
 | 
			
		||||
            var logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _factory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _factory.Setup(x => x.CreateLogger<ConsulFileConfigurationPoller>()).Returns(logger.Object);
 | 
			
		||||
            _repo = new Mock<IFileConfigurationRepository>();
 | 
			
		||||
            _setter = new Mock<IFileConfigurationSetter>();
 | 
			
		||||
            _fileConfig = new FileConfiguration();
 | 
			
		||||
            _repo.Setup(x => x.Get()).ReturnsAsync(new OkResponse<FileConfiguration>(_fileConfig));
 | 
			
		||||
            _poller = new ConsulFileConfigurationPoller(_factory.Object, _repo.Object, _setter.Object);
 | 
			
		||||
        }
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            _poller.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_start()
 | 
			
		||||
        {
 | 
			
		||||
           this.Given(x => ThenTheSetterIsCalled(_fileConfig))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_setter_when_gets_new_config()
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
            var newConfig = new FileConfiguration {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                {   
 | 
			
		||||
                    new FileReRoute
 | 
			
		||||
                    {
 | 
			
		||||
                        DownstreamHost = "test"
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => WhenTheConfigIsChangedInConsul(newConfig))
 | 
			
		||||
                .Then(x => ThenTheSetterIsCalled(newConfig))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenTheConfigIsChangedInConsul(FileConfiguration newConfig)
 | 
			
		||||
        {
 | 
			
		||||
            _repo.Setup(x => x.Get()).ReturnsAsync(new OkResponse<FileConfiguration>(newConfig));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheSetterIsCalled(FileConfiguration fileConfig)
 | 
			
		||||
        {
 | 
			
		||||
            var result = WaitFor(2000).Until(() => {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    _setter.Verify(x => x.Set(fileConfig), Times.Once);
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                catch(Exception ex)
 | 
			
		||||
                {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            result.ShouldBeTrue();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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,7 @@ using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
{
 | 
			
		||||
    using System.Collections;
 | 
			
		||||
 | 
			
		||||
    using Ocelot.Errors;
 | 
			
		||||
    using Ocelot.UnitTests.TestData;
 | 
			
		||||
 | 
			
		||||
    public class FileConfigurationCreatorTests
 | 
			
		||||
@@ -30,12 +26,6 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
        private FileConfiguration _fileConfiguration;
 | 
			
		||||
        private readonly Mock<IOcelotLoggerFactory> _logger;
 | 
			
		||||
        private readonly FileOcelotConfigurationCreator _ocelotConfigurationCreator;
 | 
			
		||||
        private readonly Mock<ILoadBalancerFactory> _loadBalancerFactory;
 | 
			
		||||
        private readonly Mock<ILoadBalancerHouse> _loadBalancerHouse;
 | 
			
		||||
        private readonly Mock<ILoadBalancer> _loadBalancer;
 | 
			
		||||
        private readonly Mock<IQoSProviderFactory> _qosProviderFactory;
 | 
			
		||||
        private readonly Mock<IQosProviderHouse> _qosProviderHouse;
 | 
			
		||||
        private readonly Mock<IQoSProvider> _qosProvider;
 | 
			
		||||
        private Mock<IClaimsToThingCreator> _claimsToThingCreator;
 | 
			
		||||
        private Mock<IAuthenticationOptionsCreator> _authOptionsCreator;
 | 
			
		||||
        private Mock<IUpstreamTemplatePatternCreator> _upstreamTemplatePatternCreator;
 | 
			
		||||
@@ -49,15 +39,9 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
 | 
			
		||||
        public FileConfigurationCreatorTests()
 | 
			
		||||
        {
 | 
			
		||||
            _qosProviderFactory = new Mock<IQoSProviderFactory>();
 | 
			
		||||
            _qosProviderHouse = new Mock<IQosProviderHouse>();
 | 
			
		||||
            _qosProvider = new Mock<IQoSProvider>();
 | 
			
		||||
            _logger = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _validator = new Mock<IConfigurationValidator>();
 | 
			
		||||
            _fileConfig = new Mock<IOptions<FileConfiguration>>();
 | 
			
		||||
            _loadBalancerFactory = new Mock<ILoadBalancerFactory>();
 | 
			
		||||
            _loadBalancerHouse = new Mock<ILoadBalancerHouse>();
 | 
			
		||||
            _loadBalancer = new Mock<ILoadBalancer>();
 | 
			
		||||
            _claimsToThingCreator = new Mock<IClaimsToThingCreator>();
 | 
			
		||||
            _authOptionsCreator = new Mock<IAuthenticationOptionsCreator>();
 | 
			
		||||
            _upstreamTemplatePatternCreator = new Mock<IUpstreamTemplatePatternCreator>();
 | 
			
		||||
@@ -71,13 +55,35 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
 | 
			
		||||
            _ocelotConfigurationCreator = new FileOcelotConfigurationCreator( 
 | 
			
		||||
                _fileConfig.Object, _validator.Object, _logger.Object,
 | 
			
		||||
                _loadBalancerFactory.Object, _loadBalancerHouse.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);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [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,
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }))
 | 
			
		||||
                .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()
 | 
			
		||||
        {
 | 
			
		||||
@@ -109,19 +115,6 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFollowingRegionIsReturned(string region)
 | 
			
		||||
        {
 | 
			
		||||
            _regionCreator
 | 
			
		||||
                .Setup(x => x.Create(It.IsAny<FileReRoute>()))
 | 
			
		||||
                .Returns(region);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheRegionCreatorIsCalledCorrectly(string expected)
 | 
			
		||||
        {
 | 
			
		||||
            _regionCreator
 | 
			
		||||
                .Verify(x => x.Create(_fileConfiguration.ReRoutes[0]), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_rate_limit_options_creator()
 | 
			
		||||
        {
 | 
			
		||||
@@ -182,43 +175,12 @@ 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();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_create_load_balancer()
 | 
			
		||||
        {
 | 
			
		||||
            var reRouteOptions = new ReRouteOptionsBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheConfigIs(new FileConfiguration
 | 
			
		||||
                            {
 | 
			
		||||
                                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                                {
 | 
			
		||||
                                    new FileReRoute
 | 
			
		||||
                                    {
 | 
			
		||||
                                        DownstreamHost = "127.0.0.1",
 | 
			
		||||
                                        UpstreamPathTemplate = "/api/products/{productId}",
 | 
			
		||||
                                        DownstreamPathTemplate = "/products/{productId}",
 | 
			
		||||
                                        UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                                    }
 | 
			
		||||
                                },
 | 
			
		||||
                            }))
 | 
			
		||||
                                .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())
 | 
			
		||||
                    .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_use_downstream_host()
 | 
			
		||||
        {
 | 
			
		||||
@@ -310,7 +272,6 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                            {
 | 
			
		||||
                                ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
 | 
			
		||||
                                {
 | 
			
		||||
                                     Provider = "consul",
 | 
			
		||||
                                     Host = "127.0.0.1"
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
@@ -324,12 +285,8 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                                    .WithDownstreamPathTemplate("/products/{productId}")
 | 
			
		||||
                                    .WithUpstreamPathTemplate("/api/products/{productId}")
 | 
			
		||||
                                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                                    .WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                                        .WithUseServiceDiscovery(true)
 | 
			
		||||
                                        .WithServiceDiscoveryProvider("consul")
 | 
			
		||||
                                        .WithServiceDiscoveryProviderHost("127.0.0.1")
 | 
			
		||||
                                        .WithServiceName("ProductService")
 | 
			
		||||
                                        .Build())
 | 
			
		||||
                                    .WithUseServiceDiscovery(true)
 | 
			
		||||
                                    .WithServiceName("ProductService")
 | 
			
		||||
                                    .Build()
 | 
			
		||||
                            }))
 | 
			
		||||
                            .BDDfy();
 | 
			
		||||
@@ -363,9 +320,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                                    .WithDownstreamPathTemplate("/products/{productId}")
 | 
			
		||||
                                    .WithUpstreamPathTemplate("/api/products/{productId}")
 | 
			
		||||
                                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                                    .WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                                        .WithUseServiceDiscovery(false)
 | 
			
		||||
                                        .Build())
 | 
			
		||||
                                    .WithUseServiceDiscovery(false)
 | 
			
		||||
                                    .Build()
 | 
			
		||||
                            }))
 | 
			
		||||
                            .BDDfy();
 | 
			
		||||
@@ -474,17 +429,6 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFollowingHttpHandlerOptionsAreReturned(HttpHandlerOptions httpHandlerOptions)
 | 
			
		||||
        {
 | 
			
		||||
            _httpHandlerOptionsCreator.Setup(x => x.Create(It.IsAny<FileReRoute>()))
 | 
			
		||||
                .Returns(httpHandlerOptions);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheHttpHandlerOptionsCreatorIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _httpHandlerOptionsCreator.Verify(x => x.Create(_fileConfiguration.ReRoutes[0]), Times.Once());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [MemberData(nameof(AuthenticationConfigTestData.GetAuthenticationData), MemberType = typeof(AuthenticationConfigTestData))]
 | 
			
		||||
        public void should_create_with_headers_to_extract(FileConfiguration fileConfig)
 | 
			
		||||
@@ -516,7 +460,6 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                .And(x => x.GivenTheAuthOptionsCreatorReturns(authenticationOptions))
 | 
			
		||||
                .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
 | 
			
		||||
                .And(x => x.GivenTheClaimsToThingCreatorReturns(new List<ClaimToThing> { 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 +493,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))
 | 
			
		||||
@@ -558,6 +500,31 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_validation_errors()
 | 
			
		||||
        {
 | 
			
		||||
            var errors = new List<Error> {new PathTemplateDoesntStartWithForwardSlash("some message")};
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheConfigIs(new FileConfiguration()))
 | 
			
		||||
                .And(x => x.GivenTheConfigIsInvalid(errors))
 | 
			
		||||
                .When(x => x.WhenICreateTheConfig())
 | 
			
		||||
                .Then(x => x.ThenTheErrorsAreReturned(errors))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheConfigIsInvalid(List<Error> errors)
 | 
			
		||||
        {
 | 
			
		||||
            _validator
 | 
			
		||||
                .Setup(x => x.IsValid(It.IsAny<FileConfiguration>()))
 | 
			
		||||
                .ReturnsAsync(new OkResponse<ConfigurationValidationResult>(new ConfigurationValidationResult(true, errors)));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheErrorsAreReturned(List<Error> errors)
 | 
			
		||||
        {
 | 
			
		||||
            _config.IsError.ShouldBeTrue();
 | 
			
		||||
            _config.Errors[0].ShouldBe(errors[0]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFollowingOptionsAreReturned(ReRouteOptions fileReRouteOptions)
 | 
			
		||||
        {
 | 
			
		||||
            _fileReRouteOptionsCreator
 | 
			
		||||
@@ -588,7 +555,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
 | 
			
		||||
        private void WhenICreateTheConfig()
 | 
			
		||||
        {
 | 
			
		||||
            _config = _ocelotConfigurationCreator.Create().Result;
 | 
			
		||||
            _config = _ocelotConfigurationCreator.Create(_fileConfiguration).Result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheReRoutesAre(List<ReRoute> expectedReRoutes)
 | 
			
		||||
@@ -610,20 +577,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<ReRoute> expectedReRoutes)
 | 
			
		||||
        {
 | 
			
		||||
            for (int i = 0; i < _config.Data.ReRoutes.Count; i++)
 | 
			
		||||
@@ -634,44 +587,6 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheLoadBalancerFactoryReturns()
 | 
			
		||||
        {
 | 
			
		||||
            _loadBalancerFactory
 | 
			
		||||
                .Setup(x => x.Get(It.IsAny<ReRoute>()))
 | 
			
		||||
                .ReturnsAsync(_loadBalancer.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void TheLoadBalancerFactoryIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _loadBalancerFactory
 | 
			
		||||
                .Verify(x => x.Get(It.IsAny<ReRoute>()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheLoadBalancerHouseIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _loadBalancerHouse
 | 
			
		||||
                .Verify(x => x.Add(It.IsAny<string>(), _loadBalancer.Object), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheQosProviderFactoryReturns()
 | 
			
		||||
        {
 | 
			
		||||
            _qosProviderFactory
 | 
			
		||||
                .Setup(x => x.Get(It.IsAny<ReRoute>()))
 | 
			
		||||
                .Returns(_qosProvider.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void TheQosProviderFactoryIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _qosProviderFactory
 | 
			
		||||
                .Verify(x => x.Get(It.IsAny<ReRoute>()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheQosProviderHouseIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _qosProviderHouse
 | 
			
		||||
                .Verify(x => x.Add(It.IsAny<string>(), _qosProvider.Object), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheClaimsToThingCreatorReturns(List<ClaimToThing> claimsToThing)
 | 
			
		||||
        {
 | 
			
		||||
            _claimsToThingCreator
 | 
			
		||||
@@ -726,5 +641,42 @@ 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<FileGlobalConfiguration>())).Returns(serviceProviderConfiguration);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        private void GivenTheFollowingRegionIsReturned(string region)
 | 
			
		||||
        {
 | 
			
		||||
            _regionCreator
 | 
			
		||||
                .Setup(x => x.Create(It.IsAny<FileReRoute>()))
 | 
			
		||||
                .Returns(region);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheRegionCreatorIsCalledCorrectly(string expected)
 | 
			
		||||
        {
 | 
			
		||||
            _regionCreator
 | 
			
		||||
                .Verify(x => x.Create(_fileConfiguration.ReRoutes[0]), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        private void GivenTheFollowingHttpHandlerOptionsAreReturned(HttpHandlerOptions httpHandlerOptions)
 | 
			
		||||
        {
 | 
			
		||||
            _httpHandlerOptionsCreator.Setup(x => x.Create(It.IsAny<FileReRoute>()))
 | 
			
		||||
                .Returns(httpHandlerOptions);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheHttpHandlerOptionsCreatorIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _httpHandlerOptionsCreator.Verify(x => x.Create(_fileConfiguration.ReRoutes[0]), Times.Once());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -45,12 +45,12 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
            _fileConfiguration = fileConfiguration;
 | 
			
		||||
            _repo
 | 
			
		||||
                .Setup(x => x.Get())
 | 
			
		||||
                .Returns(new OkResponse<FileConfiguration>(fileConfiguration));
 | 
			
		||||
                .ReturnsAsync(new OkResponse<FileConfiguration>(fileConfiguration));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIGetTheReRoutes()
 | 
			
		||||
        {
 | 
			
		||||
            _result = _provider.Get().Data;
 | 
			
		||||
            _result = _provider.Get().Result.Data;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheRepoIsCalledCorrectly()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,31 +1,176 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
using Newtonsoft.Json;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using Microsoft.AspNetCore.Hosting;
 | 
			
		||||
using Ocelot.Configuration.Repository;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
{
 | 
			
		||||
    public class FileConfigurationRepositoryTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IFileConfigurationRepository _repo;
 | 
			
		||||
        private readonly Mock<IHostingEnvironment> _hostingEnvironment = new Mock<IHostingEnvironment>();
 | 
			
		||||
        private IFileConfigurationRepository _repo;
 | 
			
		||||
        private FileConfiguration _result;
 | 
			
		||||
        private FileConfiguration _fileConfiguration;
 | 
			
		||||
        private string _environmentName = "DEV";
 | 
			
		||||
 | 
			
		||||
        public FileConfigurationRepositoryTests()
 | 
			
		||||
        {
 | 
			
		||||
            _repo = new FileConfigurationRepository();
 | 
			
		||||
            _hostingEnvironment.Setup(he => he.EnvironmentName).Returns(_environmentName);
 | 
			
		||||
            _repo = new FileConfigurationRepository(_hostingEnvironment.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_file_configuration()
 | 
			
		||||
        {
 | 
			
		||||
            var config = FakeFileConfigurationForGet();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheConfigurationIs(config))
 | 
			
		||||
                .When(x => x.WhenIGetTheReRoutes())
 | 
			
		||||
                .Then(x => x.ThenTheFollowingIsReturned(config))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_file_configuration_if_environment_name_is_unavailable()
 | 
			
		||||
        {
 | 
			
		||||
            var config = FakeFileConfigurationForGet();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheEnvironmentNameIsUnavailable())
 | 
			
		||||
                .And(x => x.GivenTheConfigurationIs(config))
 | 
			
		||||
                .When(x => x.WhenIGetTheReRoutes())
 | 
			
		||||
                .Then(x => x.ThenTheFollowingIsReturned(config))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_set_file_configuration()
 | 
			
		||||
        {
 | 
			
		||||
            var config = FakeFileConfigurationForSet();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenIHaveAConfiguration(config))
 | 
			
		||||
                .When(x => WhenISetTheConfiguration())
 | 
			
		||||
                .Then(x => ThenTheConfigurationIsStoredAs(config))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_set_file_configuration_if_environment_name_is_unavailable()
 | 
			
		||||
        {
 | 
			
		||||
            var config = FakeFileConfigurationForSet();
 | 
			
		||||
            this.Given(x => GivenIHaveAConfiguration(config))
 | 
			
		||||
                .And(x => GivenTheEnvironmentNameIsUnavailable())
 | 
			
		||||
                .When(x => WhenISetTheConfiguration())
 | 
			
		||||
                .Then(x => ThenTheConfigurationIsStoredAs(config))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheEnvironmentNameIsUnavailable()
 | 
			
		||||
        {
 | 
			
		||||
            _environmentName = null;
 | 
			
		||||
            _hostingEnvironment.Setup(he => he.EnvironmentName).Returns(_environmentName);
 | 
			
		||||
            _repo = new FileConfigurationRepository(_hostingEnvironment.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenIHaveAConfiguration(FileConfiguration fileConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            _fileConfiguration = fileConfiguration;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenISetTheConfiguration()
 | 
			
		||||
        {
 | 
			
		||||
            _repo.Set(_fileConfiguration);
 | 
			
		||||
            _result = _repo.Get().Result.Data;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheConfigurationIsStoredAs(FileConfiguration expected)
 | 
			
		||||
        {
 | 
			
		||||
            _result.GlobalConfiguration.AdministrationPath.ShouldBe(expected.GlobalConfiguration.AdministrationPath);
 | 
			
		||||
            _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);
 | 
			
		||||
 | 
			
		||||
            for(var i = 0; i < _result.ReRoutes.Count; i++)
 | 
			
		||||
            {
 | 
			
		||||
                _result.ReRoutes[i].DownstreamHost.ShouldBe(expected.ReRoutes[i].DownstreamHost);
 | 
			
		||||
                _result.ReRoutes[i].DownstreamPathTemplate.ShouldBe(expected.ReRoutes[i].DownstreamPathTemplate);
 | 
			
		||||
                _result.ReRoutes[i].DownstreamPort.ShouldBe(expected.ReRoutes[i].DownstreamPort);
 | 
			
		||||
                _result.ReRoutes[i].DownstreamScheme.ShouldBe(expected.ReRoutes[i].DownstreamScheme);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void  GivenTheConfigurationIs(FileConfiguration fileConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            var configurationPath = $"{AppContext.BaseDirectory}/configuration{(string.IsNullOrEmpty(_environmentName) ? string.Empty : ".")}{_environmentName}.json";
 | 
			
		||||
 | 
			
		||||
            var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration);
 | 
			
		||||
 | 
			
		||||
            if (File.Exists(configurationPath))
 | 
			
		||||
            {
 | 
			
		||||
                File.Delete(configurationPath);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            File.WriteAllText(configurationPath, jsonConfiguration);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIGetTheReRoutes()
 | 
			
		||||
        {
 | 
			
		||||
            _result = _repo.Get().Result.Data;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheFollowingIsReturned(FileConfiguration expected)
 | 
			
		||||
        {
 | 
			
		||||
            _result.GlobalConfiguration.AdministrationPath.ShouldBe(expected.GlobalConfiguration.AdministrationPath);
 | 
			
		||||
            _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);
 | 
			
		||||
 | 
			
		||||
            for(var i = 0; i < _result.ReRoutes.Count; i++)
 | 
			
		||||
            {
 | 
			
		||||
                _result.ReRoutes[i].DownstreamHost.ShouldBe(expected.ReRoutes[i].DownstreamHost);
 | 
			
		||||
                _result.ReRoutes[i].DownstreamPathTemplate.ShouldBe(expected.ReRoutes[i].DownstreamPathTemplate);
 | 
			
		||||
                _result.ReRoutes[i].DownstreamPort.ShouldBe(expected.ReRoutes[i].DownstreamPort);
 | 
			
		||||
                _result.ReRoutes[i].DownstreamScheme.ShouldBe(expected.ReRoutes[i].DownstreamScheme);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private FileConfiguration FakeFileConfigurationForSet()
 | 
			
		||||
        {
 | 
			
		||||
            var reRoutes = new List<FileReRoute>
 | 
			
		||||
            {
 | 
			
		||||
                new FileReRoute
 | 
			
		||||
                {
 | 
			
		||||
                    DownstreamHost = "123.12.12.12",
 | 
			
		||||
                    DownstreamPort = 80,
 | 
			
		||||
                    DownstreamScheme = "https",
 | 
			
		||||
                    DownstreamPathTemplate = "/asdfs/test/{test}"
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var globalConfiguration = new FileGlobalConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                AdministrationPath = "asdas",
 | 
			
		||||
                ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
 | 
			
		||||
                {
 | 
			
		||||
                    Port = 198,
 | 
			
		||||
                    Host = "blah"
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            return new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                GlobalConfiguration = globalConfiguration,
 | 
			
		||||
                ReRoutes = reRoutes
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private FileConfiguration FakeFileConfigurationForGet()
 | 
			
		||||
        {
 | 
			
		||||
            var reRoutes = new List<FileReRoute>
 | 
			
		||||
            {
 | 
			
		||||
@@ -43,119 +188,16 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                AdministrationPath = "testy",
 | 
			
		||||
                ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
 | 
			
		||||
                {
 | 
			
		||||
                    Provider = "consul",
 | 
			
		||||
                    Port = 198,
 | 
			
		||||
                    Host = "blah"
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var config = new FileConfiguration();
 | 
			
		||||
            config.GlobalConfiguration = globalConfiguration;
 | 
			
		||||
            config.ReRoutes.AddRange(reRoutes);
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheConfigurationIs(config))
 | 
			
		||||
                .When(x => x.WhenIGetTheReRoutes())
 | 
			
		||||
                .Then(x => x.ThenTheFollowingIsReturned(config))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_set_file_configuration()
 | 
			
		||||
        {
 | 
			
		||||
             var reRoutes = new List<FileReRoute>
 | 
			
		||||
            return new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                new FileReRoute
 | 
			
		||||
                {
 | 
			
		||||
                    DownstreamHost = "123.12.12.12",
 | 
			
		||||
                    DownstreamPort = 80,
 | 
			
		||||
                    DownstreamScheme = "https",
 | 
			
		||||
                    DownstreamPathTemplate = "/asdfs/test/{test}"
 | 
			
		||||
                }
 | 
			
		||||
                GlobalConfiguration = globalConfiguration,
 | 
			
		||||
                ReRoutes = reRoutes
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var globalConfiguration = new FileGlobalConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                AdministrationPath = "asdas",
 | 
			
		||||
                ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
 | 
			
		||||
                {
 | 
			
		||||
                    Provider = "consul",
 | 
			
		||||
                    Port = 198,
 | 
			
		||||
                    Host = "blah"
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var config = new FileConfiguration();
 | 
			
		||||
            config.GlobalConfiguration = globalConfiguration;
 | 
			
		||||
            config.ReRoutes.AddRange(reRoutes);
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenIHaveAConfiguration(config))
 | 
			
		||||
                .When(x => WhenISetTheConfiguration())
 | 
			
		||||
                .Then(x => ThenTheConfigurationIsStoredAs(config))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenIHaveAConfiguration(FileConfiguration fileConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            _fileConfiguration = fileConfiguration;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenISetTheConfiguration()
 | 
			
		||||
        {
 | 
			
		||||
            _repo.Set(_fileConfiguration);
 | 
			
		||||
            _result = _repo.Get().Data;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheConfigurationIsStoredAs(FileConfiguration expected)
 | 
			
		||||
        {
 | 
			
		||||
            _result.GlobalConfiguration.AdministrationPath.ShouldBe(expected.GlobalConfiguration.AdministrationPath);
 | 
			
		||||
            _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++)
 | 
			
		||||
            {
 | 
			
		||||
                _result.ReRoutes[i].DownstreamHost.ShouldBe(expected.ReRoutes[i].DownstreamHost);
 | 
			
		||||
                _result.ReRoutes[i].DownstreamPathTemplate.ShouldBe(expected.ReRoutes[i].DownstreamPathTemplate);
 | 
			
		||||
                _result.ReRoutes[i].DownstreamPort.ShouldBe(expected.ReRoutes[i].DownstreamPort);
 | 
			
		||||
                _result.ReRoutes[i].DownstreamScheme.ShouldBe(expected.ReRoutes[i].DownstreamScheme);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheConfigurationIs(FileConfiguration fileConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            var configurationPath = $"{AppContext.BaseDirectory}/configuration.json";
 | 
			
		||||
 | 
			
		||||
            var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration);
 | 
			
		||||
 | 
			
		||||
            if (File.Exists(configurationPath))
 | 
			
		||||
            {
 | 
			
		||||
                File.Delete(configurationPath);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            File.WriteAllText(configurationPath, jsonConfiguration);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIGetTheReRoutes()
 | 
			
		||||
        {
 | 
			
		||||
            _result = _repo.Get().Data;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheFollowingIsReturned(FileConfiguration expected)
 | 
			
		||||
        {
 | 
			
		||||
            _result.GlobalConfiguration.AdministrationPath.ShouldBe(expected.GlobalConfiguration.AdministrationPath);
 | 
			
		||||
            _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++)
 | 
			
		||||
            {
 | 
			
		||||
                _result.ReRoutes[i].DownstreamHost.ShouldBe(expected.ReRoutes[i].DownstreamHost);
 | 
			
		||||
                _result.ReRoutes[i].DownstreamPathTemplate.ShouldBe(expected.ReRoutes[i].DownstreamPathTemplate);
 | 
			
		||||
                _result.ReRoutes[i].DownstreamPort.ShouldBe(expected.ReRoutes[i].DownstreamPort);
 | 
			
		||||
                _result.ReRoutes[i].DownstreamScheme.ShouldBe(expected.ReRoutes[i].DownstreamScheme);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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<ReRoute>(), string.Empty);
 | 
			
		||||
            var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
 | 
			
		||||
            var config = new OcelotConfiguration(new List<ReRoute>(), string.Empty, serviceProviderConfig);
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFollowingConfiguration(fileConfig))
 | 
			
		||||
                .And(x => GivenTheRepoReturns(new OkResponse()))
 | 
			
		||||
@@ -76,7 +78,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
        {
 | 
			
		||||
            _repo
 | 
			
		||||
                .Setup(x => x.Set(It.IsAny<FileConfiguration>()))
 | 
			
		||||
                .Returns(response);
 | 
			
		||||
                .ReturnsAsync(response);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenAnErrorResponseIsReturned()
 | 
			
		||||
 
 | 
			
		||||
@@ -92,6 +92,8 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            public string AdministrationPath {get;}
 | 
			
		||||
 | 
			
		||||
            public ServiceProviderConfiguration ServiceProviderConfiguration => throw new NotImplementedException();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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<IOcelotConfiguration>(new OcelotConfiguration(new List<ReRoute>(), string.Empty))))
 | 
			
		||||
            var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheRepoReturns(new OkResponse<IOcelotConfiguration>(new OcelotConfiguration(new List<ReRoute>(), string.Empty, serviceProviderConfig))))
 | 
			
		||||
                .When(x => x.WhenIGetTheConfig())
 | 
			
		||||
                .Then(x => x.TheFollowingIsReturned(new OkResponse<IOcelotConfiguration>(new OcelotConfiguration(new List<ReRoute>(), string.Empty))))
 | 
			
		||||
                .Then(x => x.TheFollowingIsReturned(new OkResponse<IOcelotConfiguration>(new OcelotConfiguration(new List<ReRoute>(), string.Empty, serviceProviderConfig))))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
@@ -60,15 +58,11 @@ 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);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,23 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
 | 
			
		||||
                .When(x => x.WhenICreateTheTemplatePattern())
 | 
			
		||||
                .Then(x => x.ThenTheFollowingIsReturned("^(?i)/PRODUCTS/.*/$"))
 | 
			
		||||
                .Then(x => x.ThenTheFollowingIsReturned("^(?i)/PRODUCTS/[0-9a-zA-Z].*$"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_match_forward_slash_or_no_forward_slash_if_template_end_with_forward_slash()
 | 
			
		||||
        {
 | 
			
		||||
            var fileReRoute = new FileReRoute
 | 
			
		||||
            {
 | 
			
		||||
                UpstreamPathTemplate = "/PRODUCTS/",
 | 
			
		||||
                ReRouteIsCaseSensitive = false
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
 | 
			
		||||
                .When(x => x.WhenICreateTheTemplatePattern())
 | 
			
		||||
                .Then(x => x.ThenTheFollowingIsReturned("^(?i)/PRODUCTS(/|)$"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -42,7 +58,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                };
 | 
			
		||||
            this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
 | 
			
		||||
                .When(x => x.WhenICreateTheTemplatePattern())
 | 
			
		||||
                .Then(x => x.ThenTheFollowingIsReturned("^/PRODUCTS/.*/$"))
 | 
			
		||||
                .Then(x => x.ThenTheFollowingIsReturned("^/PRODUCTS/[0-9a-zA-Z].*$"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -57,7 +73,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
 | 
			
		||||
                .When(x => x.WhenICreateTheTemplatePattern())
 | 
			
		||||
                .Then(x => x.ThenTheFollowingIsReturned("^/api/products/.*/$"))
 | 
			
		||||
                .Then(x => x.ThenTheFollowingIsReturned("^/api/products/[0-9a-zA-Z].*$"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -72,9 +88,10 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
 | 
			
		||||
                .When(x => x.WhenICreateTheTemplatePattern())
 | 
			
		||||
                .Then(x => x.ThenTheFollowingIsReturned("^/api/products/.*/variants/.*/$"))
 | 
			
		||||
                .Then(x => x.ThenTheFollowingIsReturned("^/api/products/[0-9a-zA-Z].*/variants/[0-9a-zA-Z].*$"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_create_template_pattern_that_matches_more_than_one_placeholder_with_trailing_slash()
 | 
			
		||||
        {
 | 
			
		||||
@@ -86,7 +103,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
 | 
			
		||||
                .When(x => x.WhenICreateTheTemplatePattern())
 | 
			
		||||
                .Then(x => x.ThenTheFollowingIsReturned("^/api/products/.*/variants/.*/$"))
 | 
			
		||||
                .Then(x => x.ThenTheFollowingIsReturned("^/api/products/[0-9a-zA-Z].*/variants/[0-9a-zA-Z].*(/|)$"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -107,12 +107,12 @@ namespace Ocelot.UnitTests.Controllers
 | 
			
		||||
        {
 | 
			
		||||
            _configGetter
 | 
			
		||||
                .Setup(x => x.Get())
 | 
			
		||||
                .Returns(fileConfiguration);
 | 
			
		||||
                .ReturnsAsync(fileConfiguration);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIGetTheFileConfiguration()
 | 
			
		||||
        {
 | 
			
		||||
            _result = _controller.Get();
 | 
			
		||||
            _result = _controller.Get().Result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void TheTheGetFileConfigurationIsCalledCorrectly()
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										135
									
								
								test/Ocelot.UnitTests/DependencyInjection/OcelotBuilderTests.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								test/Ocelot.UnitTests/DependencyInjection/OcelotBuilderTests.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,135 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using CacheManager.Core;
 | 
			
		||||
using Microsoft.AspNetCore.Hosting;
 | 
			
		||||
using Microsoft.Extensions.Configuration;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using Ocelot.Cache;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using Ocelot.DependencyInjection;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.DependencyInjection
 | 
			
		||||
{
 | 
			
		||||
    public class OcelotBuilderTests
 | 
			
		||||
    {
 | 
			
		||||
        private IServiceCollection _services;
 | 
			
		||||
        private IConfigurationRoot _configRoot;
 | 
			
		||||
        private IOcelotBuilder _ocelotBuilder;
 | 
			
		||||
        private int _maxRetries;
 | 
			
		||||
 | 
			
		||||
        public OcelotBuilderTests()
 | 
			
		||||
        {
 | 
			
		||||
                IWebHostBuilder builder = new WebHostBuilder();
 | 
			
		||||
                _configRoot = new ConfigurationRoot(new List<IConfigurationProvider>());
 | 
			
		||||
                _services = new ServiceCollection();
 | 
			
		||||
                _services.AddSingleton(builder);
 | 
			
		||||
                _maxRetries = 100;
 | 
			
		||||
        }
 | 
			
		||||
        private Exception _ex;
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_set_up_services()
 | 
			
		||||
        {
 | 
			
		||||
            this.When(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .Then(x => ThenAnExceptionIsntThrown())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_ocelot_builder()
 | 
			
		||||
        {
 | 
			
		||||
            this.When(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .Then(x => ThenAnOcelotBuilderIsReturned())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
       
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_set_up_cache_manager()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => WhenISetUpCacheManager())
 | 
			
		||||
                .Then(x => ThenAnExceptionIsntThrown())
 | 
			
		||||
                .And(x => OnlyOneVersionOfEachCacheIsRegistered())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_set_up_consul()
 | 
			
		||||
        {            
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => WhenISetUpConsul())
 | 
			
		||||
                .Then(x => ThenAnExceptionIsntThrown())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void OnlyOneVersionOfEachCacheIsRegistered()
 | 
			
		||||
        {
 | 
			
		||||
            var outputCache = _services.Single(x => x.ServiceType == typeof(IOcelotCache<HttpResponseMessage>));
 | 
			
		||||
            var outputCacheManager = _services.Single(x => x.ServiceType == typeof(ICacheManager<HttpResponseMessage>));
 | 
			
		||||
            var thing = (CacheManager.Core.ICacheManager<System.Net.Http.HttpResponseMessage>)outputCacheManager.ImplementationInstance;
 | 
			
		||||
            thing.Configuration.MaxRetries.ShouldBe(_maxRetries);
 | 
			
		||||
            
 | 
			
		||||
            var ocelotConfigCache = _services.Single(x => x.ServiceType == typeof(IOcelotCache<IOcelotConfiguration>));
 | 
			
		||||
            var ocelotConfigCacheManager = _services.Single(x => x.ServiceType == typeof(ICacheManager<IOcelotConfiguration>));
 | 
			
		||||
 | 
			
		||||
            var fileConfigCache = _services.Single(x => x.ServiceType == typeof(IOcelotCache<FileConfiguration>));
 | 
			
		||||
            var fileConfigCacheManager = _services.Single(x => x.ServiceType == typeof(ICacheManager<FileConfiguration>));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenISetUpConsul()
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                _ocelotBuilder.AddStoreOcelotConfigurationInConsul();
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception e)
 | 
			
		||||
            {
 | 
			
		||||
                _ex = e;
 | 
			
		||||
            }       
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenAnOcelotBuilderIsReturned()
 | 
			
		||||
        {
 | 
			
		||||
            _ocelotBuilder.ShouldBeOfType<OcelotBuilder>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenISetUpOcelotServices()
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                _ocelotBuilder = _services.AddOcelot(_configRoot);
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception e)
 | 
			
		||||
            {
 | 
			
		||||
                _ex = e;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        private void WhenISetUpCacheManager()
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                _ocelotBuilder.AddCacheManager(x => {
 | 
			
		||||
                    x.WithMaxRetries(_maxRetries);
 | 
			
		||||
                    x.WithDictionaryHandle();
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception e)
 | 
			
		||||
            {
 | 
			
		||||
                _ex = e;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenAnExceptionIsntThrown()
 | 
			
		||||
        {
 | 
			
		||||
            _ex.ShouldBeNull();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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<IDownstreamRouteFinder> _downstreamRouteFinder;
 | 
			
		||||
        private readonly Mock<IOcelotConfigurationProvider> _provider;
 | 
			
		||||
        private Response<DownstreamRoute> _downstreamRoute;
 | 
			
		||||
        private IOcelotConfiguration _config;
 | 
			
		||||
 | 
			
		||||
        public DownstreamRouteFinderMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _provider = new Mock<IOcelotConfigurationProvider>();
 | 
			
		||||
            _downstreamRouteFinder = new Mock<IDownstreamRouteFinder>();
 | 
			
		||||
 | 
			
		||||
            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<UrlPathPlaceholderNameAndValue>(), 
 | 
			
		||||
@@ -36,16 +43,26 @@
 | 
			
		||||
                        .WithDownstreamPathTemplate("any old string")
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "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<IOcelotConfiguration>(_config));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services)
 | 
			
		||||
        {
 | 
			
		||||
            services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
 | 
			
		||||
            services.AddLogging();
 | 
			
		||||
            services.AddSingleton(_downstreamRouteFinder.Object);
 | 
			
		||||
            services.AddSingleton(_provider.Object);
 | 
			
		||||
            services.AddSingleton(ScopedRepository.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -58,14 +75,17 @@
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamRoute = new OkResponse<DownstreamRoute>(downstreamRoute);
 | 
			
		||||
            _downstreamRouteFinder
 | 
			
		||||
                .Setup(x => x.FindDownstreamRoute(It.IsAny<string>(), It.IsAny<string>()))
 | 
			
		||||
                .ReturnsAsync(_downstreamRoute);
 | 
			
		||||
                .Setup(x => x.FindDownstreamRoute(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<IOcelotConfiguration>()))
 | 
			
		||||
                .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());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -16,26 +16,27 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
			
		||||
    public class DownstreamRouteFinderTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IDownstreamRouteFinder _downstreamRouteFinder;
 | 
			
		||||
        private readonly Mock<IOcelotConfigurationProvider> _mockConfig;
 | 
			
		||||
        private readonly Mock<IUrlPathToUrlTemplateMatcher> _mockMatcher;
 | 
			
		||||
        private readonly Mock<IUrlPathPlaceholderNameAndValueFinder> _finder;
 | 
			
		||||
        private string _upstreamUrlPath;
 | 
			
		||||
        private Response<DownstreamRoute> _result;
 | 
			
		||||
        private List<ReRoute> _reRoutesConfig;
 | 
			
		||||
        private OcelotConfiguration _config;
 | 
			
		||||
        private Response<UrlMatch> _match;
 | 
			
		||||
        private string _upstreamHttpMethod;
 | 
			
		||||
 | 
			
		||||
        public DownstreamRouteFinderTests()
 | 
			
		||||
        {
 | 
			
		||||
            _mockConfig = new Mock<IOcelotConfigurationProvider>();
 | 
			
		||||
            _mockMatcher = new Mock<IUrlPathToUrlTemplateMatcher>();
 | 
			
		||||
            _finder = new Mock<IUrlPathPlaceholderNameAndValueFinder>();
 | 
			
		||||
            _downstreamRouteFinder = new Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteFinder(_mockConfig.Object, _mockMatcher.Object, _finder.Object);
 | 
			
		||||
            _downstreamRouteFinder = new Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteFinder(_mockMatcher.Object, _finder.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_route()
 | 
			
		||||
        {
 | 
			
		||||
            var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher/"))
 | 
			
		||||
                .And(x =>x.GivenTheTemplateVariableAndNameFinderReturns(
 | 
			
		||||
                        new OkResponse<List<UrlPathPlaceholderNameAndValue>>(
 | 
			
		||||
@@ -48,7 +49,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .WithUpstreamTemplatePattern("someUpstreamPath")
 | 
			
		||||
                        .Build()
 | 
			
		||||
                }, string.Empty
 | 
			
		||||
                }, string.Empty, serviceProviderConfig
 | 
			
		||||
                ))
 | 
			
		||||
                .And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
 | 
			
		||||
                .And(x => x.GivenTheUpstreamHttpMethodIs("Get"))
 | 
			
		||||
@@ -67,8 +68,10 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_append_slash_to_upstream_url_path()
 | 
			
		||||
        public void should_not_append_slash_to_upstream_url_path()
 | 
			
		||||
        {
 | 
			
		||||
            var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher"))
 | 
			
		||||
                .And(x =>x.GivenTheTemplateVariableAndNameFinderReturns(
 | 
			
		||||
                        new OkResponse<List<UrlPathPlaceholderNameAndValue>>(
 | 
			
		||||
@@ -81,7 +84,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .WithUpstreamTemplatePattern("someUpstreamPath")
 | 
			
		||||
                        .Build()
 | 
			
		||||
                }, string.Empty
 | 
			
		||||
                }, string.Empty, serviceProviderConfig
 | 
			
		||||
                ))
 | 
			
		||||
                .And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
 | 
			
		||||
                .And(x => x.GivenTheUpstreamHttpMethodIs("Get"))
 | 
			
		||||
@@ -94,13 +97,15 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
			
		||||
                                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                                .Build()
 | 
			
		||||
                )))
 | 
			
		||||
                .And(x => x.ThenTheUrlMatcherIsCalledCorrectly("matchInUrlMatcher/"))
 | 
			
		||||
                .And(x => x.ThenTheUrlMatcherIsCalledCorrectly("matchInUrlMatcher"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [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 +119,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .WithUpstreamTemplatePattern("someUpstreamPath")
 | 
			
		||||
                        .Build()
 | 
			
		||||
                }, string.Empty
 | 
			
		||||
                }, string.Empty, serviceProviderConfig
 | 
			
		||||
                    ))
 | 
			
		||||
                .And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
 | 
			
		||||
                .And(x => x.GivenTheUpstreamHttpMethodIs("Get"))
 | 
			
		||||
@@ -133,6 +138,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 +159,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Post" })
 | 
			
		||||
                        .WithUpstreamTemplatePattern("")
 | 
			
		||||
                        .Build()
 | 
			
		||||
                }, string.Empty
 | 
			
		||||
                }, string.Empty, serviceProviderConfig
 | 
			
		||||
                    ))
 | 
			
		||||
                .And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
 | 
			
		||||
                .And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
 | 
			
		||||
@@ -169,7 +176,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<ReRoute>
 | 
			
		||||
                     {
 | 
			
		||||
@@ -179,7 +188,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .WithUpstreamTemplatePattern("somePath")
 | 
			
		||||
                        .Build(),   
 | 
			
		||||
                     }, string.Empty
 | 
			
		||||
                     }, string.Empty, serviceProviderConfig
 | 
			
		||||
                 ))
 | 
			
		||||
                 .And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(false))))
 | 
			
		||||
                 .And(x => x.GivenTheUpstreamHttpMethodIs("Get"))
 | 
			
		||||
@@ -193,6 +202,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 +217,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get", "Post" })
 | 
			
		||||
                        .WithUpstreamTemplatePattern("")
 | 
			
		||||
                        .Build()
 | 
			
		||||
                }, string.Empty
 | 
			
		||||
                }, string.Empty, serviceProviderConfig
 | 
			
		||||
                    ))
 | 
			
		||||
                .And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
 | 
			
		||||
                .And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
 | 
			
		||||
@@ -224,6 +235,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 +250,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string>())
 | 
			
		||||
                        .WithUpstreamTemplatePattern("")
 | 
			
		||||
                        .Build()
 | 
			
		||||
                }, string.Empty
 | 
			
		||||
                }, string.Empty, serviceProviderConfig
 | 
			
		||||
                    ))
 | 
			
		||||
                .And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
 | 
			
		||||
                .And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
 | 
			
		||||
@@ -255,6 +268,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 +283,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get", "Patch", "Delete" })
 | 
			
		||||
                        .WithUpstreamTemplatePattern("")
 | 
			
		||||
                        .Build()
 | 
			
		||||
                }, string.Empty
 | 
			
		||||
                }, string.Empty, serviceProviderConfig
 | 
			
		||||
                    ))
 | 
			
		||||
                .And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
 | 
			
		||||
                .And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
 | 
			
		||||
@@ -322,12 +337,10 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
			
		||||
                .Returns(_match);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheConfigurationIs(List<ReRoute> reRoutesConfig, string adminPath)
 | 
			
		||||
        private void GivenTheConfigurationIs(List<ReRoute> reRoutesConfig, string adminPath, ServiceProviderConfiguration serviceProviderConfig)
 | 
			
		||||
        {
 | 
			
		||||
            _reRoutesConfig = reRoutesConfig;
 | 
			
		||||
            _mockConfig
 | 
			
		||||
                .Setup(x => x.Get())
 | 
			
		||||
                .ReturnsAsync(new OkResponse<IOcelotConfiguration>(new OcelotConfiguration(_reRoutesConfig, adminPath)));
 | 
			
		||||
            _config = new OcelotConfiguration(_reRoutesConfig, adminPath, serviceProviderConfig);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAnUpstreamUrlPath(string upstreamUrlPath)
 | 
			
		||||
@@ -337,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)
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,16 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_find_anything()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenIHaveAUpstreamPath("/products"))
 | 
			
		||||
                .And(x => x.GivenIHaveAnUpstreamUrlTemplate("/products/"))
 | 
			
		||||
                .When(x => x.WhenIFindTheUrlVariableNamesAndValues())
 | 
			
		||||
                .And(x => x.ThenTheTemplatesVariablesAre(new List<UrlPathPlaceholderNameAndValue>()))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void can_match_down_stream_url_with_no_slash()
 | 
			
		||||
        {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								test/Ocelot.UnitTests/Errors/ErrorTests.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								test/Ocelot.UnitTests/Errors/ErrorTests.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
using Ocelot.Errors;
 | 
			
		||||
using Ocelot.Infrastructure.RequestData;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Errors
 | 
			
		||||
{
 | 
			
		||||
    public class ErrorTests
 | 
			
		||||
    {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_message()
 | 
			
		||||
        {
 | 
			
		||||
            var error = new CannotAddDataError("message");
 | 
			
		||||
            var result = error.ToString();
 | 
			
		||||
            result.ShouldBe("message");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -14,7 +14,7 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
    {
 | 
			
		||||
        private HostAndPort _hostAndPort;
 | 
			
		||||
        private Response<HostAndPort> _result;
 | 
			
		||||
        private LeastConnectionLoadBalancer _leastConnection;
 | 
			
		||||
        private LeastConnection _leastConnection;
 | 
			
		||||
        private List<Service> _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<Service> services, string serviceName)
 | 
			
		||||
        {
 | 
			
		||||
            _services = services;
 | 
			
		||||
            _leastConnection = new LeastConnectionLoadBalancer(() => Task.FromResult(_services), serviceName);
 | 
			
		||||
            _leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenTheLoadBalancerStarts(List<Service> services, string serviceName)
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,8 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
        private ILoadBalancer _result;
 | 
			
		||||
        private Mock<IServiceDiscoveryProviderFactory> _serviceProviderFactory;
 | 
			
		||||
        private Mock<IServiceDiscoveryProvider> _serviceProvider;
 | 
			
		||||
        
 | 
			
		||||
        private ServiceProviderConfiguration _serviceProviderConfig;
 | 
			
		||||
 | 
			
		||||
        public LoadBalancerFactoryTests()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceProviderFactory = new Mock<IServiceDiscoveryProviderFactory>();
 | 
			
		||||
@@ -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<string> { "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<NoLoadBalancer>())
 | 
			
		||||
@@ -46,13 +47,13 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
             var reRoute = new ReRouteBuilder()
 | 
			
		||||
                .WithLoadBalancer("RoundRobin")
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "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<RoundRobinLoadBalancer>())
 | 
			
		||||
                .Then(x => x.ThenTheLoadBalancerIsReturned<RoundRobin>())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -62,13 +63,13 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
             var reRoute = new ReRouteBuilder()
 | 
			
		||||
                .WithLoadBalancer("LeastConnection")
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "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<LeastConnectionLoadBalancer>())
 | 
			
		||||
                .Then(x => x.ThenTheLoadBalancerIsReturned<LeastConnection>())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -78,27 +79,32 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
            var reRoute = new ReRouteBuilder()
 | 
			
		||||
                .WithLoadBalancer("RoundRobin")
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "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<ServiceProviderConfiguration>()))
 | 
			
		||||
                .Setup(x => x.Get(It.IsAny<ServiceProviderConfiguration>(), It.IsAny<ReRoute>()))
 | 
			
		||||
                .Returns(_serviceProvider.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheServiceProviderIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceProviderFactory
 | 
			
		||||
                .Verify(x => x.Get(It.IsAny<ServiceProviderConfiguration>()), Times.Once);
 | 
			
		||||
                .Verify(x => x.Get(It.IsAny<ServiceProviderConfiguration>(), It.IsAny<ReRoute>()), 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<T>()
 | 
			
		||||
 
 | 
			
		||||
@@ -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<ILoadBalancer> _getResult;
 | 
			
		||||
        private string _key;
 | 
			
		||||
        private Mock<ILoadBalancerFactory> _factory;
 | 
			
		||||
        private ServiceProviderConfiguration _serviceProviderConfig;
 | 
			
		||||
 | 
			
		||||
        public LoadBalancerHouseTests()
 | 
			
		||||
        {
 | 
			
		||||
            _loadBalancerHouse = new LoadBalancerHouse();
 | 
			
		||||
            _factory = new Mock<ILoadBalancerFactory>();
 | 
			
		||||
            _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().WithReRouteKey("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().WithLoadBalancer("FakeLoadBalancer").WithReRouteKey("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().WithReRouteKey("test").Build();
 | 
			
		||||
            var reRouteTwo = new ReRouteBuilder().WithReRouteKey("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<FakeLoadBalancer>())
 | 
			
		||||
                .When(x => x.WhenWeGetTheLoadBalancer(keyTwo))
 | 
			
		||||
                .When(x => x.WhenWeGetTheLoadBalancer(reRouteTwo))
 | 
			
		||||
                .Then(x => x.ThenTheLoadBalancerIs<FakeRoundRobinLoadBalancer>())
 | 
			
		||||
                .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().WithLoadBalancer("FakeLoadBalancer").WithReRouteKey("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<FakeLoadBalancer>())
 | 
			
		||||
                .When(x => x.WhenIGetTheReRouteWithTheSameKeyButDifferentLoadBalancer(reRouteTwo))
 | 
			
		||||
                .Then(x => x.ThenTheLoadBalancerIs<LeastConnection>())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIGetTheReRouteWithTheSameKeyButDifferentLoadBalancer(ReRoute reRoute)
 | 
			
		||||
        {
 | 
			
		||||
            _reRoute = reRoute;
 | 
			
		||||
            _factory.Setup(x => x.Get(_reRoute, _serviceProviderConfig)).ReturnsAsync(new LeastConnection(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<OkResponse>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIAddTheLoadBalancer()
 | 
			
		||||
        {
 | 
			
		||||
            _addResult = _loadBalancerHouse.Add(_key, _loadBalancer);
 | 
			
		||||
            _getResult.IsError.ShouldBe(false);
 | 
			
		||||
            _getResult.ShouldBeOfType<OkResponse<ILoadBalancer>>();
 | 
			
		||||
            _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
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,9 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
    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.Errors;
 | 
			
		||||
    using Ocelot.LoadBalancer.LoadBalancers;
 | 
			
		||||
@@ -26,13 +28,13 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
        private ErrorResponse<ILoadBalancer> _getLoadBalancerHouseError;
 | 
			
		||||
        private ErrorResponse<HostAndPort> _getHostAndPortError;
 | 
			
		||||
        private HttpRequestMessage _downstreamRequest;
 | 
			
		||||
        private ServiceProviderConfiguration _config;
 | 
			
		||||
 | 
			
		||||
        public LoadBalancerMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _loadBalancerHouse = new Mock<ILoadBalancerHouse>();
 | 
			
		||||
            _loadBalancer = new Mock<ILoadBalancer>();
 | 
			
		||||
            _loadBalancerHouse = new Mock<ILoadBalancerHouse>();
 | 
			
		||||
 | 
			
		||||
            _downstreamRequest = new HttpRequestMessage(HttpMethod.Get, "");
 | 
			
		||||
 | 
			
		||||
            ScopedRepository
 | 
			
		||||
@@ -50,7 +52,11 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "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())
 | 
			
		||||
@@ -67,7 +73,11 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "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())
 | 
			
		||||
@@ -82,8 +92,12 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "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())
 | 
			
		||||
@@ -92,6 +106,13 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheConfigurationIs(ServiceProviderConfiguration config)
 | 
			
		||||
        {
 | 
			
		||||
            _config = config;
 | 
			
		||||
            ScopedRepository
 | 
			
		||||
                .Setup(x => x.Get<ServiceProviderConfiguration>("ServiceProviderConfiguration")).Returns(new OkResponse<ServiceProviderConfiguration>(config));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services)
 | 
			
		||||
        {
 | 
			
		||||
            services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
 | 
			
		||||
@@ -137,8 +158,8 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
        private void GivenTheLoadBalancerHouseReturns()
 | 
			
		||||
        {
 | 
			
		||||
            _loadBalancerHouse
 | 
			
		||||
                .Setup(x => x.Get(It.IsAny<string>()))
 | 
			
		||||
                .Returns(new OkResponse<ILoadBalancer>(_loadBalancer.Object));
 | 
			
		||||
                .Setup(x => x.Get(It.IsAny<ReRoute>(), It.IsAny<ServiceProviderConfiguration>()))
 | 
			
		||||
                .ReturnsAsync(new OkResponse<ILoadBalancer>(_loadBalancer.Object));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheLoadBalancerHouseReturnsAnError()
 | 
			
		||||
@@ -149,8 +170,8 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            _loadBalancerHouse
 | 
			
		||||
                .Setup(x => x.Get(It.IsAny<string>()))
 | 
			
		||||
                .Returns(_getLoadBalancerHouseError);
 | 
			
		||||
                .Setup(x => x.Get(It.IsAny<ReRoute>(), It.IsAny<ServiceProviderConfiguration>()))
 | 
			
		||||
                .ReturnsAsync(_getLoadBalancerHouseError);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenAnErrorStatingLoadBalancerCouldNotBeFoundIsSetOnPipeline()
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
{
 | 
			
		||||
    public class RoundRobinTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly RoundRobinLoadBalancer _roundRobin;
 | 
			
		||||
        private readonly RoundRobin _roundRobin;
 | 
			
		||||
        private readonly List<Service> _services;
 | 
			
		||||
        private Response<HostAndPort> _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]
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,12 @@
 | 
			
		||||
  <Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
   <ItemGroup>
 | 
			
		||||
    <None Update="idsrv3test.pfx">
 | 
			
		||||
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 | 
			
		||||
    </None>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.0.0" />
 | 
			
		||||
 
 | 
			
		||||
@@ -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<IRequestCreator> _requestBuilder;
 | 
			
		||||
        private readonly Mock<IRequestScopedDataRepository> _scopedRepository;
 | 
			
		||||
        private readonly Mock<IQosProviderHouse> _qosProviderHouse;
 | 
			
		||||
        private readonly HttpRequestMessage _downstreamRequest;
 | 
			
		||||
        private OkResponse<Ocelot.Request.Request> _request;
 | 
			
		||||
        private OkResponse<string> _downstreamUrl;
 | 
			
		||||
        private OkResponse<DownstreamRoute> _downstreamRoute;
 | 
			
		||||
 | 
			
		||||
        public HttpRequestBuilderMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _qosProviderHouse = new Mock<IQosProviderHouse>();
 | 
			
		||||
            _requestBuilder = new Mock<IRequestCreator>();
 | 
			
		||||
            _scopedRepository = new Mock<IRequestScopedDataRepository>();
 | 
			
		||||
 | 
			
		||||
            _downstreamRequest = new HttpRequestMessage();
 | 
			
		||||
 | 
			
		||||
            _scopedRepository
 | 
			
		||||
                .Setup(sr => sr.Get<HttpRequestMessage>("DownstreamRequest"))
 | 
			
		||||
                .Returns(new OkResponse<HttpRequestMessage>(_downstreamRequest));
 | 
			
		||||
 | 
			
		||||
            GivenTheTestServerIsConfigured();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_scoped_data_repository_correctly()
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<UrlPathPlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithRequestIdKey("LSRequestId")
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                    .WithHttpHandlerOptions(new HttpHandlerOptions(true, true))
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamUrlIs("any old string"))
 | 
			
		||||
                .And(x => x.GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(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<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
 | 
			
		||||
            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<string>(downstreamUrl);
 | 
			
		||||
            _scopedRepository
 | 
			
		||||
                .Setup(x => x.Get<string>(It.IsAny<string>()))
 | 
			
		||||
                .Returns(_downstreamUrl);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheQosProviderHouseReturns(Response<IQoSProvider> qosProvider)
 | 
			
		||||
        {
 | 
			
		||||
            _qosProviderHouse
 | 
			
		||||
                .Setup(x => x.Get(It.IsAny<string>()))
 | 
			
		||||
                .Returns(qosProvider);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamRoute = new OkResponse<DownstreamRoute>(downstreamRoute);
 | 
			
		||||
            _scopedRepository
 | 
			
		||||
                .Setup(x => x.Get<DownstreamRoute>(It.IsAny<string>()))
 | 
			
		||||
                .Returns(_downstreamRoute);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheRequestBuilderReturns(Ocelot.Request.Request request)
 | 
			
		||||
        {
 | 
			
		||||
            _request = new OkResponse<Ocelot.Request.Request>(request);
 | 
			
		||||
 | 
			
		||||
            _requestBuilder
 | 
			
		||||
                .Setup(x => x.Build(It.IsAny<HttpRequestMessage>(),
 | 
			
		||||
                                    It.IsAny<bool>(),
 | 
			
		||||
                                    It.IsAny<IQoSProvider>(),
 | 
			
		||||
                                    It.IsAny<bool>(),
 | 
			
		||||
                                    It.IsAny<bool>()))
 | 
			
		||||
                .ReturnsAsync(_request);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheScopedDataRepositoryIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _scopedRepository
 | 
			
		||||
                .Verify(x => x.Add("Request", _request.Data), Times.Once());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
    public class HttpRequestBuilderMiddlewareTests : ServerHostedMiddlewareTest
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Mock<IRequestCreator> _requestBuilder;
 | 
			
		||||
        private readonly Mock<IRequestScopedDataRepository> _scopedRepository;
 | 
			
		||||
        private readonly Mock<IQosProviderHouse> _qosProviderHouse;
 | 
			
		||||
        private readonly HttpRequestMessage _downstreamRequest;
 | 
			
		||||
        private OkResponse<Ocelot.Request.Request> _request;
 | 
			
		||||
        private OkResponse<string> _downstreamUrl;
 | 
			
		||||
        private OkResponse<DownstreamRoute> _downstreamRoute;
 | 
			
		||||
 | 
			
		||||
        public HttpRequestBuilderMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _qosProviderHouse = new Mock<IQosProviderHouse>();
 | 
			
		||||
            _requestBuilder = new Mock<IRequestCreator>();
 | 
			
		||||
            _scopedRepository = new Mock<IRequestScopedDataRepository>();
 | 
			
		||||
 | 
			
		||||
            _downstreamRequest = new HttpRequestMessage();
 | 
			
		||||
 | 
			
		||||
            _scopedRepository
 | 
			
		||||
                .Setup(sr => sr.Get<HttpRequestMessage>("DownstreamRequest"))
 | 
			
		||||
                .Returns(new OkResponse<HttpRequestMessage>(_downstreamRequest));
 | 
			
		||||
 | 
			
		||||
            GivenTheTestServerIsConfigured();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_scoped_data_repository_correctly()
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<UrlPathPlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithRequestIdKey("LSRequestId")
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                    .WithHttpHandlerOptions(new HttpHandlerOptions(true, true))
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamUrlIs("any old string"))
 | 
			
		||||
                .And(x => x.GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(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<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
 | 
			
		||||
            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<string>(downstreamUrl);
 | 
			
		||||
            _scopedRepository
 | 
			
		||||
                .Setup(x => x.Get<string>(It.IsAny<string>()))
 | 
			
		||||
                .Returns(_downstreamUrl);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheQosProviderHouseReturns(Response<IQoSProvider> qosProvider)
 | 
			
		||||
        {
 | 
			
		||||
            _qosProviderHouse
 | 
			
		||||
                .Setup(x => x.Get(It.IsAny<ReRoute>()))
 | 
			
		||||
                .Returns(qosProvider);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamRoute = new OkResponse<DownstreamRoute>(downstreamRoute);
 | 
			
		||||
            _scopedRepository
 | 
			
		||||
                .Setup(x => x.Get<DownstreamRoute>(It.IsAny<string>()))
 | 
			
		||||
                .Returns(_downstreamRoute);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheRequestBuilderReturns(Ocelot.Request.Request request)
 | 
			
		||||
        {
 | 
			
		||||
            _request = new OkResponse<Ocelot.Request.Request>(request);
 | 
			
		||||
 | 
			
		||||
            _requestBuilder
 | 
			
		||||
                .Setup(x => x.Build(It.IsAny<HttpRequestMessage>(),
 | 
			
		||||
                                    It.IsAny<bool>(),
 | 
			
		||||
                                    It.IsAny<IQoSProvider>(),
 | 
			
		||||
                                    It.IsAny<bool>(),
 | 
			
		||||
                                    It.IsAny<bool>()))
 | 
			
		||||
                .ReturnsAsync(_request);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheScopedDataRepositoryIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _scopedRepository
 | 
			
		||||
                .Verify(x => x.Add("Request", _request.Data), Times.Once());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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<IQoSProvider> _getResult;
 | 
			
		||||
        private string _key;
 | 
			
		||||
        private ReRoute _reRoute;
 | 
			
		||||
        private readonly Mock<IQoSProviderFactory> _factory;
 | 
			
		||||
 | 
			
		||||
        public QosProviderHouseTests()
 | 
			
		||||
        {
 | 
			
		||||
            _qosProviderHouse = new QosProviderHouse();
 | 
			
		||||
            _factory = new Mock<IQoSProviderFactory>();
 | 
			
		||||
            _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<FakeQoSProvider>())
 | 
			
		||||
                .When(x => x.WhenWeGetTheQoSProvider(keyTwo))
 | 
			
		||||
                .When(x => x.WhenWeGetTheQoSProvider(reRouteTwo))
 | 
			
		||||
                .Then(x => x.ThenTheQoSProviderIs<FakePollyQoSProvider>())
 | 
			
		||||
                .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<FakeQoSProvider>())
 | 
			
		||||
                .When(x => x.WhenIGetTheReRouteWithTheSameKeyButDifferentQosProvider(reRouteTwo))
 | 
			
		||||
                .Then(x => x.ThenTheQoSProviderIs<FakePollyQoSProvider>())
 | 
			
		||||
                .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<OkResponse>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIAddTheQoSProvider()
 | 
			
		||||
        {
 | 
			
		||||
            _addResult = _qosProviderHouse.Add(_key, _qoSProvider);
 | 
			
		||||
            _getResult.IsError.ShouldBe(false);
 | 
			
		||||
            _getResult.ShouldBeOfType<OkResponse<IQoSProvider>>();
 | 
			
		||||
            _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
 | 
			
		||||
 
 | 
			
		||||
@@ -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<ConfigurationServiceProvider>())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
@@ -36,26 +36,29 @@ namespace Ocelot.UnitTests.ServiceDiscovery
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_consul_service_provider()
 | 
			
		||||
        {
 | 
			
		||||
            var serviceConfig = new ServiceProviderConfigurationBuilder()
 | 
			
		||||
            var reRoute = new ReRouteBuilder()
 | 
			
		||||
                .WithServiceName("product")
 | 
			
		||||
                .WithUseServiceDiscovery(true)
 | 
			
		||||
                .WithServiceDiscoveryProvider("Consul")
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheReRoute(serviceConfig))
 | 
			
		||||
            var serviceConfig = new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheReRoute(serviceConfig, reRoute))
 | 
			
		||||
                .When(x => x.WhenIGetTheServiceProvider())
 | 
			
		||||
                .Then(x => x.ThenTheServiceProviderIs<ConsulServiceDiscoveryProvider>())
 | 
			
		||||
                .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<T>()
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										55
									
								
								test/Ocelot.UnitTests/Waiter.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								test/Ocelot.UnitTests/Waiter.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests
 | 
			
		||||
{
 | 
			
		||||
    public class Wait
 | 
			
		||||
    {
 | 
			
		||||
        public static Waiter WaitFor(int milliSeconds)
 | 
			
		||||
        {
 | 
			
		||||
            return new Waiter(milliSeconds);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class Waiter
 | 
			
		||||
    {
 | 
			
		||||
        private readonly int _milliSeconds;
 | 
			
		||||
 | 
			
		||||
        public Waiter(int milliSeconds)
 | 
			
		||||
        {
 | 
			
		||||
            _milliSeconds = milliSeconds;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool Until(Func<bool> condition)
 | 
			
		||||
        {
 | 
			
		||||
            var stopwatch = Stopwatch.StartNew();
 | 
			
		||||
            var passed = false;
 | 
			
		||||
            while (stopwatch.ElapsedMilliseconds < _milliSeconds)
 | 
			
		||||
            {
 | 
			
		||||
                if (condition.Invoke())
 | 
			
		||||
                {
 | 
			
		||||
                    passed = true;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return passed;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool Until<T>(Func<bool> condition)
 | 
			
		||||
        {
 | 
			
		||||
            var stopwatch = Stopwatch.StartNew();
 | 
			
		||||
            var passed = false;
 | 
			
		||||
            while (stopwatch.ElapsedMilliseconds < _milliSeconds)
 | 
			
		||||
            {
 | 
			
		||||
                if (condition.Invoke())
 | 
			
		||||
                {
 | 
			
		||||
                    passed = true;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return passed;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								test/Ocelot.UnitTests/idsrv3test.pfx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								test/Ocelot.UnitTests/idsrv3test.pfx
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
		Reference in New Issue
	
	Block a user