changes to create load balancers and qos providers on first request to reroute and then check if they have changed on subsequent requests but not create again if they havent..quite a few breaking changes here.

This commit is contained in:
Tom Pallister 2017-11-09 17:35:49 +00:00
parent b08837ea9d
commit 1d61e403ed
39 changed files with 474 additions and 459 deletions

View File

@ -149,7 +149,7 @@ 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;

View File

@ -2,16 +2,9 @@ namespace Ocelot.Configuration.Builder
{ {
public class ServiceProviderConfigurationBuilder public class ServiceProviderConfigurationBuilder
{ {
private string _serviceDiscoveryProvider;
private string _serviceDiscoveryProviderHost; private string _serviceDiscoveryProviderHost;
private int _serviceDiscoveryProviderPort; private int _serviceDiscoveryProviderPort;
public ServiceProviderConfigurationBuilder WithServiceDiscoveryProvider(string serviceDiscoveryProvider)
{
_serviceDiscoveryProvider = serviceDiscoveryProvider;
return this;
}
public ServiceProviderConfigurationBuilder WithServiceDiscoveryProviderHost(string serviceDiscoveryProviderHost) public ServiceProviderConfigurationBuilder WithServiceDiscoveryProviderHost(string serviceDiscoveryProviderHost)
{ {
_serviceDiscoveryProviderHost = serviceDiscoveryProviderHost; _serviceDiscoveryProviderHost = serviceDiscoveryProviderHost;
@ -26,7 +19,7 @@ namespace Ocelot.Configuration.Builder
public ServiceProviderConfiguration Build() public ServiceProviderConfiguration Build()
{ {
return new ServiceProviderConfiguration(_serviceDiscoveryProvider, _serviceDiscoveryProviderHost,_serviceDiscoveryProviderPort); return new ServiceProviderConfiguration(_serviceDiscoveryProviderHost,_serviceDiscoveryProviderPort);
} }
} }
} }

View File

@ -26,8 +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 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;
@ -43,8 +41,6 @@ namespace Ocelot.Configuration.Creator
IOptions<FileConfiguration> options, IOptions<FileConfiguration> options,
IConfigurationValidator configurationValidator, IConfigurationValidator configurationValidator,
IOcelotLoggerFactory loggerFactory, IOcelotLoggerFactory loggerFactory,
IQoSProviderFactory qoSProviderFactory,
IQosProviderHouse qosProviderHouse,
IClaimsToThingCreator claimsToThingCreator, IClaimsToThingCreator claimsToThingCreator,
IAuthenticationOptionsCreator authOptionsCreator, IAuthenticationOptionsCreator authOptionsCreator,
IUpstreamTemplatePatternCreator upstreamTemplatePatternCreator, IUpstreamTemplatePatternCreator upstreamTemplatePatternCreator,
@ -62,8 +58,6 @@ namespace Ocelot.Configuration.Creator
_requestIdKeyCreator = requestIdKeyCreator; _requestIdKeyCreator = requestIdKeyCreator;
_upstreamTemplatePatternCreator = upstreamTemplatePatternCreator; _upstreamTemplatePatternCreator = upstreamTemplatePatternCreator;
_authOptionsCreator = authOptionsCreator; _authOptionsCreator = authOptionsCreator;
_qoSProviderFactory = qoSProviderFactory;
_qosProviderHouse = qosProviderHouse;
_options = options; _options = options;
_configurationValidator = configurationValidator; _configurationValidator = configurationValidator;
_logger = loggerFactory.CreateLogger<FileOcelotConfigurationCreator>(); _logger = loggerFactory.CreateLogger<FileOcelotConfigurationCreator>();
@ -108,7 +102,7 @@ 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);
} }
@ -117,7 +111,7 @@ namespace Ocelot.Configuration.Creator
return new OcelotConfiguration(reRoutes, fileConfiguration.GlobalConfiguration.AdministrationPath, serviceProviderConfiguration); 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);
@ -162,7 +156,7 @@ 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)
.WithIsQos(fileReRouteOptions.IsQos) .WithIsQos(fileReRouteOptions.IsQos)
.WithQosOptions(qosOptions) .WithQosOptions(qosOptions)
.WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting) .WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting)
@ -172,7 +166,6 @@ namespace Ocelot.Configuration.Creator
.WithUseServiceDiscovery(fileReRoute.UseServiceDiscovery) .WithUseServiceDiscovery(fileReRoute.UseServiceDiscovery)
.Build(); .Build();
SetupQosProvider(reRoute);
return reRoute; return reRoute;
} }
@ -182,11 +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 void SetupQosProvider(ReRoute reRoute)
{
var loadBalancer = _qoSProviderFactory.Get(reRoute);
_qosProviderHouse.Add(reRoute.ReRouteKey, loadBalancer);
}
} }
} }

