Merge pull request #149 from TomPallister/feature/fix-#142

Feature/fix #142
This commit is contained in:
Tom Pallister 2017-11-13 20:46:38 +00:00 committed by GitHub
commit 9f27fe27a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
60 changed files with 949 additions and 857 deletions

View File

@ -1,6 +1,6 @@
{ {
"projects": [ "src", "test" ], "projects": [ "src", "test" ],
"sdk": { "sdk": {
"version": "2.0.0" "version": "2.0.2"
} }
} }

View File

@ -26,13 +26,14 @@ namespace Ocelot.Configuration.Builder
private string _downstreamHost; private string _downstreamHost;
private int _downstreamPort; private int _downstreamPort;
private string _loadBalancer; private string _loadBalancer;
private ServiceProviderConfiguration _serviceProviderConfiguraion;
private bool _useQos; private bool _useQos;
private QoSOptions _qosOptions; private QoSOptions _qosOptions;
private HttpHandlerOptions _httpHandlerOptions; private HttpHandlerOptions _httpHandlerOptions;
public bool _enableRateLimiting; public bool _enableRateLimiting;
public RateLimitOptions _rateLimitOptions; public RateLimitOptions _rateLimitOptions;
private string _authenticationProviderKey; private string _authenticationProviderKey;
private bool _useServiceDiscovery;
private string _serviceName;
public ReRouteBuilder WithLoadBalancer(string loadBalancer) public ReRouteBuilder WithLoadBalancer(string loadBalancer)
{ {
@ -148,18 +149,12 @@ namespace Ocelot.Configuration.Builder
return this; return this;
} }
public ReRouteBuilder WithLoadBalancerKey(string loadBalancerKey) public ReRouteBuilder WithReRouteKey(string loadBalancerKey)
{ {
_loadBalancerKey = loadBalancerKey; _loadBalancerKey = loadBalancerKey;
return this; return this;
} }
public ReRouteBuilder WithServiceProviderConfiguraion(ServiceProviderConfiguration serviceProviderConfiguraion)
{
_serviceProviderConfiguraion = serviceProviderConfiguraion;
return this;
}
public ReRouteBuilder WithAuthenticationOptions(AuthenticationOptions authenticationOptions) public ReRouteBuilder WithAuthenticationOptions(AuthenticationOptions authenticationOptions)
{ {
_authenticationOptions = authenticationOptions; _authenticationOptions = authenticationOptions;
@ -190,6 +185,18 @@ namespace Ocelot.Configuration.Builder
return this; return this;
} }
public ReRouteBuilder WithUseServiceDiscovery(bool useServiceDiscovery)
{
_useServiceDiscovery = useServiceDiscovery;
return this;
}
public ReRouteBuilder WithServiceName(string serviceName)
{
_serviceName = serviceName;
return this;
}
public ReRoute Build() public ReRoute Build()
{ {
return new ReRoute( return new ReRoute(
@ -212,12 +219,13 @@ namespace Ocelot.Configuration.Builder
_downstreamHost, _downstreamHost,
_downstreamPort, _downstreamPort,
_loadBalancerKey, _loadBalancerKey,
_serviceProviderConfiguraion,
_useQos, _useQos,
_qosOptions, _qosOptions,
_enableRateLimiting, _enableRateLimiting,
_rateLimitOptions, _rateLimitOptions,
_httpHandlerOptions); _httpHandlerOptions,
_useServiceDiscovery,
_serviceName);
} }
} }
} }

View File

@ -2,44 +2,9 @@ namespace Ocelot.Configuration.Builder
{ {
public class ServiceProviderConfigurationBuilder public class ServiceProviderConfigurationBuilder
{ {
private string _serviceName;
private string _downstreamHost;
private int _downstreamPort;
private bool _userServiceDiscovery;
private string _serviceDiscoveryProvider;
private string _serviceDiscoveryProviderHost; private string _serviceDiscoveryProviderHost;
private int _serviceDiscoveryProviderPort; 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) public ServiceProviderConfigurationBuilder WithServiceDiscoveryProviderHost(string serviceDiscoveryProviderHost)
{ {
_serviceDiscoveryProviderHost = serviceDiscoveryProviderHost; _serviceDiscoveryProviderHost = serviceDiscoveryProviderHost;
@ -52,11 +17,9 @@ namespace Ocelot.Configuration.Builder
return this; return this;
} }
public ServiceProviderConfiguration Build() public ServiceProviderConfiguration Build()
{ {
return new ServiceProviderConfiguration(_serviceName, _downstreamHost, _downstreamPort, _userServiceDiscovery, return new ServiceProviderConfiguration(_serviceDiscoveryProviderHost,_serviceDiscoveryProviderPort);
_serviceDiscoveryProvider, _serviceDiscoveryProviderHost,_serviceDiscoveryProviderPort);
} }
} }
} }

View File

@ -9,6 +9,7 @@ using Ocelot.Configuration.Builder;
using Ocelot.Configuration.File; using Ocelot.Configuration.File;
using Ocelot.Configuration.Parser; using Ocelot.Configuration.Parser;
using Ocelot.Configuration.Validator; using Ocelot.Configuration.Validator;
using Ocelot.LoadBalancer;
using Ocelot.LoadBalancer.LoadBalancers; using Ocelot.LoadBalancer.LoadBalancers;
using Ocelot.Logging; using Ocelot.Logging;
using Ocelot.Requester.QoS; using Ocelot.Requester.QoS;
@ -25,10 +26,6 @@ namespace Ocelot.Configuration.Creator
private readonly IOptions<FileConfiguration> _options; private readonly IOptions<FileConfiguration> _options;
private readonly IConfigurationValidator _configurationValidator; private readonly IConfigurationValidator _configurationValidator;
private readonly IOcelotLogger _logger; 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 IClaimsToThingCreator _claimsToThingCreator;
private readonly IAuthenticationOptionsCreator _authOptionsCreator; private readonly IAuthenticationOptionsCreator _authOptionsCreator;
private readonly IUpstreamTemplatePatternCreator _upstreamTemplatePatternCreator; private readonly IUpstreamTemplatePatternCreator _upstreamTemplatePatternCreator;
@ -44,10 +41,6 @@ namespace Ocelot.Configuration.Creator
IOptions<FileConfiguration> options, IOptions<FileConfiguration> options,
IConfigurationValidator configurationValidator, IConfigurationValidator configurationValidator,
IOcelotLoggerFactory loggerFactory, IOcelotLoggerFactory loggerFactory,
ILoadBalancerFactory loadBalancerFactory,
ILoadBalancerHouse loadBalancerHouse,
IQoSProviderFactory qoSProviderFactory,
IQosProviderHouse qosProviderHouse,
IClaimsToThingCreator claimsToThingCreator, IClaimsToThingCreator claimsToThingCreator,
IAuthenticationOptionsCreator authOptionsCreator, IAuthenticationOptionsCreator authOptionsCreator,
IUpstreamTemplatePatternCreator upstreamTemplatePatternCreator, IUpstreamTemplatePatternCreator upstreamTemplatePatternCreator,
@ -65,10 +58,6 @@ namespace Ocelot.Configuration.Creator
_requestIdKeyCreator = requestIdKeyCreator; _requestIdKeyCreator = requestIdKeyCreator;
_upstreamTemplatePatternCreator = upstreamTemplatePatternCreator; _upstreamTemplatePatternCreator = upstreamTemplatePatternCreator;
_authOptionsCreator = authOptionsCreator; _authOptionsCreator = authOptionsCreator;
_loadBalanceFactory = loadBalancerFactory;
_loadBalancerHouse = loadBalancerHouse;
_qoSProviderFactory = qoSProviderFactory;
_qosProviderHouse = qosProviderHouse;
_options = options; _options = options;
_configurationValidator = configurationValidator; _configurationValidator = configurationValidator;
_logger = loggerFactory.CreateLogger<FileOcelotConfigurationCreator>(); _logger = loggerFactory.CreateLogger<FileOcelotConfigurationCreator>();
@ -113,14 +102,16 @@ namespace Ocelot.Configuration.Creator
foreach (var reRoute in fileConfiguration.ReRoutes) foreach (var reRoute in fileConfiguration.ReRoutes)
{ {
var ocelotReRoute = await SetUpReRoute(reRoute, fileConfiguration.GlobalConfiguration); var ocelotReRoute = SetUpReRoute(reRoute, fileConfiguration.GlobalConfiguration);
reRoutes.Add(ocelotReRoute); reRoutes.Add(ocelotReRoute);
} }
return new OcelotConfiguration(reRoutes, fileConfiguration.GlobalConfiguration.AdministrationPath); var serviceProviderConfiguration = _serviceProviderConfigCreator.Create(fileConfiguration.GlobalConfiguration);
return new OcelotConfiguration(reRoutes, fileConfiguration.GlobalConfiguration.AdministrationPath, serviceProviderConfiguration);
} }
private async Task<ReRoute> SetUpReRoute(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration) private ReRoute SetUpReRoute(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration)
{ {
var fileReRouteOptions = _fileReRouteOptionsCreator.Create(fileReRoute); var fileReRouteOptions = _fileReRouteOptionsCreator.Create(fileReRoute);
@ -130,8 +121,6 @@ namespace Ocelot.Configuration.Creator
var upstreamTemplatePattern = _upstreamTemplatePatternCreator.Create(fileReRoute); var upstreamTemplatePattern = _upstreamTemplatePatternCreator.Create(fileReRoute);
var serviceProviderConfiguration = _serviceProviderConfigCreator.Create(fileReRoute, globalConfiguration);
var authOptionsForRoute = _authOptionsCreator.Create(fileReRoute); var authOptionsForRoute = _authOptionsCreator.Create(fileReRoute);
var claimsToHeaders = _claimsToThingCreator.Create(fileReRoute.AddHeadersToRequest); var claimsToHeaders = _claimsToThingCreator.Create(fileReRoute.AddHeadersToRequest);
@ -167,17 +156,16 @@ namespace Ocelot.Configuration.Creator
.WithLoadBalancer(fileReRoute.LoadBalancer) .WithLoadBalancer(fileReRoute.LoadBalancer)
.WithDownstreamHost(fileReRoute.DownstreamHost) .WithDownstreamHost(fileReRoute.DownstreamHost)
.WithDownstreamPort(fileReRoute.DownstreamPort) .WithDownstreamPort(fileReRoute.DownstreamPort)
.WithLoadBalancerKey(reRouteKey) .WithReRouteKey(reRouteKey)
.WithServiceProviderConfiguraion(serviceProviderConfiguration)
.WithIsQos(fileReRouteOptions.IsQos) .WithIsQos(fileReRouteOptions.IsQos)
.WithQosOptions(qosOptions) .WithQosOptions(qosOptions)
.WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting) .WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting)
.WithRateLimitOptions(rateLimitOption) .WithRateLimitOptions(rateLimitOption)
.WithHttpHandlerOptions(httpHandlerOptions) .WithHttpHandlerOptions(httpHandlerOptions)
.WithServiceName(fileReRoute.ServiceName)
.WithUseServiceDiscovery(fileReRoute.UseServiceDiscovery)
.Build(); .Build();
await SetupLoadBalancer(reRoute);
SetupQosProvider(reRoute);
return reRoute; return reRoute;
} }
@ -187,17 +175,5 @@ namespace Ocelot.Configuration.Creator
var loadBalancerKey = $"{fileReRoute.UpstreamPathTemplate}|{string.Join(",", fileReRoute.UpstreamHttpMethod)}"; var loadBalancerKey = $"{fileReRoute.UpstreamPathTemplate}|{string.Join(",", fileReRoute.UpstreamHttpMethod)}";
return loadBalancerKey; 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);
}
} }
} }

View File

@ -4,6 +4,6 @@ namespace Ocelot.Configuration.Creator
{ {
public interface IServiceProviderConfigurationCreator public interface IServiceProviderConfigurationCreator
{ {
ServiceProviderConfiguration Create(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration); ServiceProviderConfiguration Create(FileGlobalConfiguration globalConfiguration);
} }
} }

View File

@ -5,19 +5,11 @@ namespace Ocelot.Configuration.Creator
{ {
public class ServiceProviderConfigurationCreator : IServiceProviderConfigurationCreator 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; var serviceProviderPort = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0;
return new ServiceProviderConfigurationBuilder() return new ServiceProviderConfigurationBuilder()
.WithServiceName(fileReRoute.ServiceName)
.WithDownstreamHost(fileReRoute.DownstreamHost)
.WithDownstreamPort(fileReRoute.DownstreamPort)
.WithUseServiceDiscovery(useServiceDiscovery)
.WithServiceDiscoveryProvider(globalConfiguration?.ServiceDiscoveryProvider?.Provider)
.WithServiceDiscoveryProviderHost(globalConfiguration?.ServiceDiscoveryProvider?.Host) .WithServiceDiscoveryProviderHost(globalConfiguration?.ServiceDiscoveryProvider?.Host)
.WithServiceDiscoveryProviderPort(serviceProviderPort) .WithServiceDiscoveryProviderPort(serviceProviderPort)
.Build(); .Build();

View File

@ -37,5 +37,6 @@ namespace Ocelot.Configuration.File
public FileRateLimitRule RateLimitOptions { get; set; } public FileRateLimitRule RateLimitOptions { get; set; }
public FileAuthenticationOptions AuthenticationOptions { get; set; } public FileAuthenticationOptions AuthenticationOptions { get; set; }
public FileHttpHandlerOptions HttpHandlerOptions { get; set; } public FileHttpHandlerOptions HttpHandlerOptions { get; set; }
public bool UseServiceDiscovery {get;set;}
} }
} }

