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