View File

@ -10,7 +10,6 @@ namespace Ocelot.Configuration.Creator
var serviceProviderPort = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0; var serviceProviderPort = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0;
return new ServiceProviderConfigurationBuilder() return new ServiceProviderConfigurationBuilder()
.WithServiceDiscoveryProvider(globalConfiguration?.ServiceDiscoveryProvider?.Provider)
.WithServiceDiscoveryProviderHost(globalConfiguration?.ServiceDiscoveryProvider?.Host) .WithServiceDiscoveryProviderHost(globalConfiguration?.ServiceDiscoveryProvider?.Host)
.WithServiceDiscoveryProviderPort(serviceProviderPort) .WithServiceDiscoveryProviderPort(serviceProviderPort)
.Build(); .Build();

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

@ -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,14 +2,12 @@
{ {
public class ServiceProviderConfiguration public class ServiceProviderConfiguration
{ {
public ServiceProviderConfiguration(string serviceDiscoveryProvider, string serviceProviderHost, int serviceProviderPort) public ServiceProviderConfiguration(string serviceProviderHost, int serviceProviderPort)
{ {
ServiceDiscoveryProvider = serviceDiscoveryProvider;
ServiceProviderHost = serviceProviderHost; ServiceProviderHost = serviceProviderHost;
ServiceProviderPort = serviceProviderPort; ServiceProviderPort = serviceProviderPort;
} }
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,20 +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;
using Ocelot.LoadBalancer;
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

@ -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

@ -19,9 +19,9 @@ namespace Ocelot.LoadBalancer.LoadBalancers
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.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

@ -22,16 +22,11 @@ namespace Ocelot.LoadBalancer.LoadBalancers
{ {
try try
{ {
ILoadBalancer loadBalancer; if(_loadBalancers.TryGetValue(reRoute.ReRouteKey, out var loadBalancer))
if(_loadBalancers.TryGetValue(reRoute.ReRouteKey, out loadBalancer))
{ {
loadBalancer = _loadBalancers[reRoute.ReRouteKey]; loadBalancer = _loadBalancers[reRoute.ReRouteKey];
//todo - we have some duplicate namey type logic in the LoadBalancerFactory...maybe we can do something if(reRoute.LoadBalancer != loadBalancer.GetType().Name)
//about this..
if((reRoute.LoadBalancer == "RoundRobin" && loadBalancer.GetType() != typeof(RoundRobinLoadBalancer))
|| (reRoute.LoadBalancer == "LeastConnection" && loadBalancer.GetType() != typeof(LeastConnectionLoadBalancer)))
{ {
loadBalancer = await _factory.Get(reRoute, config); loadBalancer = await _factory.Get(reRoute, config);
AddLoadBalancer(reRoute.ReRouteKey, loadBalancer); AddLoadBalancer(reRoute.ReRouteKey, loadBalancer);
@ -55,18 +50,7 @@ namespace Ocelot.LoadBalancer.LoadBalancers
private void AddLoadBalancer(string key, ILoadBalancer loadBalancer) private void AddLoadBalancer(string key, ILoadBalancer loadBalancer)
{ {
_loadBalancers.AddOrUpdate(key, loadBalancer, (x, y) => { _loadBalancers.AddOrUpdate(key, loadBalancer, (x, y) => loadBalancer);
return loadBalancer;
});
// if (!_loadBalancers.ContainsKey(key))
// {
// _loadBalancers.TryAdd(key, loadBalancer);
// }
// ILoadBalancer old;
// _loadBalancers.Remove(key, out old);
// _loadBalancers.TryAdd(key, 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

@ -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

@ -10,7 +10,7 @@ namespace Ocelot.ServiceDiscovery
{ {
if (reRoute.UseServiceDiscovery) if (reRoute.UseServiceDiscovery)
{ {
return GetServiceDiscoveryProvider(reRoute.ServiceName, serviceConfig.ServiceDiscoveryProvider, serviceConfig.ServiceProviderHost, serviceConfig.ServiceProviderPort); return GetServiceDiscoveryProvider(reRoute.ServiceName, serviceConfig.ServiceProviderHost, serviceConfig.ServiceProviderPort);
} }
var services = new List<Service>() var services = new List<Service>()
@ -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

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Text; using System.Text;
using System.Threading;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
@ -11,7 +10,6 @@ using Newtonsoft.Json;
using Ocelot.Configuration; using Ocelot.Configuration;
using Ocelot.Configuration.Builder; 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;
@ -50,7 +48,6 @@ namespace Ocelot.AcceptanceTests
{ {
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider() ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{ {
Provider = "Consul",
Host = "localhost", Host = "localhost",
Port = 9500 Port = 9500
} }
@ -59,12 +56,10 @@ 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"))
@ -74,30 +69,24 @@ namespace Ocelot.AcceptanceTests
[Fact] [Fact]
public void should_fix_issue_142() public void should_fix_issue_142()
{ {
var consulPort = 8500;
var configuration = new FileConfiguration var configuration = new FileConfiguration
{ {
ReRoutes = new List<FileReRoute>
{
},
GlobalConfiguration = new FileGlobalConfiguration() GlobalConfiguration = new FileGlobalConfiguration()
{ {
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider() ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{ {
Provider = "Consul",
Host = "localhost", Host = "localhost",
Port = 9500 Port = consulPort
} }
} }
}; };
var fakeConsulServiceDiscoveryUrl = "http://localhost:9500"; var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}";
var consulConfig = new ConsulRegistryConfiguration("localhost", 9500, "Ocelot");
var serviceProviderConfig = new ServiceProviderConfigurationBuilder() var serviceProviderConfig = new ServiceProviderConfigurationBuilder()
.WithServiceDiscoveryProvider("Consul")
.WithServiceDiscoveryProviderHost("localhost") .WithServiceDiscoveryProviderHost("localhost")
.WithServiceDiscoveryProviderPort(8500) .WithServiceDiscoveryProviderPort(consulPort)
.Build(); .Build();
var reRoute = new ReRouteBuilder() var reRoute = new ReRouteBuilder()
@ -108,10 +97,8 @@ namespace Ocelot.AcceptanceTests
.WithDownstreamPort(51779) .WithDownstreamPort(51779)
.WithUpstreamPathTemplate("/cs/status") .WithUpstreamPathTemplate("/cs/status")
.WithUpstreamHttpMethod(new List<string> {"Get"}) .WithUpstreamHttpMethod(new List<string> {"Get"})
.WithLoadBalancer("LeastConnection") .WithReRouteKey("/cs/status|Get")
.WithLoadBalancerKey("/cs/status|Get") .WithHttpHandlerOptions(new HttpHandlerOptions(true, false))
.WithServiceName("")
.WithUseServiceDiscovery(true)
.Build(); .Build();
var reRoutes = new List<ReRoute> { reRoute }; var reRoutes = new List<ReRoute> { reRoute };
@ -122,7 +109,7 @@ namespace Ocelot.AcceptanceTests
.And(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl)) .And(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl))
.And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51779", "/status", 200, "Hello from Laura")) .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51779", "/status", 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("/cs/status")) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/cs/status"))
.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"))

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()
@ -79,9 +80,8 @@ namespace Ocelot.AcceptanceTests
{ {
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider() ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{ {
Provider = "Consul",
Host = "localhost", Host = "localhost",
Port = 8500 Port = consulPort
} }
} }
}; };

View File

@ -44,4 +44,39 @@ namespace Ocelot.AcceptanceTests
app.UseOcelot().Wait(); 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++)
{ {

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,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.LoadBalancer;
using Ocelot.UnitTests.TestData; using Ocelot.UnitTests.TestData;
public class FileConfigurationCreatorTests public class FileConfigurationCreatorTests
@ -30,10 +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<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;
@ -47,13 +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>>();
_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>();
@ -67,7 +54,7 @@ namespace Ocelot.UnitTests.Configuration
_ocelotConfigurationCreator = new FileOcelotConfigurationCreator( _ocelotConfigurationCreator = new FileOcelotConfigurationCreator(
_fileConfig.Object, _validator.Object, _logger.Object, _fileConfig.Object, _validator.Object, _logger.Object,
_qosProviderFactory.Object, _qosProviderHouse.Object, _claimsToThingCreator.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);
@ -86,7 +73,6 @@ namespace Ocelot.UnitTests.Configuration
{ {
Host = "localhost", Host = "localhost",
Port = 8500, Port = 8500,
Provider = "consul"
} }
} }
})) }))
@ -201,12 +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(); .BDDfy();
} }
@ -301,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"
} }
} }
@ -603,25 +585,6 @@ namespace Ocelot.UnitTests.Configuration
} }
} }
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

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