View File

@ -2,8 +2,6 @@ namespace Ocelot.Configuration.File
{ {
public class FileServiceDiscoveryProvider public class FileServiceDiscoveryProvider
{ {
public string Provider {get;set;}
public string Host {get;set;} public string Host {get;set;}
public int Port { get; set; } public int Port { get; set; }
} }

View File

@ -6,5 +6,6 @@ namespace Ocelot.Configuration
{ {
List<ReRoute> ReRoutes { get; } List<ReRoute> ReRoutes { get; }
string AdministrationPath {get;} string AdministrationPath {get;}
ServiceProviderConfiguration ServiceProviderConfiguration {get;}
} }
} }

View File

@ -4,13 +4,15 @@ namespace Ocelot.Configuration
{ {
public class OcelotConfiguration : IOcelotConfiguration public class OcelotConfiguration : IOcelotConfiguration
{ {
public OcelotConfiguration(List<ReRoute> reRoutes, string administrationPath) public OcelotConfiguration(List<ReRoute> reRoutes, string administrationPath, ServiceProviderConfiguration serviceProviderConfiguration)
{ {
ReRoutes = reRoutes; ReRoutes = reRoutes;
AdministrationPath = administrationPath; AdministrationPath = administrationPath;
ServiceProviderConfiguration = serviceProviderConfiguration;
} }
public List<ReRoute> ReRoutes { get; } public List<ReRoute> ReRoutes { get; }
public string AdministrationPath {get;} public string AdministrationPath {get;}
public ServiceProviderConfiguration ServiceProviderConfiguration {get;}
} }
} }

View File

@ -25,15 +25,17 @@ namespace Ocelot.Configuration
string downstreamHost, string downstreamHost,
int downstreamPort, int downstreamPort,
string reRouteKey, string reRouteKey,
ServiceProviderConfiguration serviceProviderConfiguraion,
bool isQos, bool isQos,
QoSOptions qosOptions, QoSOptions qosOptions,
bool enableEndpointRateLimiting, bool enableEndpointRateLimiting,
RateLimitOptions ratelimitOptions, RateLimitOptions ratelimitOptions,
HttpHandlerOptions httpHandlerOptions) HttpHandlerOptions httpHandlerOptions,
bool useServiceDiscovery,
string serviceName)
{ {
ServiceName = serviceName;
UseServiceDiscovery = useServiceDiscovery;
ReRouteKey = reRouteKey; ReRouteKey = reRouteKey;
ServiceProviderConfiguraion = serviceProviderConfiguraion;
LoadBalancer = loadBalancer; LoadBalancer = loadBalancer;
DownstreamHost = downstreamHost; DownstreamHost = downstreamHost;
DownstreamPort = downstreamPort; DownstreamPort = downstreamPort;
@ -83,9 +85,10 @@ namespace Ocelot.Configuration
public string LoadBalancer {get;private set;} public string LoadBalancer {get;private set;}
public string DownstreamHost { get; private set; } public string DownstreamHost { get; private set; }
public int DownstreamPort { get; private set; } public int DownstreamPort { get; private set; }
public ServiceProviderConfiguration ServiceProviderConfiguraion { get; private set; }
public bool EnableEndpointEndpointRateLimiting { get; private set; } public bool EnableEndpointEndpointRateLimiting { get; private set; }
public RateLimitOptions RateLimitOptions { get; private set; } public RateLimitOptions RateLimitOptions { get; private set; }
public HttpHandlerOptions HttpHandlerOptions { get; private set; } public HttpHandlerOptions HttpHandlerOptions { get; private set; }
public bool UseServiceDiscovery {get;private set;}
public string ServiceName {get;private set;}
} }
} }

View File

@ -11,19 +11,19 @@ namespace Ocelot.Configuration.Repository
public class ConsulOcelotConfigurationRepository : IOcelotConfigurationRepository public class ConsulOcelotConfigurationRepository : IOcelotConfigurationRepository
{ {
private readonly ConsulClient _consul; private readonly ConsulClient _consul;
private ConsulRegistryConfiguration _configuration;
private string _ocelotConfiguration = "OcelotConfiguration"; private string _ocelotConfiguration = "OcelotConfiguration";
private Cache.IOcelotCache<IOcelotConfiguration> _cache; private readonly Cache.IOcelotCache<IOcelotConfiguration> _cache;
public ConsulOcelotConfigurationRepository(ConsulRegistryConfiguration consulRegistryConfiguration, Cache.IOcelotCache<IOcelotConfiguration> cache)
public ConsulOcelotConfigurationRepository(Cache.IOcelotCache<IOcelotConfiguration> cache, ServiceProviderConfiguration serviceProviderConfig)
{ {
var consulHost = string.IsNullOrEmpty(consulRegistryConfiguration?.HostName) ? "localhost" : consulRegistryConfiguration.HostName; var consulHost = string.IsNullOrEmpty(serviceProviderConfig?.ServiceProviderHost) ? "localhost" : serviceProviderConfig?.ServiceProviderHost;
var consulPort = consulRegistryConfiguration?.Port ?? 8500; var consulPort = serviceProviderConfig?.ServiceProviderPort ?? 8500;
_configuration = new ConsulRegistryConfiguration(consulHost, consulPort, consulRegistryConfiguration?.ServiceName); var configuration = new ConsulRegistryConfiguration(consulHost, consulPort, _ocelotConfiguration);
_cache = cache; _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}");
}); });
} }

View File