@ -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();
@ -65,7 +63,6 @@ namespace Ocelot.UnitTests.Configuration
private void ThenTheConfigIs(ServiceProviderConfiguration expected) private void ThenTheConfigIs(ServiceProviderConfiguration expected)
{ {
_result.ServiceDiscoveryProvider.ShouldBe(expected.ServiceDiscoveryProvider);
_result.ServiceProviderHost.ShouldBe(expected.ServiceProviderHost); _result.ServiceProviderHost.ShouldBe(expected.ServiceProviderHost);
_result.ServiceProviderPort.ShouldBe(expected.ServiceProviderPort); _result.ServiceProviderPort.ShouldBe(expected.ServiceProviderPort);
} }

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

@ -53,7 +53,7 @@ namespace Ocelot.UnitTests.LoadBalancer
.And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build())) .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();
} }
@ -69,7 +69,7 @@ namespace Ocelot.UnitTests.LoadBalancer
.And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build())) .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();
} }

View File

@ -32,7 +32,7 @@ namespace Ocelot.UnitTests.LoadBalancer
[Fact] [Fact]
public void should_store_load_balancer_on_first_request() public void should_store_load_balancer_on_first_request()
{ {
var reRoute = new ReRouteBuilder().WithLoadBalancerKey("test").Build(); var reRoute = new ReRouteBuilder().WithReRouteKey("test").Build();
this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer())) this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
.Then(x => x.ThenItIsAdded()) .Then(x => x.ThenItIsAdded())
@ -42,7 +42,7 @@ namespace Ocelot.UnitTests.LoadBalancer
[Fact] [Fact]
public void should_not_store_load_balancer_on_second_request() public void should_not_store_load_balancer_on_second_request()
{ {
var reRoute = new ReRouteBuilder().WithLoadBalancerKey("test").Build(); var reRoute = new ReRouteBuilder().WithLoadBalancer("FakeLoadBalancer").WithReRouteKey("test").Build();
this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer())) this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
.When(x => x.WhenWeGetTheLoadBalancer(reRoute)) .When(x => x.WhenWeGetTheLoadBalancer(reRoute))
@ -53,8 +53,8 @@ namespace Ocelot.UnitTests.LoadBalancer
[Fact] [Fact]
public void should_store_load_balancers_by_key() public void should_store_load_balancers_by_key()
{ {
var reRoute = new ReRouteBuilder().WithLoadBalancerKey("test").Build(); var reRoute = new ReRouteBuilder().WithReRouteKey("test").Build();
var reRouteTwo = new ReRouteBuilder().WithLoadBalancerKey("testtwo").Build(); var reRouteTwo = new ReRouteBuilder().WithReRouteKey("testtwo").Build();
this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer())) this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
.And(x => x.GivenThereIsALoadBalancer(reRouteTwo, new FakeRoundRobinLoadBalancer())) .And(x => x.GivenThereIsALoadBalancer(reRouteTwo, new FakeRoundRobinLoadBalancer()))
@ -78,22 +78,22 @@ namespace Ocelot.UnitTests.LoadBalancer
[Fact] [Fact]
public void should_get_new_load_balancer_if_reroute_load_balancer_has_changed() public void should_get_new_load_balancer_if_reroute_load_balancer_has_changed()
{ {
var reRoute = new ReRouteBuilder().WithLoadBalancerKey("test").Build(); var reRoute = new ReRouteBuilder().WithLoadBalancer("FakeLoadBalancer").WithReRouteKey("test").Build();
var reRouteTwo = new ReRouteBuilder().WithLoadBalancer("LeastConnection").WithLoadBalancerKey("test").Build(); var reRouteTwo = new ReRouteBuilder().WithLoadBalancer("LeastConnection").WithReRouteKey("test").Build();
this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer())) this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
.When(x => x.WhenWeGetTheLoadBalancer(reRoute)) .When(x => x.WhenWeGetTheLoadBalancer(reRoute))
.Then(x => x.ThenTheLoadBalancerIs<FakeLoadBalancer>()) .Then(x => x.ThenTheLoadBalancerIs<FakeLoadBalancer>())
.When(x => x.WhenIGetTheReRouteWithTheSameKeyButDifferentLoadBalancer(reRouteTwo)) .When(x => x.WhenIGetTheReRouteWithTheSameKeyButDifferentLoadBalancer(reRouteTwo))
.Then(x => x.ThenTheLoadBalancerIs<LeastConnectionLoadBalancer>()) .Then(x => x.ThenTheLoadBalancerIs<LeastConnection>())
.BDDfy(); .BDDfy();
} }
private void WhenIGetTheReRouteWithTheSameKeyButDifferentLoadBalancer(ReRoute reRoute) private void WhenIGetTheReRouteWithTheSameKeyButDifferentLoadBalancer(ReRoute reRoute)
{ {
_reRoute = reRoute; _reRoute = reRoute;
_factory.Setup(x => x.Get(_reRoute, _serviceProviderConfig)).ReturnsAsync(new LeastConnectionLoadBalancer(null, null)); _factory.Setup(x => x.Get(_reRoute, _serviceProviderConfig)).ReturnsAsync(new LeastConnection(null, null));
_getResult = _loadBalancerHouse.Get(_reRoute, _serviceProviderConfig).Result; _getResult = _loadBalancerHouse.Get(_reRoute, _serviceProviderConfig).Result;
} }

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

@ -42,7 +42,6 @@ namespace Ocelot.UnitTests.ServiceDiscovery
.Build(); .Build();
var serviceConfig = new ServiceProviderConfigurationBuilder() var serviceConfig = new ServiceProviderConfigurationBuilder()
.WithServiceDiscoveryProvider("Consul")
.Build(); .Build();
this.Given(x => x.GivenTheReRoute(serviceConfig, reRoute)) this.Given(x => x.GivenTheReRoute(serviceConfig, reRoute))