@ -2,23 +2,12 @@
{ {
public class ServiceProviderConfiguration public class ServiceProviderConfiguration
{ {
public ServiceProviderConfiguration(string serviceName, string downstreamHost, public ServiceProviderConfiguration(string serviceProviderHost, int serviceProviderPort)
int downstreamPort, bool useServiceDiscovery, string serviceDiscoveryProvider, string serviceProviderHost, int serviceProviderPort)
{ {
ServiceName = serviceName;
DownstreamHost = downstreamHost;
DownstreamPort = downstreamPort;
UseServiceDiscovery = useServiceDiscovery;
ServiceDiscoveryProvider = serviceDiscoveryProvider;
ServiceProviderHost = serviceProviderHost; ServiceProviderHost = serviceProviderHost;
ServiceProviderPort = serviceProviderPort; 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 string ServiceProviderHost { get; private set; }
public int ServiceProviderPort { get; private set; } public int ServiceProviderPort { get; private set; }
} }

View File

@ -45,19 +45,39 @@ using IdentityServer4.AccessTokenValidation;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Ocelot.Configuration; using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using FileConfigurationProvider = Ocelot.Configuration.Provider.FileConfigurationProvider; using FileConfigurationProvider = Ocelot.Configuration.Provider.FileConfigurationProvider;
namespace Ocelot.DependencyInjection namespace Ocelot.DependencyInjection
{ {
public static class ServiceCollectionExtensions public static class ServiceCollectionExtensions
{ {
public static IServiceCollection AddOcelotStoreConfigurationInConsul(this IServiceCollection services, ConsulRegistryConfiguration consulConfig) public static IServiceCollection AddStoreOcelotConfigurationInConsul(this IServiceCollection services, IConfigurationRoot configurationRoot)
{ {
services.AddSingleton<ConsulRegistryConfiguration>(consulConfig); var serviceDiscoveryPort = configurationRoot.GetValue("GlobalConfiguration:ServiceDiscoveryProvider:Port", 0);
var serviceDiscoveryHost = configurationRoot.GetValue("GlobalConfiguration:ServiceDiscoveryProvider:Host", string.Empty);
var config = new ServiceProviderConfigurationBuilder()
.WithServiceDiscoveryProviderPort(serviceDiscoveryPort)
.WithServiceDiscoveryProviderHost(serviceDiscoveryHost)
.Build();
services.AddSingleton<ServiceProviderConfiguration>(config);
services.AddSingleton<IOcelotConfigurationRepository, ConsulOcelotConfigurationRepository>(); services.AddSingleton<IOcelotConfigurationRepository, ConsulOcelotConfigurationRepository>();
return services; return services;
} }
public static IServiceCollection AddOcelot(this IServiceCollection services,
IConfigurationRoot configurationRoot)
{
Action<ConfigurationBuilderCachePart> defaultCachingSettings = x =>
{
x.WithDictionaryHandle();
};
return services.AddOcelot(configurationRoot, defaultCachingSettings);
}
public static IServiceCollection AddOcelot(this IServiceCollection services, IConfigurationRoot configurationRoot, Action<ConfigurationBuilderCachePart> settings) public static IServiceCollection AddOcelot(this IServiceCollection services, IConfigurationRoot configurationRoot, Action<ConfigurationBuilderCachePart> settings)
{ {
var cacheManagerOutputCache = CacheFactory.Build<HttpResponseMessage>("OcelotOutputCache", settings); var cacheManagerOutputCache = CacheFactory.Build<HttpResponseMessage>("OcelotOutputCache", settings);

View File

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ocelot.Configuration;
using Ocelot.Configuration.Provider; using Ocelot.Configuration.Provider;
using Ocelot.DownstreamRouteFinder.UrlMatcher; using Ocelot.DownstreamRouteFinder.UrlMatcher;
using Ocelot.Errors; using Ocelot.Errors;
@ -12,24 +13,20 @@ namespace Ocelot.DownstreamRouteFinder.Finder
{ {
public class DownstreamRouteFinder : IDownstreamRouteFinder public class DownstreamRouteFinder : IDownstreamRouteFinder
{ {
private readonly IOcelotConfigurationProvider _configProvider;
private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; private readonly IUrlPathToUrlTemplateMatcher _urlMatcher;
private readonly IUrlPathPlaceholderNameAndValueFinder _urlPathPlaceholderNameAndValueFinder; private readonly IUrlPathPlaceholderNameAndValueFinder _urlPathPlaceholderNameAndValueFinder;
public DownstreamRouteFinder(IOcelotConfigurationProvider configProvider, IUrlPathToUrlTemplateMatcher urlMatcher, IUrlPathPlaceholderNameAndValueFinder urlPathPlaceholderNameAndValueFinder) public DownstreamRouteFinder(IUrlPathToUrlTemplateMatcher urlMatcher, IUrlPathPlaceholderNameAndValueFinder urlPathPlaceholderNameAndValueFinder)
{ {
_configProvider = configProvider;
_urlMatcher = urlMatcher; _urlMatcher = urlMatcher;
_urlPathPlaceholderNameAndValueFinder = urlPathPlaceholderNameAndValueFinder; _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('/'); upstreamUrlPath = upstreamUrlPath.SetLastCharacterAs('/');
var configuration = await _configProvider.Get(); var applicableReRoutes = configuration.ReRoutes.Where(r => r.UpstreamHttpMethod.Count == 0 || r.UpstreamHttpMethod.Select(x => x.Method.ToLower()).Contains(upstreamHttpMethod.ToLower()));
var applicableReRoutes = configuration.Data.ReRoutes.Where(r => r.UpstreamHttpMethod.Count == 0 || r.UpstreamHttpMethod.Select(x => x.Method.ToLower()).Contains(upstreamHttpMethod.ToLower()));
foreach (var reRoute in applicableReRoutes) foreach (var reRoute in applicableReRoutes)
{ {

View File

@ -1,10 +1,11 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Ocelot.Configuration;
using Ocelot.Responses; using Ocelot.Responses;
namespace Ocelot.DownstreamRouteFinder.Finder namespace Ocelot.DownstreamRouteFinder.Finder
{ {
public interface IDownstreamRouteFinder public interface IDownstreamRouteFinder
{ {
Task<Response<DownstreamRoute>> FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod); Response<DownstreamRoute> FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod, IOcelotConfiguration configuration);
} }
} }

View File

@ -2,6 +2,7 @@ using System.Linq;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.Provider;
using Ocelot.DownstreamRouteFinder.Finder; using Ocelot.DownstreamRouteFinder.Finder;
using Ocelot.Infrastructure.Extensions; using Ocelot.Infrastructure.Extensions;
using Ocelot.Infrastructure.RequestData; using Ocelot.Infrastructure.RequestData;
@ -16,13 +17,17 @@ namespace Ocelot.DownstreamRouteFinder.Middleware
private readonly RequestDelegate _next; private readonly RequestDelegate _next;
private readonly IDownstreamRouteFinder _downstreamRouteFinder; private readonly IDownstreamRouteFinder _downstreamRouteFinder;
private readonly IOcelotLogger _logger; private readonly IOcelotLogger _logger;
private readonly IOcelotConfigurationProvider _configProvider;
public DownstreamRouteFinderMiddleware(RequestDelegate next, public DownstreamRouteFinderMiddleware(RequestDelegate next,
IOcelotLoggerFactory loggerFactory, IOcelotLoggerFactory loggerFactory,
IDownstreamRouteFinder downstreamRouteFinder, IDownstreamRouteFinder downstreamRouteFinder,
IRequestScopedDataRepository requestScopedDataRepository) IRequestScopedDataRepository requestScopedDataRepository,
IOcelotConfigurationProvider configProvider)
:base(requestScopedDataRepository) :base(requestScopedDataRepository)
{ {
_configProvider = configProvider;
_next = next; _next = next;
_downstreamRouteFinder = downstreamRouteFinder; _downstreamRouteFinder = downstreamRouteFinder;
_logger = loggerFactory.CreateLogger<DownstreamRouteFinderMiddleware>(); _logger = loggerFactory.CreateLogger<DownstreamRouteFinderMiddleware>();
@ -32,9 +37,19 @@ namespace Ocelot.DownstreamRouteFinder.Middleware
{ {
var upstreamUrlPath = context.Request.Path.ToString(); 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); _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) if (downstreamRoute.IsError)
{ {

View File

@ -5,6 +5,6 @@ namespace Ocelot.LoadBalancer.LoadBalancers
{ {
public interface ILoadBalancerFactory public interface ILoadBalancerFactory
{ {
Task<ILoadBalancer> Get(ReRoute reRoute); Task<ILoadBalancer> Get(ReRoute reRoute, ServiceProviderConfiguration config);
} }
} }

View File

@ -1,10 +1,11 @@
using Ocelot.Responses; using System.Threading.Tasks;
using Ocelot.Configuration;
using Ocelot.Responses;
namespace Ocelot.LoadBalancer.LoadBalancers namespace Ocelot.LoadBalancer.LoadBalancers
{ {
public interface ILoadBalancerHouse public interface ILoadBalancerHouse
{ {
Response<ILoadBalancer> Get(string key); Task<Response<ILoadBalancer>> Get(ReRoute reRoute, ServiceProviderConfiguration config);
Response Add(string key, ILoadBalancer loadBalancer);
} }
} }

View File

@ -8,14 +8,14 @@ using Ocelot.Values;
namespace Ocelot.LoadBalancer.LoadBalancers namespace Ocelot.LoadBalancer.LoadBalancers
{ {
public class LeastConnectionLoadBalancer : ILoadBalancer public class LeastConnection : ILoadBalancer
{ {
private readonly Func<Task<List<Service>>> _services; private readonly Func<Task<List<Service>>> _services;
private readonly List<Lease> _leases; private readonly List<Lease> _leases;
private readonly string _serviceName; private readonly string _serviceName;
private static readonly object _syncLock = new object(); 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; _services = services;
_serviceName = serviceName; _serviceName = serviceName;

View File

@ -12,16 +12,16 @@ namespace Ocelot.LoadBalancer.LoadBalancers
_serviceProviderFactory = serviceProviderFactory; _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) switch (reRoute.LoadBalancer)
{ {
case "RoundRobin": case "RoundRobin":
return new RoundRobinLoadBalancer(async () => await serviceProvider.Get()); return new RoundRobin(async () => await serviceProvider.Get());
case "LeastConnection": case "LeastConnection":
return new LeastConnectionLoadBalancer(async () => await serviceProvider.Get(), reRoute.ServiceProviderConfiguraion.ServiceName); return new LeastConnection(async () => await serviceProvider.Get(), reRoute.ServiceName);
default: default:
return new NoLoadBalancer(await serviceProvider.Get()); return new NoLoadBalancer(await serviceProvider.Get());
} }

View File

@ -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; using Ocelot.Responses;
namespace Ocelot.LoadBalancer.LoadBalancers namespace Ocelot.LoadBalancer.LoadBalancers
{ {
public class LoadBalancerHouse : ILoadBalancerHouse 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; try
{
if(_loadBalancers.TryGetValue(reRoute.ReRouteKey, out var loadBalancer))
{
loadBalancer = _loadBalancers[reRoute.ReRouteKey];
if(_loadBalancers.TryGetValue(key, out loadBalancer)) if(reRoute.LoadBalancer != loadBalancer.GetType().Name)
{ {
return new OkResponse<ILoadBalancer>(_loadBalancers[key]); 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>() 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)
{
if (!_loadBalancers.ContainsKey(key))
{
_loadBalancers.Add(key, loadBalancer);
} }
_loadBalancers.Remove(key); private void AddLoadBalancer(string key, ILoadBalancer loadBalancer)
_loadBalancers.Add(key, loadBalancer); {
return new OkResponse(); _loadBalancers.AddOrUpdate(key, loadBalancer, (x, y) => loadBalancer);
} }
} }
} }

View File

@ -6,13 +6,13 @@ using System;
namespace Ocelot.LoadBalancer.LoadBalancers namespace Ocelot.LoadBalancer.LoadBalancers
{ {
public class RoundRobinLoadBalancer : ILoadBalancer public class RoundRobin : ILoadBalancer
{ {
private readonly Func<Task<List<Service>>> _services; private readonly Func<Task<List<Service>>> _services;
private int _last; private int _last;
public RoundRobinLoadBalancer(Func<Task<List<Service>>> services) public RoundRobin(Func<Task<List<Service>>> services)
{ {
_services = services; _services = services;
} }

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.Provider;
using Ocelot.Infrastructure.RequestData; using Ocelot.Infrastructure.RequestData;
using Ocelot.LoadBalancer.LoadBalancers; using Ocelot.LoadBalancer.LoadBalancers;
using Ocelot.Logging; using Ocelot.Logging;
@ -28,7 +29,7 @@ namespace Ocelot.LoadBalancer.Middleware
public async Task Invoke(HttpContext context) public async Task Invoke(HttpContext context)
{ {
var loadBalancer = _loadBalancerHouse.Get(DownstreamRoute.ReRoute.ReRouteKey); var loadBalancer = await _loadBalancerHouse.Get(DownstreamRoute.ReRoute, ServiceProviderConfiguration);
if(loadBalancer.IsError) if(loadBalancer.IsError)
{ {
_logger.LogDebug("there was an error retriving the loadbalancer, setting pipeline error"); _logger.LogDebug("there was an error retriving the loadbalancer, setting pipeline error");

View File

@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Http; using System.Net.Http;
using Ocelot.Configuration;
using Ocelot.DownstreamRouteFinder; using Ocelot.DownstreamRouteFinder;
using Ocelot.Errors; using Ocelot.Errors;
using Ocelot.Infrastructure.RequestData; using Ocelot.Infrastructure.RequestData;
@ -30,11 +31,18 @@ namespace Ocelot.Middleware
public HttpResponseMessage HttpResponseMessage => _requestScopedDataRepository.Get<HttpResponseMessage>("HttpResponseMessage").Data; public HttpResponseMessage HttpResponseMessage => _requestScopedDataRepository.Get<HttpResponseMessage>("HttpResponseMessage").Data;
public ServiceProviderConfiguration ServiceProviderConfiguration => _requestScopedDataRepository.Get<ServiceProviderConfiguration>("ServiceProviderConfiguration").Data;
public void SetDownstreamRouteForThisRequest(DownstreamRoute downstreamRoute) public void SetDownstreamRouteForThisRequest(DownstreamRoute downstreamRoute)
{ {
_requestScopedDataRepository.Add("DownstreamRoute", downstreamRoute); _requestScopedDataRepository.Add("DownstreamRoute", downstreamRoute);
} }
public void SetServiceProviderConfigurationForThisRequest(ServiceProviderConfiguration serviceProviderConfiguration)
{
_requestScopedDataRepository.Add("ServiceProviderConfiguration", serviceProviderConfiguration);
}
public void SetUpstreamRequestForThisRequest(Request.Request request) public void SetUpstreamRequestForThisRequest(Request.Request request)
{ {
_requestScopedDataRepository.Add("Request", request); _requestScopedDataRepository.Add("Request", request);

View File

@ -32,7 +32,7 @@ namespace Ocelot.Request.Middleware
{ {
_logger.LogDebug("started calling request builder middleware"); _logger.LogDebug("started calling request builder middleware");
var qosProvider = _qosProviderHouse.Get(DownstreamRoute.ReRoute.ReRouteKey); var qosProvider = _qosProviderHouse.Get(DownstreamRoute.ReRoute);
if (qosProvider.IsError) if (qosProvider.IsError)
{ {

View 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; }
}
}

View File

@ -0,0 +1,7 @@
namespace Ocelot.Requester.QoS
{
public interface IQoSProvider
{
CircuitBreaker CircuitBreaker { get; }
}
}

View File

@ -1,13 +1,5 @@
using System; using Ocelot.Configuration;
using System.Collections.Generic;
using System.Net.Http;
using Ocelot.Configuration;
using Ocelot.LoadBalancer.LoadBalancers; using Ocelot.LoadBalancer.LoadBalancers;
using Ocelot.Logging;
using Ocelot.Responses;
using Polly;
using Polly.CircuitBreaker;
using Polly.Timeout;
namespace Ocelot.Requester.QoS namespace Ocelot.Requester.QoS
{ {
@ -15,131 +7,4 @@ namespace Ocelot.Requester.QoS
{ {
IQoSProvider Get(ReRoute reRoute); 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();
}
}
} }

View File

@ -0,0 +1,10 @@
using Ocelot.Configuration;
using Ocelot.Responses;
namespace Ocelot.Requester.QoS
{
public interface IQosProviderHouse
{
Response<IQoSProvider> Get(ReRoute reRoute);
}
}

View File

@ -0,0 +1,7 @@
namespace Ocelot.Requester.QoS
{
public class NoQoSProvider : IQoSProvider
{
public CircuitBreaker CircuitBreaker { get; }
}
}

View 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;
}
}

View 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();
}
}
}

View 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);
}
}
}

View File

@ -2,14 +2,14 @@ namespace Ocelot.ServiceDiscovery
{ {
public class ConsulRegistryConfiguration public class ConsulRegistryConfiguration
{ {
public ConsulRegistryConfiguration(string hostName, int port, string serviceName) public ConsulRegistryConfiguration(string hostName, int port, string keyOfServiceInConsul)
{ {
HostName = hostName; HostName = hostName;
Port = port; 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 string HostName { get; private set; }
public int Port { get; private set; } public int Port { get; private set; }
} }

View File

@ -10,7 +10,7 @@ namespace Ocelot.ServiceDiscovery
{ {
public class ConsulServiceDiscoveryProvider : IServiceDiscoveryProvider public class ConsulServiceDiscoveryProvider : IServiceDiscoveryProvider
{ {
private readonly ConsulRegistryConfiguration _configuration; private readonly ConsulRegistryConfiguration _consulConfig;
private readonly ConsulClient _consul; private readonly ConsulClient _consul;
private const string VersionPrefix = "version-"; private const string VersionPrefix = "version-";
@ -18,17 +18,17 @@ namespace Ocelot.ServiceDiscovery
{ {
var consulHost = string.IsNullOrEmpty(consulRegistryConfiguration?.HostName) ? "localhost" : consulRegistryConfiguration.HostName; var consulHost = string.IsNullOrEmpty(consulRegistryConfiguration?.HostName) ? "localhost" : consulRegistryConfiguration.HostName;
var consulPort = consulRegistryConfiguration?.Port ?? 8500; var consulPort = consulRegistryConfiguration?.Port ?? 8500;
_configuration = new ConsulRegistryConfiguration(consulHost, consulPort, consulRegistryConfiguration?.ServiceName); _consulConfig = new ConsulRegistryConfiguration(consulHost, consulPort, consulRegistryConfiguration?.KeyOfServiceInConsul);
_consul = new ConsulClient(config => _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() 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); var services = queryResult.Response.Select(BuildService);

View File

@ -4,6 +4,6 @@ namespace Ocelot.ServiceDiscovery
{ {
public interface IServiceDiscoveryProviderFactory public interface IServiceDiscoveryProviderFactory
{ {
IServiceDiscoveryProvider Get(ServiceProviderConfiguration serviceConfig); IServiceDiscoveryProvider Get(ServiceProviderConfiguration serviceConfig, ReRoute reRoute);
} }
} }

View File

@ -6,17 +6,17 @@ namespace Ocelot.ServiceDiscovery
{ {
public class ServiceDiscoveryProviderFactory : IServiceDiscoveryProviderFactory 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>() var services = new List<Service>()
{ {
new Service(serviceConfig.ServiceName, new Service(reRoute.ServiceName,
new HostAndPort(serviceConfig.DownstreamHost, serviceConfig.DownstreamPort), new HostAndPort(reRoute.DownstreamHost, reRoute.DownstreamPort),
string.Empty, string.Empty,
string.Empty, string.Empty,
new string[0]) new string[0])
@ -25,9 +25,9 @@ namespace Ocelot.ServiceDiscovery
return new ConfigurationServiceProvider(services); 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); return new ConsulServiceDiscoveryProvider(consulRegistryConfiguration);
} }
} }

View File

@ -8,8 +8,8 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Newtonsoft.Json; using Newtonsoft.Json;
using Ocelot.Configuration; using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.File; using Ocelot.Configuration.File;
using Ocelot.ServiceDiscovery;
using TestStack.BDDfy; using TestStack.BDDfy;
using Xunit; using Xunit;
@ -48,7 +48,6 @@ namespace Ocelot.AcceptanceTests
{ {
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider() ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{ {
Provider = "Consul",
Host = "localhost", Host = "localhost",
Port = 9500 Port = 9500
} }
@ -57,18 +56,71 @@ namespace Ocelot.AcceptanceTests
var fakeConsulServiceDiscoveryUrl = "http://localhost:9500"; var fakeConsulServiceDiscoveryUrl = "http://localhost:9500";
var consulConfig = new ConsulRegistryConfiguration("localhost", 9500, "Ocelot");
this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl)) 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.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfig(consulConfig)) .And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfig())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy(); .BDDfy();
} }
[Fact]
public void should_fix_issue_142()
{
var consulPort = 8500;
var configuration = new FileConfiguration
{
GlobalConfiguration = new FileGlobalConfiguration()
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Host = "localhost",
Port = consulPort
}
}
};
var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}";
var serviceProviderConfig = new ServiceProviderConfigurationBuilder()
.WithServiceDiscoveryProviderHost("localhost")
.WithServiceDiscoveryProviderPort(consulPort)
.Build();
var reRoute = new ReRouteBuilder()
.WithDownstreamPathTemplate("/status")
.WithUpstreamTemplatePattern("^(?i)/cs/status/$")
.WithDownstreamScheme("http")
.WithDownstreamHost("localhost")
.WithDownstreamPort(51779)
.WithUpstreamPathTemplate("/cs/status")
.WithUpstreamHttpMethod(new List<string> {"Get"})
.WithReRouteKey("/cs/status|Get")
.WithHttpHandlerOptions(new HttpHandlerOptions(true, false))
.Build();
var reRoutes = new List<ReRoute> { reRoute };
var config = new OcelotConfiguration(reRoutes, null, serviceProviderConfig);
this.Given(x => GivenTheConsulConfigurationIs(config))
.And(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl))
.And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51779", "/status", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfig())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/cs/status"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
private void GivenTheConsulConfigurationIs(OcelotConfiguration config)
{
_config = config;
}
private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url) private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url)
{ {
_fakeConsulBuilder = new WebHostBuilder() _fakeConsulBuilder = new WebHostBuilder()
@ -137,7 +189,7 @@ namespace Ocelot.AcceptanceTests
public string Session => "adf4238a-882b-9ddc-4a9d-5b6758e4159e"; 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() _builder = new WebHostBuilder()
.UseUrls(url) .UseUrls(url)
@ -147,6 +199,8 @@ namespace Ocelot.AcceptanceTests
.UseUrls(url) .UseUrls(url)
.Configure(app => .Configure(app =>
{ {
app.UsePathBase(basePath);
app.Run(async context => app.Run(async context =>
{ {
context.Response.StatusCode = statusCode; context.Response.StatusCode = statusCode;

View File

@ -33,10 +33,11 @@ namespace Ocelot.AcceptanceTests
[Fact] [Fact]
public void should_use_service_discovery_and_load_balance_request() public void should_use_service_discovery_and_load_balance_request()
{ {
var consulPort = 8501;
var serviceName = "product"; var serviceName = "product";
var downstreamServiceOneUrl = "http://localhost:50879"; var downstreamServiceOneUrl = "http://localhost:50879";
var downstreamServiceTwoUrl = "http://localhost:50880"; var downstreamServiceTwoUrl = "http://localhost:50880";
var fakeConsulServiceDiscoveryUrl = "http://localhost:8500"; var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}";
var serviceEntryOne = new ServiceEntry() var serviceEntryOne = new ServiceEntry()
{ {
Service = new AgentService() Service = new AgentService()
@ -72,15 +73,15 @@ namespace Ocelot.AcceptanceTests
UpstreamHttpMethod = new List<string> { "Get" }, UpstreamHttpMethod = new List<string> { "Get" },
ServiceName = serviceName, ServiceName = serviceName,
LoadBalancer = "LeastConnection", LoadBalancer = "LeastConnection",
UseServiceDiscovery = true,
} }
}, },
GlobalConfiguration = new FileGlobalConfiguration() GlobalConfiguration = new FileGlobalConfiguration()
{ {
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider() ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{ {
Provider = "Consul",
Host = "localhost", Host = "localhost",
Port = 8500 Port = consulPort
} }
} }
}; };
@ -99,8 +100,8 @@ namespace Ocelot.AcceptanceTests
private void ThenBothServicesCalledRealisticAmountOfTimes() private void ThenBothServicesCalledRealisticAmountOfTimes()
{ {
_counterOne.ShouldBe(25); _counterOne.ShouldBeInRange(24,26);
_counterTwo.ShouldBe(25); _counterOne.ShouldBeInRange(24,26);
} }
private void ThenTheTwoServicesShouldHaveBeenCalledTimes(int expected) private void ThenTheTwoServicesShouldHaveBeenCalledTimes(int expected)

View File

@ -0,0 +1,82 @@
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, settings);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
app.UseOcelot().Wait();
}
}
public class ConsulStartup
{
public ConsulStartup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddJsonFile("configuration.json")
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
Action<ConfigurationBuilderCachePart> settings = (x) =>
{
x.WithDictionaryHandle();
};
services.AddOcelot(Configuration, settings);
services.AddStoreOcelotConfigurationInConsul(Configuration);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
app.UseOcelot().Wait();
}
}
}

View File

@ -107,18 +107,17 @@ namespace Ocelot.AcceptanceTests
_ocelotClient = _ocelotServer.CreateClient(); _ocelotClient = _ocelotServer.CreateClient();
} }
public void GivenOcelotIsRunningUsingConsulToStoreConfig(ConsulRegistryConfiguration consulConfig) public void GivenOcelotIsRunningUsingConsulToStoreConfig(/*ConsulRegistryConfiguration consulConfig*/)
{ {
_webHostBuilder = new WebHostBuilder(); _webHostBuilder = new WebHostBuilder();
_webHostBuilder.ConfigureServices(s => _webHostBuilder.ConfigureServices(s =>
{ {
s.AddSingleton(_webHostBuilder); s.AddSingleton(_webHostBuilder);
s.AddOcelotStoreConfigurationInConsul(consulConfig);
}); });
_ocelotServer = new TestServer(_webHostBuilder _ocelotServer = new TestServer(_webHostBuilder
.UseStartup<Startup>()); .UseStartup<ConsulStartup>());
_ocelotClient = _ocelotServer.CreateClient(); _ocelotClient = _ocelotServer.CreateClient();
} }
@ -131,7 +130,6 @@ namespace Ocelot.AcceptanceTests
response.GlobalConfiguration.RequestIdKey.ShouldBe(expected.GlobalConfiguration.RequestIdKey); response.GlobalConfiguration.RequestIdKey.ShouldBe(expected.GlobalConfiguration.RequestIdKey);
response.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Host); response.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Host);
response.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Port); 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++) for(var i = 0; i < response.ReRoutes.Count; i++)
{ {
@ -381,42 +379,4 @@ namespace Ocelot.AcceptanceTests
_response.Headers.GetValues(RequestIdKey).First().ShouldBe(expected); _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();
}
}
} }

View File

@ -107,7 +107,6 @@ namespace Ocelot.IntegrationTests
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{ {
Host = "127.0.0.1", Host = "127.0.0.1",
Provider = "test"
} }
}, },
@ -332,7 +331,6 @@ namespace Ocelot.IntegrationTests
response.GlobalConfiguration.RequestIdKey.ShouldBe(expected.GlobalConfiguration.RequestIdKey); response.GlobalConfiguration.RequestIdKey.ShouldBe(expected.GlobalConfiguration.RequestIdKey);
response.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Host); response.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Host);
response.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Port); 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++) for (var i = 0; i < response.ReRoutes.Count; i++)
{ {

View File

@ -1,133 +1,62 @@
// using System.Collections.Generic; using System.Collections.Generic;
// using Ocelot.Configuration; using Ocelot.Configuration;
// using Ocelot.Configuration.Builder; using Ocelot.Configuration.Builder;
// using Ocelot.Configuration.Creator; using Ocelot.Configuration.Creator;
// using Ocelot.Configuration.File; using Ocelot.Configuration.File;
// using Shouldly; using Shouldly;
// using TestStack.BDDfy; using TestStack.BDDfy;
// using Xunit; using Xunit;
// namespace Ocelot.UnitTests.Configuration namespace Ocelot.UnitTests.Configuration
// { {
// public class AuthenticationOptionsCreatorTests public class AuthenticationOptionsCreatorTests
// { {
// private readonly AuthenticationOptionsCreator _authOptionsCreator; private readonly AuthenticationOptionsCreator _authOptionsCreator;
// private FileReRoute _fileReRoute; private FileReRoute _fileReRoute;
// private AuthenticationOptions _result; private AuthenticationOptions _result;
// public AuthenticationOptionsCreatorTests() public AuthenticationOptionsCreatorTests()
// { {
// _authOptionsCreator = new AuthenticationOptionsCreator(new AuthenticationProviderConfigCreator()); _authOptionsCreator = new AuthenticationOptionsCreator();
// } }
// [Fact] [Fact]
// public void should_return_auth_options() public void should_return_auth_options()
// { {
// var fileReRoute = new FileReRoute() var fileReRoute = new FileReRoute()
// { {
// AuthenticationOptions = new FileAuthenticationOptions AuthenticationOptions = new FileAuthenticationOptions
// { {
// Provider = "Geoff", AuthenticationProviderKey = "Test",
// IdentityServerConfig = new FileIdentityServerConfig() AllowedScopes = new List<string> { "cheese" },
// { }
// ProviderRootUrl = "http://www.bbc.co.uk/", };
// ApiName = "Laura",
// RequireHttps = true,
// ApiSecret = "secret"
// },
// AllowedScopes = new List<string> { "cheese" },
// } var expected = new AuthenticationOptionsBuilder()
// }; .WithAllowedScopes(fileReRoute.AuthenticationOptions?.AllowedScopes)
.WithAuthenticationProviderKey("Test")
.Build();
// var authenticationConfig = new IdentityServerConfigBuilder() this.Given(x => x.GivenTheFollowing(fileReRoute))
// .WithProviderRootUrl(fileReRoute.AuthenticationOptions?.IdentityServerConfig?.ProviderRootUrl) .When(x => x.WhenICreateTheAuthenticationOptions())
// .WithApiName(fileReRoute.AuthenticationOptions?.IdentityServerConfig?.ApiName) .Then(x => x.ThenTheFollowingConfigIsReturned(expected))
// .WithRequireHttps(fileReRoute.AuthenticationOptions.IdentityServerConfig.RequireHttps) .BDDfy();
// .WithApiSecret(fileReRoute.AuthenticationOptions?.IdentityServerConfig?.ApiSecret) }
// .Build();
// var expected = new AuthenticationOptionsBuilder() private void GivenTheFollowing(FileReRoute fileReRoute)
// .WithProvider(fileReRoute.AuthenticationOptions?.Provider) {
// .WithAllowedScopes(fileReRoute.AuthenticationOptions?.AllowedScopes) _fileReRoute = fileReRoute;
// .WithConfig(authenticationConfig) }
// .Build();
// this.Given(x => x.GivenTheFollowing(fileReRoute)) private void WhenICreateTheAuthenticationOptions()
// .When(x => x.WhenICreateTheAuthenticationOptions()) {
// .Then(x => x.ThenTheFollowingIdentityServerConfigIsReturned(expected)) _result = _authOptionsCreator.Create(_fileReRoute);
// .BDDfy(); }
// }
// [Fact] private void ThenTheFollowingConfigIsReturned(AuthenticationOptions expected)
// public void should_return_Jwt_auth_options() {
// { _result.AllowedScopes.ShouldBe(expected.AllowedScopes);
// var fileReRoute = new FileReRoute() _result.AuthenticationProviderKey.ShouldBe(expected.AuthenticationProviderKey);
// { }
// AuthenticationOptions = new FileAuthenticationOptions }
// { }
// Provider = "Jwt",
// JwtConfig = new FileJwtConfig()
// {
// Audience = "Audience",
// Authority = "Authority"
// },
// AllowedScopes = new List<string> { "cheese" }
// }
// };
// 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);
// }
// }
// }

View File

@ -1,5 +1,4 @@
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Moq; using Moq;
using Ocelot.Cache; using Ocelot.Cache;
@ -8,9 +7,7 @@ using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator; using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File; using Ocelot.Configuration.File;
using Ocelot.Configuration.Validator; using Ocelot.Configuration.Validator;
using Ocelot.LoadBalancer.LoadBalancers;
using Ocelot.Logging; using Ocelot.Logging;
using Ocelot.Requester.QoS;
using Ocelot.Responses; using Ocelot.Responses;
using Shouldly; using Shouldly;
using TestStack.BDDfy; using TestStack.BDDfy;
@ -18,8 +15,6 @@ using Xunit;
namespace Ocelot.UnitTests.Configuration namespace Ocelot.UnitTests.Configuration
{ {
using System.Collections;
using Ocelot.UnitTests.TestData; using Ocelot.UnitTests.TestData;
public class FileConfigurationCreatorTests public class FileConfigurationCreatorTests
@ -30,12 +25,6 @@ namespace Ocelot.UnitTests.Configuration
private FileConfiguration _fileConfiguration; private FileConfiguration _fileConfiguration;
private readonly Mock<IOcelotLoggerFactory> _logger; private readonly Mock<IOcelotLoggerFactory> _logger;
private readonly FileOcelotConfigurationCreator _ocelotConfigurationCreator; 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<IClaimsToThingCreator> _claimsToThingCreator;
private Mock<IAuthenticationOptionsCreator> _authOptionsCreator; private Mock<IAuthenticationOptionsCreator> _authOptionsCreator;
private Mock<IUpstreamTemplatePatternCreator> _upstreamTemplatePatternCreator; private Mock<IUpstreamTemplatePatternCreator> _upstreamTemplatePatternCreator;
@ -49,15 +38,9 @@ namespace Ocelot.UnitTests.Configuration
public FileConfigurationCreatorTests() public FileConfigurationCreatorTests()
{ {
_qosProviderFactory = new Mock<IQoSProviderFactory>();
_qosProviderHouse = new Mock<IQosProviderHouse>();
_qosProvider = new Mock<IQoSProvider>();
_logger = new Mock<IOcelotLoggerFactory>(); _logger = new Mock<IOcelotLoggerFactory>();
_validator = new Mock<IConfigurationValidator>(); _validator = new Mock<IConfigurationValidator>();
_fileConfig = new Mock<IOptions<FileConfiguration>>(); _fileConfig = new Mock<IOptions<FileConfiguration>>();
_loadBalancerFactory = new Mock<ILoadBalancerFactory>();
_loadBalancerHouse = new Mock<ILoadBalancerHouse>();
_loadBalancer = new Mock<ILoadBalancer>();
_claimsToThingCreator = new Mock<IClaimsToThingCreator>(); _claimsToThingCreator = new Mock<IClaimsToThingCreator>();
_authOptionsCreator = new Mock<IAuthenticationOptionsCreator>(); _authOptionsCreator = new Mock<IAuthenticationOptionsCreator>();
_upstreamTemplatePatternCreator = new Mock<IUpstreamTemplatePatternCreator>(); _upstreamTemplatePatternCreator = new Mock<IUpstreamTemplatePatternCreator>();
@ -71,13 +54,35 @@ namespace Ocelot.UnitTests.Configuration
_ocelotConfigurationCreator = new FileOcelotConfigurationCreator( _ocelotConfigurationCreator = new FileOcelotConfigurationCreator(
_fileConfig.Object, _validator.Object, _logger.Object, _fileConfig.Object, _validator.Object, _logger.Object,
_loadBalancerFactory.Object, _loadBalancerHouse.Object, _claimsToThingCreator.Object,
_qosProviderFactory.Object, _qosProviderHouse.Object, _claimsToThingCreator.Object,
_authOptionsCreator.Object, _upstreamTemplatePatternCreator.Object, _requestIdKeyCreator.Object, _authOptionsCreator.Object, _upstreamTemplatePatternCreator.Object, _requestIdKeyCreator.Object,
_serviceProviderConfigCreator.Object, _qosOptionsCreator.Object, _fileReRouteOptionsCreator.Object, _serviceProviderConfigCreator.Object, _qosOptionsCreator.Object, _fileReRouteOptionsCreator.Object,
_rateLimitOptions.Object, _regionCreator.Object, _httpHandlerOptionsCreator.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] [Fact]
public void should_call_region_creator() public void should_call_region_creator()
{ {
@ -182,40 +187,9 @@ namespace Ocelot.UnitTests.Configuration
})) }))
.And(x => x.GivenTheConfigIsValid()) .And(x => x.GivenTheConfigIsValid())
.And(x => x.GivenTheFollowingOptionsAreReturned(serviceOptions)) .And(x => x.GivenTheFollowingOptionsAreReturned(serviceOptions))
.And(x => x.GivenTheQosProviderFactoryReturns())
.And(x => x.GivenTheQosOptionsCreatorReturns(expected)) .And(x => x.GivenTheQosOptionsCreatorReturns(expected))
.When(x => x.WhenICreateTheConfig()) .When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheQosOptionsAre(expected)) .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(); .BDDfy();
} }
@ -310,7 +284,6 @@ namespace Ocelot.UnitTests.Configuration
{ {
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{ {
Provider = "consul",
Host = "127.0.0.1" Host = "127.0.0.1"
} }
} }
@ -324,12 +297,8 @@ namespace Ocelot.UnitTests.Configuration
.WithDownstreamPathTemplate("/products/{productId}") .WithDownstreamPathTemplate("/products/{productId}")
.WithUpstreamPathTemplate("/api/products/{productId}") .WithUpstreamPathTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder()
.WithUseServiceDiscovery(true) .WithUseServiceDiscovery(true)
.WithServiceDiscoveryProvider("consul")
.WithServiceDiscoveryProviderHost("127.0.0.1")
.WithServiceName("ProductService") .WithServiceName("ProductService")
.Build())
.Build() .Build()
})) }))
.BDDfy(); .BDDfy();
@ -363,9 +332,7 @@ namespace Ocelot.UnitTests.Configuration
.WithDownstreamPathTemplate("/products/{productId}") .WithDownstreamPathTemplate("/products/{productId}")
.WithUpstreamPathTemplate("/api/products/{productId}") .WithUpstreamPathTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder()
.WithUseServiceDiscovery(false) .WithUseServiceDiscovery(false)
.Build())
.Build() .Build()
})) }))
.BDDfy(); .BDDfy();
@ -516,7 +483,6 @@ namespace Ocelot.UnitTests.Configuration
.And(x => x.GivenTheAuthOptionsCreatorReturns(authenticationOptions)) .And(x => x.GivenTheAuthOptionsCreatorReturns(authenticationOptions))
.And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions)) .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
.And(x => x.GivenTheClaimsToThingCreatorReturns(new List<ClaimToThing> { new ClaimToThing("CustomerId", "CustomerId", "", 0) })) .And(x => x.GivenTheClaimsToThingCreatorReturns(new List<ClaimToThing> { new ClaimToThing("CustomerId", "CustomerId", "", 0) }))
.And(x => x.GivenTheLoadBalancerFactoryReturns())
.When(x => x.WhenICreateTheConfig()) .When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheReRoutesAre(expected)) .Then(x => x.ThenTheReRoutesAre(expected))
.And(x => x.ThenTheAuthenticationOptionsAre(expected)) .And(x => x.ThenTheAuthenticationOptionsAre(expected))
@ -550,7 +516,6 @@ namespace Ocelot.UnitTests.Configuration
.And(x => x.GivenTheConfigIsValid()) .And(x => x.GivenTheConfigIsValid())
.And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions)) .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
.And(x => x.GivenTheAuthOptionsCreatorReturns(authenticationOptions)) .And(x => x.GivenTheAuthOptionsCreatorReturns(authenticationOptions))
.And(x => x.GivenTheLoadBalancerFactoryReturns())
.When(x => x.WhenICreateTheConfig()) .When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheReRoutesAre(expected)) .Then(x => x.ThenTheReRoutesAre(expected))
.And(x => x.ThenTheAuthenticationOptionsAre(expected)) .And(x => x.ThenTheAuthenticationOptionsAre(expected))
@ -610,20 +575,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) private void ThenTheAuthenticationOptionsAre(List<ReRoute> expectedReRoutes)
{ {
for (int i = 0; i < _config.Data.ReRoutes.Count; i++) for (int i = 0; i < _config.Data.ReRoutes.Count; i++)
@ -634,44 +585,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) private void GivenTheClaimsToThingCreatorReturns(List<ClaimToThing> claimsToThing)
{ {
_claimsToThingCreator _claimsToThingCreator
@ -726,5 +639,17 @@ namespace Ocelot.UnitTests.Configuration
_config.Data.ReRoutes[0].QosOptionsOptions.ExceptionsAllowedBeforeBreaking.ShouldBe(qosOptions.ExceptionsAllowedBeforeBreaking); _config.Data.ReRoutes[0].QosOptionsOptions.ExceptionsAllowedBeforeBreaking.ShouldBe(qosOptions.ExceptionsAllowedBeforeBreaking);
_config.Data.ReRoutes[0].QosOptionsOptions.TimeoutValue.ShouldBe(qosOptions.TimeoutValue); _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);
}
} }
} }

View File

@ -43,7 +43,6 @@ namespace Ocelot.UnitTests.Configuration
AdministrationPath = "testy", AdministrationPath = "testy",
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{ {
Provider = "consul",
Port = 198, Port = 198,
Host = "blah" Host = "blah"
} }
@ -78,7 +77,6 @@ namespace Ocelot.UnitTests.Configuration
AdministrationPath = "asdas", AdministrationPath = "asdas",
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{ {
Provider = "consul",
Port = 198, Port = 198,
Host = "blah" Host = "blah"
} }
@ -111,7 +109,6 @@ namespace Ocelot.UnitTests.Configuration
_result.GlobalConfiguration.RequestIdKey.ShouldBe(expected.GlobalConfiguration.RequestIdKey); _result.GlobalConfiguration.RequestIdKey.ShouldBe(expected.GlobalConfiguration.RequestIdKey);
_result.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Host); _result.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Host);
_result.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Port); _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++) for(var i = 0; i < _result.ReRoutes.Count; i++)
{ {
@ -147,7 +144,6 @@ namespace Ocelot.UnitTests.Configuration
_result.GlobalConfiguration.RequestIdKey.ShouldBe(expected.GlobalConfiguration.RequestIdKey); _result.GlobalConfiguration.RequestIdKey.ShouldBe(expected.GlobalConfiguration.RequestIdKey);
_result.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Host); _result.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Host);
_result.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Port); _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++) for(var i = 0; i < _result.ReRoutes.Count; i++)
{ {

View File

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using Moq; using Moq;
using Ocelot.Configuration; using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator; using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File; using Ocelot.Configuration.File;
using Ocelot.Configuration.Repository; using Ocelot.Configuration.Repository;
@ -36,7 +37,8 @@ namespace Ocelot.UnitTests.Configuration
public void should_set_configuration() public void should_set_configuration()
{ {
var fileConfig = new FileConfiguration(); 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)) this.Given(x => GivenTheFollowingConfiguration(fileConfig))
.And(x => GivenTheRepoReturns(new OkResponse())) .And(x => GivenTheRepoReturns(new OkResponse()))

View File

@ -92,6 +92,8 @@ namespace Ocelot.UnitTests.Configuration
}; };
public string AdministrationPath {get;} public string AdministrationPath {get;}
public ServiceProviderConfiguration ServiceProviderConfiguration => throw new NotImplementedException();
} }
} }
} }

View File

@ -1,6 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using Moq; using Moq;
using Ocelot.Configuration; using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator; using Ocelot.Configuration.Creator;
using Ocelot.Configuration.Provider; using Ocelot.Configuration.Provider;
using Ocelot.Configuration.Repository; using Ocelot.Configuration.Repository;
@ -27,9 +28,11 @@ namespace Ocelot.UnitTests.Configuration
[Fact] [Fact]
public void should_get_config() 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()) .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(); .BDDfy();
} }

View File

@ -29,14 +29,12 @@ namespace Ocelot.UnitTests.Configuration
{ {
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{ {
Provider = "consul",
Host = "127.0.0.1", Host = "127.0.0.1",
Port = 1234 Port = 1234
} }
}; };
var expected = new ServiceProviderConfigurationBuilder() var expected = new ServiceProviderConfigurationBuilder()
.WithServiceDiscoveryProvider("consul")
.WithServiceDiscoveryProviderHost("127.0.0.1") .WithServiceDiscoveryProviderHost("127.0.0.1")
.WithServiceDiscoveryProviderPort(1234) .WithServiceDiscoveryProviderPort(1234)
.Build(); .Build();
@ -60,15 +58,11 @@ namespace Ocelot.UnitTests.Configuration
private void WhenICreate() private void WhenICreate()
{ {
_result = _creator.Create(_reRoute, _globalConfig); _result = _creator.Create(_globalConfig);
} }
private void ThenTheConfigIs(ServiceProviderConfiguration expected) 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.ServiceProviderHost.ShouldBe(expected.ServiceProviderHost);
_result.ServiceProviderPort.ShouldBe(expected.ServiceProviderPort); _result.ServiceProviderPort.ShouldBe(expected.ServiceProviderPort);
} }

View File

@ -4,7 +4,9 @@
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Moq; using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder; using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Provider;
using Ocelot.DownstreamRouteFinder; using Ocelot.DownstreamRouteFinder;
using Ocelot.DownstreamRouteFinder.Finder; using Ocelot.DownstreamRouteFinder.Finder;
using Ocelot.DownstreamRouteFinder.Middleware; using Ocelot.DownstreamRouteFinder.Middleware;
@ -17,10 +19,13 @@
public class DownstreamRouteFinderMiddlewareTests : ServerHostedMiddlewareTest public class DownstreamRouteFinderMiddlewareTests : ServerHostedMiddlewareTest
{ {
private readonly Mock<IDownstreamRouteFinder> _downstreamRouteFinder; private readonly Mock<IDownstreamRouteFinder> _downstreamRouteFinder;
private readonly Mock<IOcelotConfigurationProvider> _provider;
private Response<DownstreamRoute> _downstreamRoute; private Response<DownstreamRoute> _downstreamRoute;
private IOcelotConfiguration _config;
public DownstreamRouteFinderMiddlewareTests() public DownstreamRouteFinderMiddlewareTests()
{ {
_provider = new Mock<IOcelotConfigurationProvider>();
_downstreamRouteFinder = new Mock<IDownstreamRouteFinder>(); _downstreamRouteFinder = new Mock<IDownstreamRouteFinder>();
GivenTheTestServerIsConfigured(); GivenTheTestServerIsConfigured();
@ -29,6 +34,8 @@
[Fact] [Fact]
public void should_call_scoped_data_repository_correctly() public void should_call_scoped_data_repository_correctly()
{ {
var config = new OcelotConfiguration(null, null, new ServiceProviderConfigurationBuilder().Build());
this.Given(x => x.GivenTheDownStreamRouteFinderReturns( this.Given(x => x.GivenTheDownStreamRouteFinderReturns(
new DownstreamRoute( new DownstreamRoute(
new List<UrlPathPlaceholderNameAndValue>(), new List<UrlPathPlaceholderNameAndValue>(),
@ -36,16 +43,26 @@
.WithDownstreamPathTemplate("any old string") .WithDownstreamPathTemplate("any old string")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.Build()))) .Build())))
.And(x => GivenTheFollowingConfig(config))
.When(x => x.WhenICallTheMiddleware()) .When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly())
.BDDfy(); .BDDfy();
} }
private void GivenTheFollowingConfig(IOcelotConfiguration config)
{
_config = config;
_provider
.Setup(x => x.Get())
.ReturnsAsync(new OkResponse<IOcelotConfiguration>(_config));
}
protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services) protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services)
{ {
services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>(); services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
services.AddLogging(); services.AddLogging();
services.AddSingleton(_downstreamRouteFinder.Object); services.AddSingleton(_downstreamRouteFinder.Object);
services.AddSingleton(_provider.Object);
services.AddSingleton(ScopedRepository.Object); services.AddSingleton(ScopedRepository.Object);
} }
@ -58,14 +75,17 @@
{ {
_downstreamRoute = new OkResponse<DownstreamRoute>(downstreamRoute); _downstreamRoute = new OkResponse<DownstreamRoute>(downstreamRoute);
_downstreamRouteFinder _downstreamRouteFinder
.Setup(x => x.FindDownstreamRoute(It.IsAny<string>(), It.IsAny<string>())) .Setup(x => x.FindDownstreamRoute(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<IOcelotConfiguration>()))
.ReturnsAsync(_downstreamRoute); .Returns(_downstreamRoute);
} }
private void ThenTheScopedDataRepositoryIsCalledCorrectly() private void ThenTheScopedDataRepositoryIsCalledCorrectly()
{ {
ScopedRepository ScopedRepository
.Verify(x => x.Add("DownstreamRoute", _downstreamRoute.Data), Times.Once()); .Verify(x => x.Add("DownstreamRoute", _downstreamRoute.Data), Times.Once());
ScopedRepository
.Verify(x => x.Add("ServiceProviderConfiguration", _config.ServiceProviderConfiguration), Times.Once());
} }
} }
} }

View File

@ -16,26 +16,27 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
public class DownstreamRouteFinderTests public class DownstreamRouteFinderTests
{ {
private readonly IDownstreamRouteFinder _downstreamRouteFinder; private readonly IDownstreamRouteFinder _downstreamRouteFinder;
private readonly Mock<IOcelotConfigurationProvider> _mockConfig;
private readonly Mock<IUrlPathToUrlTemplateMatcher> _mockMatcher; private readonly Mock<IUrlPathToUrlTemplateMatcher> _mockMatcher;
private readonly Mock<IUrlPathPlaceholderNameAndValueFinder> _finder; private readonly Mock<IUrlPathPlaceholderNameAndValueFinder> _finder;
private string _upstreamUrlPath; private string _upstreamUrlPath;
private Response<DownstreamRoute> _result; private Response<DownstreamRoute> _result;
private List<ReRoute> _reRoutesConfig; private List<ReRoute> _reRoutesConfig;
private OcelotConfiguration _config;
private Response<UrlMatch> _match; private Response<UrlMatch> _match;
private string _upstreamHttpMethod; private string _upstreamHttpMethod;
public DownstreamRouteFinderTests() public DownstreamRouteFinderTests()
{ {
_mockConfig = new Mock<IOcelotConfigurationProvider>();
_mockMatcher = new Mock<IUrlPathToUrlTemplateMatcher>(); _mockMatcher = new Mock<IUrlPathToUrlTemplateMatcher>();
_finder = new Mock<IUrlPathPlaceholderNameAndValueFinder>(); _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] [Fact]
public void should_return_route() public void should_return_route()
{ {
var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher/")) this.Given(x => x.GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher/"))
.And(x =>x.GivenTheTemplateVariableAndNameFinderReturns( .And(x =>x.GivenTheTemplateVariableAndNameFinderReturns(
new OkResponse<List<UrlPathPlaceholderNameAndValue>>( new OkResponse<List<UrlPathPlaceholderNameAndValue>>(
@ -48,7 +49,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern("someUpstreamPath") .WithUpstreamTemplatePattern("someUpstreamPath")
.Build() .Build()
}, string.Empty }, string.Empty, serviceProviderConfig
)) ))
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true)))) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
.And(x => x.GivenTheUpstreamHttpMethodIs("Get")) .And(x => x.GivenTheUpstreamHttpMethodIs("Get"))
@ -69,6 +70,8 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
[Fact] [Fact]
public void should_append_slash_to_upstream_url_path() public void should_append_slash_to_upstream_url_path()
{ {
var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher")) this.Given(x => x.GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher"))
.And(x =>x.GivenTheTemplateVariableAndNameFinderReturns( .And(x =>x.GivenTheTemplateVariableAndNameFinderReturns(
new OkResponse<List<UrlPathPlaceholderNameAndValue>>( new OkResponse<List<UrlPathPlaceholderNameAndValue>>(
@ -81,7 +84,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern("someUpstreamPath") .WithUpstreamTemplatePattern("someUpstreamPath")
.Build() .Build()
}, string.Empty }, string.Empty, serviceProviderConfig
)) ))
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true)))) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
.And(x => x.GivenTheUpstreamHttpMethodIs("Get")) .And(x => x.GivenTheUpstreamHttpMethodIs("Get"))
@ -101,6 +104,8 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
[Fact] [Fact]
public void should_return_route_if_upstream_path_and_upstream_template_are_the_same() public void should_return_route_if_upstream_path_and_upstream_template_are_the_same()
{ {
var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath"))
.And( .And(
x => x =>
@ -114,7 +119,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern("someUpstreamPath") .WithUpstreamTemplatePattern("someUpstreamPath")
.Build() .Build()
}, string.Empty }, string.Empty, serviceProviderConfig
)) ))
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true)))) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
.And(x => x.GivenTheUpstreamHttpMethodIs("Get")) .And(x => x.GivenTheUpstreamHttpMethodIs("Get"))
@ -133,6 +138,8 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
[Fact] [Fact]
public void should_return_correct_route_for_http_verb() public void should_return_correct_route_for_http_verb()
{ {
var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath"))
.And( .And(
x => x =>
@ -152,7 +159,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithUpstreamHttpMethod(new List<string> { "Post" }) .WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern("") .WithUpstreamTemplatePattern("")
.Build() .Build()
}, string.Empty }, string.Empty, serviceProviderConfig
)) ))
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true)))) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
.And(x => x.GivenTheUpstreamHttpMethodIs("Post")) .And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
@ -170,6 +177,8 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
[Fact] [Fact]
public void should_not_return_route() public void should_not_return_route()
{ {
var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("dontMatchPath/")) this.Given(x => x.GivenThereIsAnUpstreamUrlPath("dontMatchPath/"))
.And(x => x.GivenTheConfigurationIs(new List<ReRoute> .And(x => x.GivenTheConfigurationIs(new List<ReRoute>
{ {
@ -179,7 +188,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern("somePath") .WithUpstreamTemplatePattern("somePath")
.Build(), .Build(),
}, string.Empty }, string.Empty, serviceProviderConfig
)) ))
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(false)))) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(false))))
.And(x => x.GivenTheUpstreamHttpMethodIs("Get")) .And(x => x.GivenTheUpstreamHttpMethodIs("Get"))
@ -193,6 +202,8 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
[Fact] [Fact]
public void should_return_correct_route_for_http_verb_setting_multiple_upstream_http_method() public void should_return_correct_route_for_http_verb_setting_multiple_upstream_http_method()
{ {
var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath"))
.And( .And(
x => x =>
@ -206,7 +217,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithUpstreamHttpMethod(new List<string> { "Get", "Post" }) .WithUpstreamHttpMethod(new List<string> { "Get", "Post" })
.WithUpstreamTemplatePattern("") .WithUpstreamTemplatePattern("")
.Build() .Build()
}, string.Empty }, string.Empty, serviceProviderConfig
)) ))
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true)))) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
.And(x => x.GivenTheUpstreamHttpMethodIs("Post")) .And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
@ -224,6 +235,8 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
[Fact] [Fact]
public void should_return_correct_route_for_http_verb_setting_all_upstream_http_method() public void should_return_correct_route_for_http_verb_setting_all_upstream_http_method()
{ {
var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath"))
.And( .And(
x => x =>
@ -237,7 +250,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithUpstreamHttpMethod(new List<string>()) .WithUpstreamHttpMethod(new List<string>())
.WithUpstreamTemplatePattern("") .WithUpstreamTemplatePattern("")
.Build() .Build()
}, string.Empty }, string.Empty, serviceProviderConfig
)) ))
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true)))) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
.And(x => x.GivenTheUpstreamHttpMethodIs("Post")) .And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
@ -255,6 +268,8 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
[Fact] [Fact]
public void should_not_return_route_for_http_verb_not_setting_in_upstream_http_method() public void should_not_return_route_for_http_verb_not_setting_in_upstream_http_method()
{ {
var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath"))
.And( .And(
x => x =>
@ -268,7 +283,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithUpstreamHttpMethod(new List<string> { "Get", "Patch", "Delete" }) .WithUpstreamHttpMethod(new List<string> { "Get", "Patch", "Delete" })
.WithUpstreamTemplatePattern("") .WithUpstreamTemplatePattern("")
.Build() .Build()
}, string.Empty }, string.Empty, serviceProviderConfig
)) ))
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true)))) .And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
.And(x => x.GivenTheUpstreamHttpMethodIs("Post")) .And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
@ -322,12 +337,10 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.Returns(_match); .Returns(_match);
} }
private void GivenTheConfigurationIs(List<ReRoute> reRoutesConfig, string adminPath) private void GivenTheConfigurationIs(List<ReRoute> reRoutesConfig, string adminPath, ServiceProviderConfiguration serviceProviderConfig)
{ {
_reRoutesConfig = reRoutesConfig; _reRoutesConfig = reRoutesConfig;
_mockConfig _config = new OcelotConfiguration(_reRoutesConfig, adminPath, serviceProviderConfig);
.Setup(x => x.Get())
.ReturnsAsync(new OkResponse<IOcelotConfiguration>(new OcelotConfiguration(_reRoutesConfig, adminPath)));
} }
private void GivenThereIsAnUpstreamUrlPath(string upstreamUrlPath) private void GivenThereIsAnUpstreamUrlPath(string upstreamUrlPath)
@ -337,7 +350,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
private void WhenICallTheFinder() private void WhenICallTheFinder()
{ {
_result = _downstreamRouteFinder.FindDownstreamRoute(_upstreamUrlPath, _upstreamHttpMethod).Result; _result = _downstreamRouteFinder.FindDownstreamRoute(_upstreamUrlPath, _upstreamHttpMethod, _config);
} }
private void ThenTheFollowingIsReturned(DownstreamRoute expected) private void ThenTheFollowingIsReturned(DownstreamRoute expected)

View File

@ -14,7 +14,7 @@ namespace Ocelot.UnitTests.LoadBalancer
{ {
private HostAndPort _hostAndPort; private HostAndPort _hostAndPort;
private Response<HostAndPort> _result; private Response<HostAndPort> _result;
private LeastConnectionLoadBalancer _leastConnection; private LeastConnection _leastConnection;
private List<Service> _services; private List<Service> _services;
private Random _random; private Random _random;
@ -35,7 +35,7 @@ namespace Ocelot.UnitTests.LoadBalancer
}; };
_services = availableServices; _services = availableServices;
_leastConnection = new LeastConnectionLoadBalancer(() => Task.FromResult(_services), serviceName); _leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName);
var tasks = new Task[100]; var tasks = new Task[100];
@ -86,7 +86,7 @@ namespace Ocelot.UnitTests.LoadBalancer
}; };
_services = availableServices; _services = availableServices;
_leastConnection = new LeastConnectionLoadBalancer(() => Task.FromResult(_services), serviceName); _leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName);
var response = _leastConnection.Lease().Result; var response = _leastConnection.Lease().Result;
@ -113,7 +113,7 @@ namespace Ocelot.UnitTests.LoadBalancer
}; };
_services = availableServices; _services = availableServices;
_leastConnection = new LeastConnectionLoadBalancer(() => Task.FromResult(_services), serviceName); _leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName);
var response = _leastConnection.Lease().Result; var response = _leastConnection.Lease().Result;
@ -144,7 +144,7 @@ namespace Ocelot.UnitTests.LoadBalancer
}; };
_services = availableServices; _services = availableServices;
_leastConnection = new LeastConnectionLoadBalancer(() => Task.FromResult(_services), serviceName); _leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName);
var response = _leastConnection.Lease().Result; var response = _leastConnection.Lease().Result;
@ -211,7 +211,7 @@ namespace Ocelot.UnitTests.LoadBalancer
private void GivenTheLoadBalancerStarts(List<Service> services, string serviceName) private void GivenTheLoadBalancerStarts(List<Service> services, string serviceName)
{ {
_services = services; _services = services;
_leastConnection = new LeastConnectionLoadBalancer(() => Task.FromResult(_services), serviceName); _leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName);
} }
private void WhenTheLoadBalancerStarts(List<Service> services, string serviceName) private void WhenTheLoadBalancerStarts(List<Service> services, string serviceName)

View File

@ -17,6 +17,7 @@ namespace Ocelot.UnitTests.LoadBalancer
private ILoadBalancer _result; private ILoadBalancer _result;
private Mock<IServiceDiscoveryProviderFactory> _serviceProviderFactory; private Mock<IServiceDiscoveryProviderFactory> _serviceProviderFactory;
private Mock<IServiceDiscoveryProvider> _serviceProvider; private Mock<IServiceDiscoveryProvider> _serviceProvider;
private ServiceProviderConfiguration _serviceProviderConfig;
public LoadBalancerFactoryTests() public LoadBalancerFactoryTests()
{ {
@ -29,11 +30,11 @@ namespace Ocelot.UnitTests.LoadBalancer
public void should_return_no_load_balancer() public void should_return_no_load_balancer()
{ {
var reRoute = new ReRouteBuilder() var reRoute = new ReRouteBuilder()
.WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder().Build())
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.Build(); .Build();
this.Given(x => x.GivenAReRoute(reRoute)) this.Given(x => x.GivenAReRoute(reRoute))
.And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build()))
.And(x => x.GivenTheServiceProviderFactoryReturns()) .And(x => x.GivenTheServiceProviderFactoryReturns())
.When(x => x.WhenIGetTheLoadBalancer()) .When(x => x.WhenIGetTheLoadBalancer())
.Then(x => x.ThenTheLoadBalancerIsReturned<NoLoadBalancer>()) .Then(x => x.ThenTheLoadBalancerIsReturned<NoLoadBalancer>())
@ -46,13 +47,13 @@ namespace Ocelot.UnitTests.LoadBalancer
var reRoute = new ReRouteBuilder() var reRoute = new ReRouteBuilder()
.WithLoadBalancer("RoundRobin") .WithLoadBalancer("RoundRobin")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder().Build())
.Build(); .Build();
this.Given(x => x.GivenAReRoute(reRoute)) this.Given(x => x.GivenAReRoute(reRoute))
.And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build()))
.And(x => x.GivenTheServiceProviderFactoryReturns()) .And(x => x.GivenTheServiceProviderFactoryReturns())
.When(x => x.WhenIGetTheLoadBalancer()) .When(x => x.WhenIGetTheLoadBalancer())
.Then(x => x.ThenTheLoadBalancerIsReturned<RoundRobinLoadBalancer>()) .Then(x => x.ThenTheLoadBalancerIsReturned<RoundRobin>())
.BDDfy(); .BDDfy();
} }
@ -62,13 +63,13 @@ namespace Ocelot.UnitTests.LoadBalancer
var reRoute = new ReRouteBuilder() var reRoute = new ReRouteBuilder()
.WithLoadBalancer("LeastConnection") .WithLoadBalancer("LeastConnection")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder().Build())
.Build(); .Build();
this.Given(x => x.GivenAReRoute(reRoute)) this.Given(x => x.GivenAReRoute(reRoute))
.And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build()))
.And(x => x.GivenTheServiceProviderFactoryReturns()) .And(x => x.GivenTheServiceProviderFactoryReturns())
.When(x => x.WhenIGetTheLoadBalancer()) .When(x => x.WhenIGetTheLoadBalancer())
.Then(x => x.ThenTheLoadBalancerIsReturned<LeastConnectionLoadBalancer>()) .Then(x => x.ThenTheLoadBalancerIsReturned<LeastConnection>())
.BDDfy(); .BDDfy();
} }
@ -78,27 +79,32 @@ namespace Ocelot.UnitTests.LoadBalancer
var reRoute = new ReRouteBuilder() var reRoute = new ReRouteBuilder()
.WithLoadBalancer("RoundRobin") .WithLoadBalancer("RoundRobin")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder().Build())
.Build(); .Build();
this.Given(x => x.GivenAReRoute(reRoute)) this.Given(x => x.GivenAReRoute(reRoute))
.And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build()))
.And(x => x.GivenTheServiceProviderFactoryReturns()) .And(x => x.GivenTheServiceProviderFactoryReturns())
.When(x => x.WhenIGetTheLoadBalancer()) .When(x => x.WhenIGetTheLoadBalancer())
.Then(x => x.ThenTheServiceProviderIsCalledCorrectly()) .Then(x => x.ThenTheServiceProviderIsCalledCorrectly())
.BDDfy(); .BDDfy();
} }
private void GivenAServiceProviderConfig(ServiceProviderConfiguration serviceProviderConfig)
{
_serviceProviderConfig = serviceProviderConfig;
}
private void GivenTheServiceProviderFactoryReturns() private void GivenTheServiceProviderFactoryReturns()
{ {
_serviceProviderFactory _serviceProviderFactory
.Setup(x => x.Get(It.IsAny<ServiceProviderConfiguration>())) .Setup(x => x.Get(It.IsAny<ServiceProviderConfiguration>(), It.IsAny<ReRoute>()))
.Returns(_serviceProvider.Object); .Returns(_serviceProvider.Object);
} }
private void ThenTheServiceProviderIsCalledCorrectly() private void ThenTheServiceProviderIsCalledCorrectly()
{ {
_serviceProviderFactory _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) private void GivenAReRoute(ReRoute reRoute)
@ -108,7 +114,7 @@ namespace Ocelot.UnitTests.LoadBalancer
private void WhenIGetTheLoadBalancer() private void WhenIGetTheLoadBalancer()
{ {
_result = _factory.Get(_reRoute).Result; _result = _factory.Get(_reRoute, _serviceProviderConfig).Result;
} }
private void ThenTheLoadBalancerIsReturned<T>() private void ThenTheLoadBalancerIsReturned<T>()

View File

@ -1,5 +1,8 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.LoadBalancer.LoadBalancers; using Ocelot.LoadBalancer.LoadBalancers;
using Ocelot.Responses; using Ocelot.Responses;
using Ocelot.Values; using Ocelot.Values;
@ -11,35 +14,38 @@ namespace Ocelot.UnitTests.LoadBalancer
{ {
public class LoadBalancerHouseTests public class LoadBalancerHouseTests
{ {
private ReRoute _reRoute;
private ILoadBalancer _loadBalancer; private ILoadBalancer _loadBalancer;
private readonly LoadBalancerHouse _loadBalancerHouse; private readonly LoadBalancerHouse _loadBalancerHouse;
private Response _addResult; private Response _addResult;
private Response<ILoadBalancer> _getResult; private Response<ILoadBalancer> _getResult;
private string _key; private string _key;
private Mock<ILoadBalancerFactory> _factory;
private ServiceProviderConfiguration _serviceProviderConfig;
public LoadBalancerHouseTests() public LoadBalancerHouseTests()
{ {
_loadBalancerHouse = new LoadBalancerHouse(); _factory = new Mock<ILoadBalancerFactory>();
_loadBalancerHouse = new LoadBalancerHouse(_factory.Object);
} }
[Fact] [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())) this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
.When(x => x.WhenIAddTheLoadBalancer())
.Then(x => x.ThenItIsAdded()) .Then(x => x.ThenItIsAdded())
.BDDfy(); .BDDfy();
} }
[Fact] [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())) this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
.When(x => x.WhenWeGetTheLoadBalancer(key)) .When(x => x.WhenWeGetTheLoadBalancer(reRoute))
.Then(x => x.ThenItIsReturned()) .Then(x => x.ThenItIsReturned())
.BDDfy(); .BDDfy();
} }
@ -47,26 +53,50 @@ namespace Ocelot.UnitTests.LoadBalancer
[Fact] [Fact]
public void should_store_load_balancers_by_key() public void should_store_load_balancers_by_key()
{ {
var key = "test"; var reRoute = new ReRouteBuilder().WithReRouteKey("test").Build();
var keyTwo = "testTwo"; var reRouteTwo = new ReRouteBuilder().WithReRouteKey("testtwo").Build();
this.Given(x => x.GivenThereIsALoadBalancer(key, new FakeLoadBalancer())) this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
.And(x => x.GivenThereIsALoadBalancer(keyTwo, new FakeRoundRobinLoadBalancer())) .And(x => x.GivenThereIsALoadBalancer(reRouteTwo, new FakeRoundRobinLoadBalancer()))
.When(x => x.WhenWeGetTheLoadBalancer(key)) .When(x => x.WhenWeGetTheLoadBalancer(reRoute))
.Then(x => x.ThenTheLoadBalancerIs<FakeLoadBalancer>()) .Then(x => x.ThenTheLoadBalancerIs<FakeLoadBalancer>())
.When(x => x.WhenWeGetTheLoadBalancer(keyTwo)) .When(x => x.WhenWeGetTheLoadBalancer(reRouteTwo))
.Then(x => x.ThenTheLoadBalancerIs<FakeRoundRobinLoadBalancer>()) .Then(x => x.ThenTheLoadBalancerIs<FakeRoundRobinLoadBalancer>())
.BDDfy(); .BDDfy();
} }
[Fact] [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()) .Then(x => x.ThenAnErrorIsReturned())
.BDDfy(); .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() private void ThenAnErrorIsReturned()
{ {
_getResult.IsError.ShouldBeTrue(); _getResult.IsError.ShouldBeTrue();
@ -80,31 +110,30 @@ namespace Ocelot.UnitTests.LoadBalancer
private void ThenItIsAdded() private void ThenItIsAdded()
{ {
_addResult.IsError.ShouldBe(false); _getResult.IsError.ShouldBe(false);
_addResult.ShouldBeOfType<OkResponse>(); _getResult.ShouldBeOfType<OkResponse<ILoadBalancer>>();
} _getResult.Data.ShouldBe(_loadBalancer);
_factory.Verify(x => x.Get(_reRoute, _serviceProviderConfig), Times.Once);
private void WhenIAddTheLoadBalancer()
{
_addResult = _loadBalancerHouse.Add(_key, _loadBalancer);
} }
private void GivenThereIsALoadBalancer(string key, ILoadBalancer loadBalancer) private void GivenThereIsALoadBalancer(ReRoute reRoute, ILoadBalancer loadBalancer)
{ {
_key = key; _reRoute = reRoute;
_loadBalancer = loadBalancer; _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() private void ThenItIsReturned()
{ {
_getResult.Data.ShouldBe(_loadBalancer); _getResult.Data.ShouldBe(_loadBalancer);
_factory.Verify(x => x.Get(_reRoute, _serviceProviderConfig), Times.Once);
} }
class FakeLoadBalancer : ILoadBalancer class FakeLoadBalancer : ILoadBalancer

View File

@ -5,7 +5,9 @@ namespace Ocelot.UnitTests.LoadBalancer
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Moq; using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder; using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Provider;
using Ocelot.DownstreamRouteFinder; using Ocelot.DownstreamRouteFinder;
using Ocelot.Errors; using Ocelot.Errors;
using Ocelot.LoadBalancer.LoadBalancers; using Ocelot.LoadBalancer.LoadBalancers;
@ -26,13 +28,13 @@ namespace Ocelot.UnitTests.LoadBalancer
private ErrorResponse<ILoadBalancer> _getLoadBalancerHouseError; private ErrorResponse<ILoadBalancer> _getLoadBalancerHouseError;
private ErrorResponse<HostAndPort> _getHostAndPortError; private ErrorResponse<HostAndPort> _getHostAndPortError;
private HttpRequestMessage _downstreamRequest; private HttpRequestMessage _downstreamRequest;
private ServiceProviderConfiguration _config;
public LoadBalancerMiddlewareTests() public LoadBalancerMiddlewareTests()
{ {
_loadBalancerHouse = new Mock<ILoadBalancerHouse>(); _loadBalancerHouse = new Mock<ILoadBalancerHouse>();
_loadBalancer = new Mock<ILoadBalancer>(); _loadBalancer = new Mock<ILoadBalancer>();
_loadBalancerHouse = new Mock<ILoadBalancerHouse>(); _loadBalancerHouse = new Mock<ILoadBalancerHouse>();
_downstreamRequest = new HttpRequestMessage(HttpMethod.Get, ""); _downstreamRequest = new HttpRequestMessage(HttpMethod.Get, "");
ScopedRepository ScopedRepository
@ -50,7 +52,11 @@ namespace Ocelot.UnitTests.LoadBalancer
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.Build()); .Build());
var serviceProviderConfig = new ServiceProviderConfigurationBuilder()
.Build();
this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123")) this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123"))
.And(x => GivenTheConfigurationIs(serviceProviderConfig))
.And(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) .And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
.And(x => x.GivenTheLoadBalancerHouseReturns()) .And(x => x.GivenTheLoadBalancerHouseReturns())
.And(x => x.GivenTheLoadBalancerReturns()) .And(x => x.GivenTheLoadBalancerReturns())
@ -67,7 +73,11 @@ namespace Ocelot.UnitTests.LoadBalancer
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.Build()); .Build());
var serviceProviderConfig = new ServiceProviderConfigurationBuilder()
.Build();
this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123")) this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123"))
.And(x => GivenTheConfigurationIs(serviceProviderConfig))
.And(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) .And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
.And(x => x.GivenTheLoadBalancerHouseReturnsAnError()) .And(x => x.GivenTheLoadBalancerHouseReturnsAnError())
.When(x => x.WhenICallTheMiddleware()) .When(x => x.WhenICallTheMiddleware())
@ -83,7 +93,11 @@ namespace Ocelot.UnitTests.LoadBalancer
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.Build()); .Build());
var serviceProviderConfig = new ServiceProviderConfigurationBuilder()
.Build();
this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123")) this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123"))
.And(x => GivenTheConfigurationIs(serviceProviderConfig))
.And(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) .And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
.And(x => x.GivenTheLoadBalancerHouseReturns()) .And(x => x.GivenTheLoadBalancerHouseReturns())
.And(x => x.GivenTheLoadBalancerReturnsAnError()) .And(x => x.GivenTheLoadBalancerReturnsAnError())
@ -92,6 +106,13 @@ namespace Ocelot.UnitTests.LoadBalancer
.BDDfy(); .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) protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services)
{ {
services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>(); services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
@ -137,8 +158,8 @@ namespace Ocelot.UnitTests.LoadBalancer
private void GivenTheLoadBalancerHouseReturns() private void GivenTheLoadBalancerHouseReturns()
{ {
_loadBalancerHouse _loadBalancerHouse
.Setup(x => x.Get(It.IsAny<string>())) .Setup(x => x.Get(It.IsAny<ReRoute>(), It.IsAny<ServiceProviderConfiguration>()))
.Returns(new OkResponse<ILoadBalancer>(_loadBalancer.Object)); .ReturnsAsync(new OkResponse<ILoadBalancer>(_loadBalancer.Object));
} }
private void GivenTheLoadBalancerHouseReturnsAnError() private void GivenTheLoadBalancerHouseReturnsAnError()
@ -149,8 +170,8 @@ namespace Ocelot.UnitTests.LoadBalancer
}); });
_loadBalancerHouse _loadBalancerHouse
.Setup(x => x.Get(It.IsAny<string>())) .Setup(x => x.Get(It.IsAny<ReRoute>(), It.IsAny<ServiceProviderConfiguration>()))
.Returns(_getLoadBalancerHouseError); .ReturnsAsync(_getLoadBalancerHouseError);
} }
private void ThenAnErrorStatingLoadBalancerCouldNotBeFoundIsSetOnPipeline() private void ThenAnErrorStatingLoadBalancerCouldNotBeFoundIsSetOnPipeline()

View File

@ -12,7 +12,7 @@ namespace Ocelot.UnitTests.LoadBalancer
{ {
public class RoundRobinTests public class RoundRobinTests
{ {
private readonly RoundRobinLoadBalancer _roundRobin; private readonly RoundRobin _roundRobin;
private readonly List<Service> _services; private readonly List<Service> _services;
private Response<HostAndPort> _hostAndPort; 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]) 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] [Fact]

View File

@ -88,7 +88,7 @@
private void GivenTheQosProviderHouseReturns(Response<IQoSProvider> qosProvider) private void GivenTheQosProviderHouseReturns(Response<IQoSProvider> qosProvider)
{ {
_qosProviderHouse _qosProviderHouse
.Setup(x => x.Get(It.IsAny<string>())) .Setup(x => x.Get(It.IsAny<ReRoute>()))
.Returns(qosProvider); .Returns(qosProvider);
} }

View File

@ -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.Responses;
using Ocelot.UnitTests.LoadBalancer;
using Shouldly; using Shouldly;
using TestStack.BDDfy; using TestStack.BDDfy;
using Xunit; using Xunit;
@ -12,31 +17,32 @@ namespace Ocelot.UnitTests.Requester
private readonly QosProviderHouse _qosProviderHouse; private readonly QosProviderHouse _qosProviderHouse;
private Response _addResult; private Response _addResult;
private Response<IQoSProvider> _getResult; private Response<IQoSProvider> _getResult;
private string _key; private ReRoute _reRoute;
private readonly Mock<IQoSProviderFactory> _factory;
public QosProviderHouseTests() public QosProviderHouseTests()
{ {
_qosProviderHouse = new QosProviderHouse(); _factory = new Mock<IQoSProviderFactory>();
_qosProviderHouse = new QosProviderHouse(_factory.Object);
} }
[Fact] [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())) this.Given(x => x.GivenThereIsAQoSProvider(reRoute, new FakeQoSProvider()))
.When(x => x.WhenIAddTheQoSProvider())
.Then(x => x.ThenItIsAdded()) .Then(x => x.ThenItIsAdded())
.BDDfy(); .BDDfy();
} }
[Fact] [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())) this.Given(x => x.GivenThereIsAQoSProvider(reRoute, new FakeQoSProvider()))
.When(x => x.WhenWeGetTheQoSProvider(key)) .When(x => x.WhenWeGetTheQoSProvider(reRoute))
.Then(x => x.ThenItIsReturned()) .Then(x => x.ThenItIsReturned())
.BDDfy(); .BDDfy();
} }
@ -44,14 +50,14 @@ namespace Ocelot.UnitTests.Requester
[Fact] [Fact]
public void should_store_qos_providers_by_key() public void should_store_qos_providers_by_key()
{ {
var key = "test"; var reRoute = new ReRouteBuilder().WithReRouteKey("test").Build();
var keyTwo = "testTwo"; var reRouteTwo = new ReRouteBuilder().WithReRouteKey("testTwo").Build();
this.Given(x => x.GivenThereIsAQoSProvider(key, new FakeQoSProvider())) this.Given(x => x.GivenThereIsAQoSProvider(reRoute, new FakeQoSProvider()))
.And(x => x.GivenThereIsAQoSProvider(keyTwo, new FakePollyQoSProvider())) .And(x => x.GivenThereIsAQoSProvider(reRouteTwo, new FakePollyQoSProvider()))
.When(x => x.WhenWeGetTheQoSProvider(key)) .When(x => x.WhenWeGetTheQoSProvider(reRoute))
.Then(x => x.ThenTheQoSProviderIs<FakeQoSProvider>()) .Then(x => x.ThenTheQoSProviderIs<FakeQoSProvider>())
.When(x => x.WhenWeGetTheQoSProvider(keyTwo)) .When(x => x.WhenWeGetTheQoSProvider(reRouteTwo))
.Then(x => x.ThenTheQoSProviderIs<FakePollyQoSProvider>()) .Then(x => x.ThenTheQoSProviderIs<FakePollyQoSProvider>())
.BDDfy(); .BDDfy();
} }
@ -59,11 +65,35 @@ namespace Ocelot.UnitTests.Requester
[Fact] [Fact]
public void should_return_error_if_no_qos_provider_with_key() 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()) .Then(x => x.ThenAnErrorIsReturned())
.BDDfy(); .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() private void ThenAnErrorIsReturned()
{ {
_getResult.IsError.ShouldBeTrue(); _getResult.IsError.ShouldBeTrue();
@ -77,31 +107,30 @@ namespace Ocelot.UnitTests.Requester
private void ThenItIsAdded() private void ThenItIsAdded()
{ {
_addResult.IsError.ShouldBe(false); _getResult.IsError.ShouldBe(false);
_addResult.ShouldBeOfType<OkResponse>(); _getResult.ShouldBeOfType<OkResponse<IQoSProvider>>();
} _factory.Verify(x => x.Get(_reRoute), Times.Once);
_getResult.Data.ShouldBe(_qoSProvider);
private void WhenIAddTheQoSProvider()
{
_addResult = _qosProviderHouse.Add(_key, _qoSProvider);
} }
private void GivenThereIsAQoSProvider(string key, IQoSProvider qoSProvider) private void GivenThereIsAQoSProvider(ReRoute reRoute, IQoSProvider qoSProvider)
{ {
_key = key; _reRoute = reRoute;
_qoSProvider = qoSProvider; _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() private void ThenItIsReturned()
{ {
_getResult.Data.ShouldBe(_qoSProvider); _getResult.Data.ShouldBe(_qoSProvider);
_factory.Verify(x => x.Get(_reRoute), Times.Once);
} }
class FakeQoSProvider : IQoSProvider class FakeQoSProvider : IQoSProvider

View File

@ -12,6 +12,7 @@ namespace Ocelot.UnitTests.ServiceDiscovery
private ServiceProviderConfiguration _serviceConfig; private ServiceProviderConfiguration _serviceConfig;
private IServiceDiscoveryProvider _result; private IServiceDiscoveryProvider _result;
private readonly ServiceDiscoveryProviderFactory _factory; private readonly ServiceDiscoveryProviderFactory _factory;
private ReRoute _reRoute;
public ServiceProviderFactoryTests() public ServiceProviderFactoryTests()
{ {
@ -22,12 +23,11 @@ namespace Ocelot.UnitTests.ServiceDiscovery
public void should_return_no_service_provider() public void should_return_no_service_provider()
{ {
var serviceConfig = new ServiceProviderConfigurationBuilder() var serviceConfig = new ServiceProviderConfigurationBuilder()
.WithDownstreamHost("127.0.0.1")
.WithDownstreamPort(80)
.WithUseServiceDiscovery(false)
.Build(); .Build();
this.Given(x => x.GivenTheReRoute(serviceConfig)) var reRoute = new ReRouteBuilder().Build();
this.Given(x => x.GivenTheReRoute(serviceConfig, reRoute))
.When(x => x.WhenIGetTheServiceProvider()) .When(x => x.WhenIGetTheServiceProvider())
.Then(x => x.ThenTheServiceProviderIs<ConfigurationServiceProvider>()) .Then(x => x.ThenTheServiceProviderIs<ConfigurationServiceProvider>())
.BDDfy(); .BDDfy();
@ -36,26 +36,29 @@ namespace Ocelot.UnitTests.ServiceDiscovery
[Fact] [Fact]
public void should_return_consul_service_provider() public void should_return_consul_service_provider()
{ {
var serviceConfig = new ServiceProviderConfigurationBuilder() var reRoute = new ReRouteBuilder()
.WithServiceName("product") .WithServiceName("product")
.WithUseServiceDiscovery(true) .WithUseServiceDiscovery(true)
.WithServiceDiscoveryProvider("Consul")
.Build(); .Build();
this.Given(x => x.GivenTheReRoute(serviceConfig)) var serviceConfig = new ServiceProviderConfigurationBuilder()
.Build();
this.Given(x => x.GivenTheReRoute(serviceConfig, reRoute))
.When(x => x.WhenIGetTheServiceProvider()) .When(x => x.WhenIGetTheServiceProvider())
.Then(x => x.ThenTheServiceProviderIs<ConsulServiceDiscoveryProvider>()) .Then(x => x.ThenTheServiceProviderIs<ConsulServiceDiscoveryProvider>())
.BDDfy(); .BDDfy();
} }
private void GivenTheReRoute(ServiceProviderConfiguration serviceConfig) private void GivenTheReRoute(ServiceProviderConfiguration serviceConfig, ReRoute reRoute)
{ {
_serviceConfig = serviceConfig; _serviceConfig = serviceConfig;
_reRoute = reRoute;
} }
private void WhenIGetTheServiceProvider() private void WhenIGetTheServiceProvider()
{ {
_result = _factory.Get(_serviceConfig); _result = _factory.Get(_serviceConfig, _reRoute);
} }
private void ThenTheServiceProviderIs<T>() private void ThenTheServiceProviderIs<T>()