mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-04-22 06:22:50 +08:00
commit
b0f928127e
@ -4,9 +4,7 @@
|
|||||||
|
|
||||||
[](https://coveralls.io/github/TomPallister/Ocelot?branch=develop)
|
[](https://coveralls.io/github/TomPallister/Ocelot?branch=develop)
|
||||||
|
|
||||||
Attempt at a .NET Api Gateway
|
Ocelot is a .NET Api Gateway. This project is aimed at people using .NET running
|
||||||
|
|
||||||
This project is aimed at people using .NET running
|
|
||||||
a micro services / service orientated architecture
|
a micro services / service orientated architecture
|
||||||
that need a unified point of entry into their system.
|
that need a unified point of entry into their system.
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"projects": [ "src", "test" ],
|
"projects": [ "src", "test" ],
|
||||||
"sdk": {
|
"sdk": {
|
||||||
"version": "2.0.0"
|
"version": "2.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -26,13 +26,14 @@ namespace Ocelot.Configuration.Builder
|
|||||||
private string _downstreamHost;
|
private string _downstreamHost;
|
||||||
private int _downstreamPort;
|
private int _downstreamPort;
|
||||||
private string _loadBalancer;
|
private string _loadBalancer;
|
||||||
private ServiceProviderConfiguration _serviceProviderConfiguraion;
|
|
||||||
private bool _useQos;
|
private bool _useQos;
|
||||||
private QoSOptions _qosOptions;
|
private QoSOptions _qosOptions;
|
||||||
private HttpHandlerOptions _httpHandlerOptions;
|
private HttpHandlerOptions _httpHandlerOptions;
|
||||||
public bool _enableRateLimiting;
|
public bool _enableRateLimiting;
|
||||||
public RateLimitOptions _rateLimitOptions;
|
public RateLimitOptions _rateLimitOptions;
|
||||||
private string _authenticationProviderKey;
|
private string _authenticationProviderKey;
|
||||||
|
private bool _useServiceDiscovery;
|
||||||
|
private string _serviceName;
|
||||||
|
|
||||||
public ReRouteBuilder WithLoadBalancer(string loadBalancer)
|
public ReRouteBuilder WithLoadBalancer(string loadBalancer)
|
||||||
{
|
{
|
||||||
@ -148,18 +149,12 @@ namespace Ocelot.Configuration.Builder
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReRouteBuilder WithLoadBalancerKey(string loadBalancerKey)
|
public ReRouteBuilder WithReRouteKey(string loadBalancerKey)
|
||||||
{
|
{
|
||||||
_loadBalancerKey = loadBalancerKey;
|
_loadBalancerKey = loadBalancerKey;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReRouteBuilder WithServiceProviderConfiguraion(ServiceProviderConfiguration serviceProviderConfiguraion)
|
|
||||||
{
|
|
||||||
_serviceProviderConfiguraion = serviceProviderConfiguraion;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReRouteBuilder WithAuthenticationOptions(AuthenticationOptions authenticationOptions)
|
public ReRouteBuilder WithAuthenticationOptions(AuthenticationOptions authenticationOptions)
|
||||||
{
|
{
|
||||||
_authenticationOptions = authenticationOptions;
|
_authenticationOptions = authenticationOptions;
|
||||||
@ -190,6 +185,18 @@ namespace Ocelot.Configuration.Builder
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ReRouteBuilder WithUseServiceDiscovery(bool useServiceDiscovery)
|
||||||
|
{
|
||||||
|
_useServiceDiscovery = useServiceDiscovery;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReRouteBuilder WithServiceName(string serviceName)
|
||||||
|
{
|
||||||
|
_serviceName = serviceName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public ReRoute Build()
|
public ReRoute Build()
|
||||||
{
|
{
|
||||||
return new ReRoute(
|
return new ReRoute(
|
||||||
@ -212,12 +219,13 @@ namespace Ocelot.Configuration.Builder
|
|||||||
_downstreamHost,
|
_downstreamHost,
|
||||||
_downstreamPort,
|
_downstreamPort,
|
||||||
_loadBalancerKey,
|
_loadBalancerKey,
|
||||||
_serviceProviderConfiguraion,
|
|
||||||
_useQos,
|
_useQos,
|
||||||
_qosOptions,
|
_qosOptions,
|
||||||
_enableRateLimiting,
|
_enableRateLimiting,
|
||||||
_rateLimitOptions,
|
_rateLimitOptions,
|
||||||
_httpHandlerOptions);
|
_httpHandlerOptions,
|
||||||
|
_useServiceDiscovery,
|
||||||
|
_serviceName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,44 +2,9 @@ namespace Ocelot.Configuration.Builder
|
|||||||
{
|
{
|
||||||
public class ServiceProviderConfigurationBuilder
|
public class ServiceProviderConfigurationBuilder
|
||||||
{
|
{
|
||||||
private string _serviceName;
|
|
||||||
private string _downstreamHost;
|
|
||||||
private int _downstreamPort;
|
|
||||||
private bool _userServiceDiscovery;
|
|
||||||
private string _serviceDiscoveryProvider;
|
|
||||||
private string _serviceDiscoveryProviderHost;
|
private string _serviceDiscoveryProviderHost;
|
||||||
private int _serviceDiscoveryProviderPort;
|
private int _serviceDiscoveryProviderPort;
|
||||||
|
|
||||||
public ServiceProviderConfigurationBuilder WithServiceName(string serviceName)
|
|
||||||
{
|
|
||||||
_serviceName = serviceName;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServiceProviderConfigurationBuilder WithDownstreamHost(string downstreamHost)
|
|
||||||
{
|
|
||||||
_downstreamHost = downstreamHost;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServiceProviderConfigurationBuilder WithDownstreamPort(int downstreamPort)
|
|
||||||
{
|
|
||||||
_downstreamPort = downstreamPort;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServiceProviderConfigurationBuilder WithUseServiceDiscovery(bool userServiceDiscovery)
|
|
||||||
{
|
|
||||||
_userServiceDiscovery = userServiceDiscovery;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServiceProviderConfigurationBuilder WithServiceDiscoveryProvider(string serviceDiscoveryProvider)
|
|
||||||
{
|
|
||||||
_serviceDiscoveryProvider = serviceDiscoveryProvider;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServiceProviderConfigurationBuilder WithServiceDiscoveryProviderHost(string serviceDiscoveryProviderHost)
|
public ServiceProviderConfigurationBuilder WithServiceDiscoveryProviderHost(string serviceDiscoveryProviderHost)
|
||||||
{
|
{
|
||||||
_serviceDiscoveryProviderHost = serviceDiscoveryProviderHost;
|
_serviceDiscoveryProviderHost = serviceDiscoveryProviderHost;
|
||||||
@ -52,11 +17,9 @@ namespace Ocelot.Configuration.Builder
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ServiceProviderConfiguration Build()
|
public ServiceProviderConfiguration Build()
|
||||||
{
|
{
|
||||||
return new ServiceProviderConfiguration(_serviceName, _downstreamHost, _downstreamPort, _userServiceDiscovery,
|
return new ServiceProviderConfiguration(_serviceDiscoveryProviderHost,_serviceDiscoveryProviderPort);
|
||||||
_serviceDiscoveryProvider, _serviceDiscoveryProviderHost,_serviceDiscoveryProviderPort);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -9,11 +9,11 @@ using Ocelot.Configuration.Builder;
|
|||||||
using Ocelot.Configuration.File;
|
using Ocelot.Configuration.File;
|
||||||
using Ocelot.Configuration.Parser;
|
using Ocelot.Configuration.Parser;
|
||||||
using Ocelot.Configuration.Validator;
|
using Ocelot.Configuration.Validator;
|
||||||
|
using Ocelot.LoadBalancer;
|
||||||
using Ocelot.LoadBalancer.LoadBalancers;
|
using Ocelot.LoadBalancer.LoadBalancers;
|
||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
using Ocelot.Requester.QoS;
|
using Ocelot.Requester.QoS;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
using Ocelot.Utilities;
|
|
||||||
|
|
||||||
namespace Ocelot.Configuration.Creator
|
namespace Ocelot.Configuration.Creator
|
||||||
{
|
{
|
||||||
@ -25,10 +25,6 @@ namespace Ocelot.Configuration.Creator
|
|||||||
private readonly IOptions<FileConfiguration> _options;
|
private readonly IOptions<FileConfiguration> _options;
|
||||||
private readonly IConfigurationValidator _configurationValidator;
|
private readonly IConfigurationValidator _configurationValidator;
|
||||||
private readonly IOcelotLogger _logger;
|
private readonly IOcelotLogger _logger;
|
||||||
private readonly ILoadBalancerFactory _loadBalanceFactory;
|
|
||||||
private readonly ILoadBalancerHouse _loadBalancerHouse;
|
|
||||||
private readonly IQoSProviderFactory _qoSProviderFactory;
|
|
||||||
private readonly IQosProviderHouse _qosProviderHouse;
|
|
||||||
private readonly IClaimsToThingCreator _claimsToThingCreator;
|
private readonly IClaimsToThingCreator _claimsToThingCreator;
|
||||||
private readonly IAuthenticationOptionsCreator _authOptionsCreator;
|
private readonly IAuthenticationOptionsCreator _authOptionsCreator;
|
||||||
private readonly IUpstreamTemplatePatternCreator _upstreamTemplatePatternCreator;
|
private readonly IUpstreamTemplatePatternCreator _upstreamTemplatePatternCreator;
|
||||||
@ -44,10 +40,6 @@ namespace Ocelot.Configuration.Creator
|
|||||||
IOptions<FileConfiguration> options,
|
IOptions<FileConfiguration> options,
|
||||||
IConfigurationValidator configurationValidator,
|
IConfigurationValidator configurationValidator,
|
||||||
IOcelotLoggerFactory loggerFactory,
|
IOcelotLoggerFactory loggerFactory,
|
||||||
ILoadBalancerFactory loadBalancerFactory,
|
|
||||||
ILoadBalancerHouse loadBalancerHouse,
|
|
||||||
IQoSProviderFactory qoSProviderFactory,
|
|
||||||
IQosProviderHouse qosProviderHouse,
|
|
||||||
IClaimsToThingCreator claimsToThingCreator,
|
IClaimsToThingCreator claimsToThingCreator,
|
||||||
IAuthenticationOptionsCreator authOptionsCreator,
|
IAuthenticationOptionsCreator authOptionsCreator,
|
||||||
IUpstreamTemplatePatternCreator upstreamTemplatePatternCreator,
|
IUpstreamTemplatePatternCreator upstreamTemplatePatternCreator,
|
||||||
@ -65,10 +57,6 @@ namespace Ocelot.Configuration.Creator
|
|||||||
_requestIdKeyCreator = requestIdKeyCreator;
|
_requestIdKeyCreator = requestIdKeyCreator;
|
||||||
_upstreamTemplatePatternCreator = upstreamTemplatePatternCreator;
|
_upstreamTemplatePatternCreator = upstreamTemplatePatternCreator;
|
||||||
_authOptionsCreator = authOptionsCreator;
|
_authOptionsCreator = authOptionsCreator;
|
||||||
_loadBalanceFactory = loadBalancerFactory;
|
|
||||||
_loadBalancerHouse = loadBalancerHouse;
|
|
||||||
_qoSProviderFactory = qoSProviderFactory;
|
|
||||||
_qosProviderHouse = qosProviderHouse;
|
|
||||||
_options = options;
|
_options = options;
|
||||||
_configurationValidator = configurationValidator;
|
_configurationValidator = configurationValidator;
|
||||||
_logger = loggerFactory.CreateLogger<FileOcelotConfigurationCreator>();
|
_logger = loggerFactory.CreateLogger<FileOcelotConfigurationCreator>();
|
||||||
@ -79,48 +67,37 @@ namespace Ocelot.Configuration.Creator
|
|||||||
_httpHandlerOptionsCreator = httpHandlerOptionsCreator;
|
_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)
|
public async Task<Response<IOcelotConfiguration>> Create(FileConfiguration fileConfiguration)
|
||||||
{
|
{
|
||||||
var config = await SetUpConfiguration(fileConfiguration);
|
var config = await SetUpConfiguration(fileConfiguration);
|
||||||
|
return config;
|
||||||
return new OkResponse<IOcelotConfiguration>(config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<IOcelotConfiguration> SetUpConfiguration(FileConfiguration fileConfiguration)
|
private async Task<Response<IOcelotConfiguration>> SetUpConfiguration(FileConfiguration fileConfiguration)
|
||||||
{
|
{
|
||||||
var response = await _configurationValidator.IsValid(fileConfiguration);
|
var response = await _configurationValidator.IsValid(fileConfiguration);
|
||||||
|
|
||||||
if (response.Data.IsError)
|
if (response.Data.IsError)
|
||||||
{
|
{
|
||||||
var errorBuilder = new StringBuilder();
|
return new ErrorResponse<IOcelotConfiguration>(response.Data.Errors);
|
||||||
|
|
||||||
foreach (var error in response.Errors)
|
|
||||||
{
|
|
||||||
errorBuilder.AppendLine(error.Message);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Exception($"Unable to start Ocelot..configuration, errors were {errorBuilder}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var reRoutes = new List<ReRoute>();
|
var reRoutes = new List<ReRoute>();
|
||||||
|
|
||||||
foreach (var reRoute in fileConfiguration.ReRoutes)
|
foreach (var reRoute in fileConfiguration.ReRoutes)
|
||||||
{
|
{
|
||||||
var ocelotReRoute = await SetUpReRoute(reRoute, fileConfiguration.GlobalConfiguration);
|
var ocelotReRoute = SetUpReRoute(reRoute, fileConfiguration.GlobalConfiguration);
|
||||||
reRoutes.Add(ocelotReRoute);
|
reRoutes.Add(ocelotReRoute);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new OcelotConfiguration(reRoutes, fileConfiguration.GlobalConfiguration.AdministrationPath);
|
var serviceProviderConfiguration = _serviceProviderConfigCreator.Create(fileConfiguration.GlobalConfiguration);
|
||||||
|
|
||||||
|
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);
|
var fileReRouteOptions = _fileReRouteOptionsCreator.Create(fileReRoute);
|
||||||
|
|
||||||
@ -130,8 +107,6 @@ namespace Ocelot.Configuration.Creator
|
|||||||
|
|
||||||
var upstreamTemplatePattern = _upstreamTemplatePatternCreator.Create(fileReRoute);
|
var upstreamTemplatePattern = _upstreamTemplatePatternCreator.Create(fileReRoute);
|
||||||
|
|
||||||
var serviceProviderConfiguration = _serviceProviderConfigCreator.Create(fileReRoute, globalConfiguration);
|
|
||||||
|
|
||||||
var authOptionsForRoute = _authOptionsCreator.Create(fileReRoute);
|
var authOptionsForRoute = _authOptionsCreator.Create(fileReRoute);
|
||||||
|
|
||||||
var claimsToHeaders = _claimsToThingCreator.Create(fileReRoute.AddHeadersToRequest);
|
var claimsToHeaders = _claimsToThingCreator.Create(fileReRoute.AddHeadersToRequest);
|
||||||
@ -167,17 +142,16 @@ namespace Ocelot.Configuration.Creator
|
|||||||
.WithLoadBalancer(fileReRoute.LoadBalancer)
|
.WithLoadBalancer(fileReRoute.LoadBalancer)
|
||||||
.WithDownstreamHost(fileReRoute.DownstreamHost)
|
.WithDownstreamHost(fileReRoute.DownstreamHost)
|
||||||
.WithDownstreamPort(fileReRoute.DownstreamPort)
|
.WithDownstreamPort(fileReRoute.DownstreamPort)
|
||||||
.WithLoadBalancerKey(reRouteKey)
|
.WithReRouteKey(reRouteKey)
|
||||||
.WithServiceProviderConfiguraion(serviceProviderConfiguration)
|
|
||||||
.WithIsQos(fileReRouteOptions.IsQos)
|
.WithIsQos(fileReRouteOptions.IsQos)
|
||||||
.WithQosOptions(qosOptions)
|
.WithQosOptions(qosOptions)
|
||||||
.WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting)
|
.WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting)
|
||||||
.WithRateLimitOptions(rateLimitOption)
|
.WithRateLimitOptions(rateLimitOption)
|
||||||
.WithHttpHandlerOptions(httpHandlerOptions)
|
.WithHttpHandlerOptions(httpHandlerOptions)
|
||||||
|
.WithServiceName(fileReRoute.ServiceName)
|
||||||
|
.WithUseServiceDiscovery(fileReRoute.UseServiceDiscovery)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
await SetupLoadBalancer(reRoute);
|
|
||||||
SetupQosProvider(reRoute);
|
|
||||||
return reRoute;
|
return reRoute;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,17 +161,5 @@ namespace Ocelot.Configuration.Creator
|
|||||||
var loadBalancerKey = $"{fileReRoute.UpstreamPathTemplate}|{string.Join(",", fileReRoute.UpstreamHttpMethod)}";
|
var loadBalancerKey = $"{fileReRoute.UpstreamPathTemplate}|{string.Join(",", fileReRoute.UpstreamHttpMethod)}";
|
||||||
return loadBalancerKey;
|
return loadBalancerKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SetupLoadBalancer(ReRoute reRoute)
|
|
||||||
{
|
|
||||||
var loadBalancer = await _loadBalanceFactory.Get(reRoute);
|
|
||||||
_loadBalancerHouse.Add(reRoute.ReRouteKey, loadBalancer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetupQosProvider(ReRoute reRoute)
|
|
||||||
{
|
|
||||||
var loadBalancer = _qoSProviderFactory.Get(reRoute);
|
|
||||||
_qosProviderHouse.Add(reRoute.ReRouteKey, loadBalancer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,7 +6,6 @@ namespace Ocelot.Configuration.Creator
|
|||||||
{
|
{
|
||||||
public interface IOcelotConfigurationCreator
|
public interface IOcelotConfigurationCreator
|
||||||
{
|
{
|
||||||
Task<Response<IOcelotConfiguration>> Create();
|
|
||||||
Task<Response<IOcelotConfiguration>> Create(FileConfiguration fileConfiguration);
|
Task<Response<IOcelotConfiguration>> Create(FileConfiguration fileConfiguration);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,6 +4,6 @@ namespace Ocelot.Configuration.Creator
|
|||||||
{
|
{
|
||||||
public interface IServiceProviderConfigurationCreator
|
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 class ServiceProviderConfigurationCreator : IServiceProviderConfigurationCreator
|
||||||
{
|
{
|
||||||
public ServiceProviderConfiguration Create(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration)
|
public ServiceProviderConfiguration Create(FileGlobalConfiguration globalConfiguration)
|
||||||
{
|
{
|
||||||
var useServiceDiscovery = !string.IsNullOrEmpty(fileReRoute.ServiceName)
|
|
||||||
&& !string.IsNullOrEmpty(globalConfiguration?.ServiceDiscoveryProvider?.Provider);
|
|
||||||
|
|
||||||
var serviceProviderPort = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0;
|
var serviceProviderPort = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0;
|
||||||
|
|
||||||
return new ServiceProviderConfigurationBuilder()
|
return new ServiceProviderConfigurationBuilder()
|
||||||
.WithServiceName(fileReRoute.ServiceName)
|
|
||||||
.WithDownstreamHost(fileReRoute.DownstreamHost)
|
|
||||||
.WithDownstreamPort(fileReRoute.DownstreamPort)
|
|
||||||
.WithUseServiceDiscovery(useServiceDiscovery)
|
|
||||||
.WithServiceDiscoveryProvider(globalConfiguration?.ServiceDiscoveryProvider?.Provider)
|
|
||||||
.WithServiceDiscoveryProviderHost(globalConfiguration?.ServiceDiscoveryProvider?.Host)
|
.WithServiceDiscoveryProviderHost(globalConfiguration?.ServiceDiscoveryProvider?.Host)
|
||||||
.WithServiceDiscoveryProviderPort(serviceProviderPort)
|
.WithServiceDiscoveryProviderPort(serviceProviderPort)
|
||||||
.Build();
|
.Build();
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Ocelot.Configuration.File;
|
using Ocelot.Configuration.File;
|
||||||
using Ocelot.Utilities;
|
|
||||||
|
|
||||||
namespace Ocelot.Configuration.Creator
|
namespace Ocelot.Configuration.Creator
|
||||||
{
|
{
|
||||||
public class UpstreamTemplatePatternCreator : IUpstreamTemplatePatternCreator
|
public class UpstreamTemplatePatternCreator : IUpstreamTemplatePatternCreator
|
||||||
{
|
{
|
||||||
private const string RegExMatchEverything = ".*";
|
private const string RegExMatchEverything = "[0-9a-zA-Z].*";
|
||||||
private const string RegExMatchEndString = "$";
|
private const string RegExMatchEndString = "$";
|
||||||
private const string RegExIgnoreCase = "(?i)";
|
private const string RegExIgnoreCase = "(?i)";
|
||||||
private const string RegExForwardSlashOnly = "^/$";
|
private const string RegExForwardSlashOnly = "^/$";
|
||||||
@ -15,8 +14,6 @@ namespace Ocelot.Configuration.Creator
|
|||||||
{
|
{
|
||||||
var upstreamTemplate = reRoute.UpstreamPathTemplate;
|
var upstreamTemplate = reRoute.UpstreamPathTemplate;
|
||||||
|
|
||||||
upstreamTemplate = upstreamTemplate.SetLastCharacterAs('/');
|
|
||||||
|
|
||||||
var placeholders = new List<string>();
|
var placeholders = new List<string>();
|
||||||
|
|
||||||
for (var i = 0; i < upstreamTemplate.Length; i++)
|
for (var i = 0; i < upstreamTemplate.Length; i++)
|
||||||
@ -40,6 +37,11 @@ namespace Ocelot.Configuration.Creator
|
|||||||
return RegExForwardSlashOnly;
|
return RegExForwardSlashOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(upstreamTemplate.EndsWith("/"))
|
||||||
|
{
|
||||||
|
upstreamTemplate = upstreamTemplate.Remove(upstreamTemplate.Length -1, 1) + "(/|)";
|
||||||
|
}
|
||||||
|
|
||||||
var route = reRoute.ReRouteIsCaseSensitive
|
var route = reRoute.ReRouteIsCaseSensitive
|
||||||
? $"^{upstreamTemplate}{RegExMatchEndString}"
|
? $"^{upstreamTemplate}{RegExMatchEndString}"
|
||||||
: $"^{RegExIgnoreCase}{upstreamTemplate}{RegExMatchEndString}";
|
: $"^{RegExIgnoreCase}{upstreamTemplate}{RegExMatchEndString}";
|
||||||
|
@ -37,5 +37,6 @@ namespace Ocelot.Configuration.File
|
|||||||
public FileRateLimitRule RateLimitOptions { get; set; }
|
public FileRateLimitRule RateLimitOptions { get; set; }
|
||||||
public FileAuthenticationOptions AuthenticationOptions { get; set; }
|
public FileAuthenticationOptions AuthenticationOptions { get; set; }
|
||||||
public FileHttpHandlerOptions HttpHandlerOptions { get; set; }
|
public FileHttpHandlerOptions HttpHandlerOptions { get; set; }
|
||||||
|
public bool UseServiceDiscovery {get;set;}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,8 +2,6 @@ namespace Ocelot.Configuration.File
|
|||||||
{
|
{
|
||||||
public class FileServiceDiscoveryProvider
|
public class FileServiceDiscoveryProvider
|
||||||
{
|
{
|
||||||
|
|
||||||
public string Provider {get;set;}
|
|
||||||
public string Host {get;set;}
|
public string Host {get;set;}
|
||||||
public int Port { get; set; }
|
public int Port { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -6,5 +6,6 @@ namespace Ocelot.Configuration
|
|||||||
{
|
{
|
||||||
List<ReRoute> ReRoutes { get; }
|
List<ReRoute> ReRoutes { get; }
|
||||||
string AdministrationPath {get;}
|
string AdministrationPath {get;}
|
||||||
|
ServiceProviderConfiguration ServiceProviderConfiguration {get;}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,13 +4,15 @@ namespace Ocelot.Configuration
|
|||||||
{
|
{
|
||||||
public class OcelotConfiguration : IOcelotConfiguration
|
public class OcelotConfiguration : IOcelotConfiguration
|
||||||
{
|
{
|
||||||
public OcelotConfiguration(List<ReRoute> reRoutes, string administrationPath)
|
public OcelotConfiguration(List<ReRoute> reRoutes, string administrationPath, ServiceProviderConfiguration serviceProviderConfiguration)
|
||||||
{
|
{
|
||||||
ReRoutes = reRoutes;
|
ReRoutes = reRoutes;
|
||||||
AdministrationPath = administrationPath;
|
AdministrationPath = administrationPath;
|
||||||
|
ServiceProviderConfiguration = serviceProviderConfiguration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ReRoute> ReRoutes { get; }
|
public List<ReRoute> ReRoutes { get; }
|
||||||
public string AdministrationPath {get;}
|
public string AdministrationPath {get;}
|
||||||
|
public ServiceProviderConfiguration ServiceProviderConfiguration {get;}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Ocelot.Configuration.File;
|
using Ocelot.Configuration.File;
|
||||||
using Ocelot.Configuration.Repository;
|
using Ocelot.Configuration.Repository;
|
||||||
@ -16,9 +17,9 @@ namespace Ocelot.Configuration.Provider
|
|||||||
_repo = repo;
|
_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);
|
return new OkResponse<FileConfiguration>(fileConfig.Data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
using Ocelot.Configuration.File;
|
using Ocelot.Configuration.File;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
|
|
||||||
@ -5,6 +6,6 @@ namespace Ocelot.Configuration.Provider
|
|||||||
{
|
{
|
||||||
public interface IFileConfigurationProvider
|
public interface IFileConfigurationProvider
|
||||||
{
|
{
|
||||||
Response<FileConfiguration> Get();
|
Task<Response<FileConfiguration>> Get();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Ocelot.Configuration.File;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
|
|
||||||
namespace Ocelot.Configuration.Provider
|
namespace Ocelot.Configuration.Provider
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Ocelot.Configuration.File;
|
||||||
using Ocelot.Configuration.Repository;
|
using Ocelot.Configuration.Repository;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
|
|
||||||
@ -9,16 +10,16 @@ namespace Ocelot.Configuration.Provider
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class OcelotConfigurationProvider : IOcelotConfigurationProvider
|
public class OcelotConfigurationProvider : IOcelotConfigurationProvider
|
||||||
{
|
{
|
||||||
private readonly IOcelotConfigurationRepository _repo;
|
private readonly IOcelotConfigurationRepository _config;
|
||||||
|
|
||||||
public OcelotConfigurationProvider(IOcelotConfigurationRepository repo)
|
public OcelotConfigurationProvider(IOcelotConfigurationRepository repo)
|
||||||
{
|
{
|
||||||
_repo = repo;
|
_config = repo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Response<IOcelotConfiguration>> Get()
|
public async Task<Response<IOcelotConfiguration>> Get()
|
||||||
{
|
{
|
||||||
var repoConfig = await _repo.Get();
|
var repoConfig = await _config.Get();
|
||||||
|
|
||||||
if (repoConfig.IsError)
|
if (repoConfig.IsError)
|
||||||
{
|
{
|
||||||
|
@ -25,15 +25,17 @@ namespace Ocelot.Configuration
|
|||||||
string downstreamHost,
|
string downstreamHost,
|
||||||
int downstreamPort,
|
int downstreamPort,
|
||||||
string reRouteKey,
|
string reRouteKey,
|
||||||
ServiceProviderConfiguration serviceProviderConfiguraion,
|
|
||||||
bool isQos,
|
bool isQos,
|
||||||
QoSOptions qosOptions,
|
QoSOptions qosOptions,
|
||||||
bool enableEndpointRateLimiting,
|
bool enableEndpointRateLimiting,
|
||||||
RateLimitOptions ratelimitOptions,
|
RateLimitOptions ratelimitOptions,
|
||||||
HttpHandlerOptions httpHandlerOptions)
|
HttpHandlerOptions httpHandlerOptions,
|
||||||
|
bool useServiceDiscovery,
|
||||||
|
string serviceName)
|
||||||
{
|
{
|
||||||
|
ServiceName = serviceName;
|
||||||
|
UseServiceDiscovery = useServiceDiscovery;
|
||||||
ReRouteKey = reRouteKey;
|
ReRouteKey = reRouteKey;
|
||||||
ServiceProviderConfiguraion = serviceProviderConfiguraion;
|
|
||||||
LoadBalancer = loadBalancer;
|
LoadBalancer = loadBalancer;
|
||||||
DownstreamHost = downstreamHost;
|
DownstreamHost = downstreamHost;
|
||||||
DownstreamPort = downstreamPort;
|
DownstreamPort = downstreamPort;
|
||||||
@ -83,9 +85,10 @@ namespace Ocelot.Configuration
|
|||||||
public string LoadBalancer {get;private set;}
|
public string LoadBalancer {get;private set;}
|
||||||
public string DownstreamHost { get; private set; }
|
public string DownstreamHost { get; private set; }
|
||||||
public int DownstreamPort { get; private set; }
|
public int DownstreamPort { get; private set; }
|
||||||
public ServiceProviderConfiguration ServiceProviderConfiguraion { get; private set; }
|
|
||||||
public bool EnableEndpointEndpointRateLimiting { get; private set; }
|
public bool EnableEndpointEndpointRateLimiting { get; private set; }
|
||||||
public RateLimitOptions RateLimitOptions { get; private set; }
|
public RateLimitOptions RateLimitOptions { get; private set; }
|
||||||
public HttpHandlerOptions HttpHandlerOptions { get; private set; }
|
public HttpHandlerOptions HttpHandlerOptions { get; private set; }
|
||||||
|
public bool UseServiceDiscovery {get;private set;}
|
||||||
|
public string ServiceName {get;private set;}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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 System.Threading.Tasks;
|
||||||
using Consul;
|
using Consul;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Ocelot.Configuration.File;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
using Ocelot.ServiceDiscovery;
|
using Ocelot.ServiceDiscovery;
|
||||||
|
|
||||||
namespace Ocelot.Configuration.Repository
|
namespace Ocelot.Configuration.Repository
|
||||||
{
|
{
|
||||||
public class ConsulOcelotConfigurationRepository : IOcelotConfigurationRepository
|
|
||||||
|
public class ConsulFileConfigurationRepository : IFileConfigurationRepository
|
||||||
{
|
{
|
||||||
private readonly ConsulClient _consul;
|
private readonly ConsulClient _consul;
|
||||||
private ConsulRegistryConfiguration _configuration;
|
|
||||||
private string _ocelotConfiguration = "OcelotConfiguration";
|
private string _ocelotConfiguration = "OcelotConfiguration";
|
||||||
private Cache.IOcelotCache<IOcelotConfiguration> _cache;
|
private readonly Cache.IOcelotCache<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 consulHost = string.IsNullOrEmpty(serviceProviderConfig?.ServiceProviderHost) ? "localhost" : serviceProviderConfig?.ServiceProviderHost;
|
||||||
var consulPort = consulRegistryConfiguration?.Port ?? 8500;
|
var consulPort = serviceProviderConfig?.ServiceProviderPort ?? 8500;
|
||||||
_configuration = new ConsulRegistryConfiguration(consulHost, consulPort, consulRegistryConfiguration?.ServiceName);
|
var configuration = new ConsulRegistryConfiguration(consulHost, consulPort, _ocelotConfiguration);
|
||||||
_cache = cache;
|
_cache = cache;
|
||||||
_consul = new ConsulClient(config =>
|
_consul = new ConsulClient(c =>
|
||||||
{
|
{
|
||||||
config.Address = new Uri($"http://{_configuration.HostName}:{_configuration.Port}");
|
c.Address = new Uri($"http://{configuration.HostName}:{configuration.Port}");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Response<IOcelotConfiguration>> Get()
|
public async Task<Response<FileConfiguration>> Get()
|
||||||
{
|
{
|
||||||
var config = _cache.Get(_ocelotConfiguration, _ocelotConfiguration);
|
var config = _cache.Get(_ocelotConfiguration, _ocelotConfiguration);
|
||||||
|
|
||||||
if (config != null)
|
if (config != null)
|
||||||
{
|
{
|
||||||
return new OkResponse<IOcelotConfiguration>(config);
|
return new OkResponse<FileConfiguration>(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
var queryResult = await _consul.KV.Get(_ocelotConfiguration);
|
var queryResult = await _consul.KV.Get(_ocelotConfiguration);
|
||||||
|
|
||||||
if (queryResult.Response == null)
|
if (queryResult.Response == null)
|
||||||
{
|
{
|
||||||
return new OkResponse<IOcelotConfiguration>(null);
|
return new OkResponse<FileConfiguration>(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
var bytes = queryResult.Response.Value;
|
var bytes = queryResult.Response.Value;
|
||||||
|
|
||||||
var json = Encoding.UTF8.GetString(bytes);
|
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);
|
var json = JsonConvert.SerializeObject(ocelotConfiguration);
|
||||||
|
|
||||||
@ -72,7 +73,7 @@ namespace Ocelot.Configuration.Repository
|
|||||||
return new OkResponse();
|
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;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Ocelot.Configuration.File;
|
using Ocelot.Configuration.File;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
@ -7,33 +9,41 @@ namespace Ocelot.Configuration.Repository
|
|||||||
{
|
{
|
||||||
public class FileConfigurationRepository : IFileConfigurationRepository
|
public class FileConfigurationRepository : IFileConfigurationRepository
|
||||||
{
|
{
|
||||||
|
private readonly string _configFilePath;
|
||||||
|
|
||||||
private static readonly object _lock = new object();
|
private static readonly object _lock = new object();
|
||||||
public Response<FileConfiguration> Get()
|
|
||||||
|
public FileConfigurationRepository(IHostingEnvironment hostingEnvironment)
|
||||||
{
|
{
|
||||||
var configFilePath = $"{AppContext.BaseDirectory}/configuration.json";
|
_configFilePath = $"{AppContext.BaseDirectory}/configuration{(string.IsNullOrEmpty(hostingEnvironment.EnvironmentName) ? string.Empty : ".")}{hostingEnvironment.EnvironmentName}.json";
|
||||||
string json = string.Empty;
|
}
|
||||||
|
|
||||||
|
public async Task<Response<FileConfiguration>> Get()
|
||||||
|
{
|
||||||
|
string jsonConfiguration;
|
||||||
|
|
||||||
lock(_lock)
|
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);
|
return new OkResponse<FileConfiguration>(fileConfiguration);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Response Set(FileConfiguration fileConfiguration)
|
public async Task<Response> Set(FileConfiguration fileConfiguration)
|
||||||
{
|
{
|
||||||
var configurationPath = $"{AppContext.BaseDirectory}/configuration.json";
|
string jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration);
|
||||||
|
|
||||||
var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration);
|
|
||||||
|
|
||||||
lock(_lock)
|
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();
|
return new OkResponse();
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
using Ocelot.Configuration.File;
|
using Ocelot.Configuration.File;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
|
|
||||||
@ -5,7 +6,7 @@ namespace Ocelot.Configuration.Repository
|
|||||||
{
|
{
|
||||||
public interface IFileConfigurationRepository
|
public interface IFileConfigurationRepository
|
||||||
{
|
{
|
||||||
Response<FileConfiguration> Get();
|
Task<Response<FileConfiguration>> Get();
|
||||||
Response Set(FileConfiguration fileConfiguration);
|
Task<Response> Set(FileConfiguration fileConfiguration);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Ocelot.Configuration.File;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
|
|
||||||
namespace Ocelot.Configuration.Repository
|
namespace Ocelot.Configuration.Repository
|
||||||
|
@ -2,23 +2,12 @@
|
|||||||
{
|
{
|
||||||
public class ServiceProviderConfiguration
|
public class ServiceProviderConfiguration
|
||||||
{
|
{
|
||||||
public ServiceProviderConfiguration(string serviceName, string downstreamHost,
|
public ServiceProviderConfiguration(string serviceProviderHost, int serviceProviderPort)
|
||||||
int downstreamPort, bool useServiceDiscovery, string serviceDiscoveryProvider, string serviceProviderHost, int serviceProviderPort)
|
|
||||||
{
|
{
|
||||||
ServiceName = serviceName;
|
|
||||||
DownstreamHost = downstreamHost;
|
|
||||||
DownstreamPort = downstreamPort;
|
|
||||||
UseServiceDiscovery = useServiceDiscovery;
|
|
||||||
ServiceDiscoveryProvider = serviceDiscoveryProvider;
|
|
||||||
ServiceProviderHost = serviceProviderHost;
|
ServiceProviderHost = serviceProviderHost;
|
||||||
ServiceProviderPort = serviceProviderPort;
|
ServiceProviderPort = serviceProviderPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ServiceName { get; }
|
|
||||||
public string DownstreamHost { get; }
|
|
||||||
public int DownstreamPort { get; }
|
|
||||||
public bool UseServiceDiscovery { get; }
|
|
||||||
public string ServiceDiscoveryProvider { get; }
|
|
||||||
public string ServiceProviderHost { get; private set; }
|
public string ServiceProviderHost { get; private set; }
|
||||||
public int ServiceProviderPort { get; private set; }
|
public int ServiceProviderPort { get; private set; }
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ namespace Ocelot.Configuration.Setter
|
|||||||
|
|
||||||
public async Task<Response> Set(FileConfiguration fileConfig)
|
public async Task<Response> Set(FileConfiguration fileConfig)
|
||||||
{
|
{
|
||||||
var response = _repo.Set(fileConfig);
|
var response = await _repo.Set(fileConfig);
|
||||||
|
|
||||||
if(response.IsError)
|
if(response.IsError)
|
||||||
{
|
{
|
||||||
|
@ -21,9 +21,9 @@ namespace Ocelot.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IActionResult Get()
|
public async Task<IActionResult> Get()
|
||||||
{
|
{
|
||||||
var response = _configGetter.Get();
|
var response = await _configGetter.Get();
|
||||||
|
|
||||||
if(response.IsError)
|
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 Microsoft.Extensions.Configuration;
|
||||||
using IdentityServer4.Models;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
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.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
|
namespace Ocelot.DependencyInjection
|
||||||
{
|
{
|
||||||
public static class ServiceCollectionExtensions
|
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);
|
return new OcelotBuilder(services, configurationRoot);
|
||||||
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 }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,34 +2,28 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Ocelot.Configuration;
|
||||||
using Ocelot.Configuration.Provider;
|
using Ocelot.Configuration.Provider;
|
||||||
using Ocelot.DownstreamRouteFinder.UrlMatcher;
|
using Ocelot.DownstreamRouteFinder.UrlMatcher;
|
||||||
using Ocelot.Errors;
|
using Ocelot.Errors;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
using Ocelot.Utilities;
|
|
||||||
|
|
||||||
namespace Ocelot.DownstreamRouteFinder.Finder
|
namespace Ocelot.DownstreamRouteFinder.Finder
|
||||||
{
|
{
|
||||||
public class DownstreamRouteFinder : IDownstreamRouteFinder
|
public class DownstreamRouteFinder : IDownstreamRouteFinder
|
||||||
{
|
{
|
||||||
private readonly IOcelotConfigurationProvider _configProvider;
|
|
||||||
private readonly IUrlPathToUrlTemplateMatcher _urlMatcher;
|
private readonly IUrlPathToUrlTemplateMatcher _urlMatcher;
|
||||||
private readonly IUrlPathPlaceholderNameAndValueFinder _urlPathPlaceholderNameAndValueFinder;
|
private readonly IUrlPathPlaceholderNameAndValueFinder _urlPathPlaceholderNameAndValueFinder;
|
||||||
|
|
||||||
public DownstreamRouteFinder(IOcelotConfigurationProvider configProvider, IUrlPathToUrlTemplateMatcher urlMatcher, IUrlPathPlaceholderNameAndValueFinder urlPathPlaceholderNameAndValueFinder)
|
public DownstreamRouteFinder(IUrlPathToUrlTemplateMatcher urlMatcher, IUrlPathPlaceholderNameAndValueFinder urlPathPlaceholderNameAndValueFinder)
|
||||||
{
|
{
|
||||||
_configProvider = configProvider;
|
|
||||||
_urlMatcher = urlMatcher;
|
_urlMatcher = urlMatcher;
|
||||||
_urlPathPlaceholderNameAndValueFinder = urlPathPlaceholderNameAndValueFinder;
|
_urlPathPlaceholderNameAndValueFinder = urlPathPlaceholderNameAndValueFinder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Response<DownstreamRoute>> FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod)
|
public Response<DownstreamRoute> FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod, IOcelotConfiguration configuration)
|
||||||
{
|
{
|
||||||
upstreamUrlPath = upstreamUrlPath.SetLastCharacterAs('/');
|
var applicableReRoutes = configuration.ReRoutes.Where(r => r.UpstreamHttpMethod.Count == 0 || r.UpstreamHttpMethod.Select(x => x.Method.ToLower()).Contains(upstreamHttpMethod.ToLower()));
|
||||||
|
|
||||||
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()));
|
|
||||||
|
|
||||||
foreach (var reRoute in applicableReRoutes)
|
foreach (var reRoute in applicableReRoutes)
|
||||||
{
|
{
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Ocelot.Configuration;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
|
|
||||||
namespace Ocelot.DownstreamRouteFinder.Finder
|
namespace Ocelot.DownstreamRouteFinder.Finder
|
||||||
{
|
{
|
||||||
public interface IDownstreamRouteFinder
|
public interface IDownstreamRouteFinder
|
||||||
{
|
{
|
||||||
Task<Response<DownstreamRoute>> FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod);
|
Response<DownstreamRoute> FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod, IOcelotConfiguration configuration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,12 @@ using System.Linq;
|
|||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Ocelot.Configuration.Provider;
|
||||||
using Ocelot.DownstreamRouteFinder.Finder;
|
using Ocelot.DownstreamRouteFinder.Finder;
|
||||||
using Ocelot.Infrastructure.Extensions;
|
using Ocelot.Infrastructure.Extensions;
|
||||||
using Ocelot.Infrastructure.RequestData;
|
using Ocelot.Infrastructure.RequestData;
|
||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
using Ocelot.Middleware;
|
using Ocelot.Middleware;
|
||||||
using Ocelot.Utilities;
|
|
||||||
|
|
||||||
namespace Ocelot.DownstreamRouteFinder.Middleware
|
namespace Ocelot.DownstreamRouteFinder.Middleware
|
||||||
{
|
{
|
||||||
@ -16,13 +16,17 @@ namespace Ocelot.DownstreamRouteFinder.Middleware
|
|||||||
private readonly RequestDelegate _next;
|
private readonly RequestDelegate _next;
|
||||||
private readonly IDownstreamRouteFinder _downstreamRouteFinder;
|
private readonly IDownstreamRouteFinder _downstreamRouteFinder;
|
||||||
private readonly IOcelotLogger _logger;
|
private readonly IOcelotLogger _logger;
|
||||||
|
private readonly IOcelotConfigurationProvider _configProvider;
|
||||||
|
|
||||||
|
|
||||||
public DownstreamRouteFinderMiddleware(RequestDelegate next,
|
public DownstreamRouteFinderMiddleware(RequestDelegate next,
|
||||||
IOcelotLoggerFactory loggerFactory,
|
IOcelotLoggerFactory loggerFactory,
|
||||||
IDownstreamRouteFinder downstreamRouteFinder,
|
IDownstreamRouteFinder downstreamRouteFinder,
|
||||||
IRequestScopedDataRepository requestScopedDataRepository)
|
IRequestScopedDataRepository requestScopedDataRepository,
|
||||||
|
IOcelotConfigurationProvider configProvider)
|
||||||
:base(requestScopedDataRepository)
|
:base(requestScopedDataRepository)
|
||||||
{
|
{
|
||||||
|
_configProvider = configProvider;
|
||||||
_next = next;
|
_next = next;
|
||||||
_downstreamRouteFinder = downstreamRouteFinder;
|
_downstreamRouteFinder = downstreamRouteFinder;
|
||||||
_logger = loggerFactory.CreateLogger<DownstreamRouteFinderMiddleware>();
|
_logger = loggerFactory.CreateLogger<DownstreamRouteFinderMiddleware>();
|
||||||
@ -32,9 +36,19 @@ namespace Ocelot.DownstreamRouteFinder.Middleware
|
|||||||
{
|
{
|
||||||
var upstreamUrlPath = context.Request.Path.ToString();
|
var upstreamUrlPath = context.Request.Path.ToString();
|
||||||
|
|
||||||
|
//todo make this getting config its own middleware one day?
|
||||||
|
var configuration = await _configProvider.Get();
|
||||||
|
if(configuration.IsError)
|
||||||
|
{
|
||||||
|
_logger.LogError($"{MiddlewareName} setting pipeline errors. IOcelotConfigurationProvider returned {configuration.Errors.ToErrorString()}");
|
||||||
|
SetPipelineError(configuration.Errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetServiceProviderConfigurationForThisRequest(configuration.Data.ServiceProviderConfiguration);
|
||||||
|
|
||||||
_logger.LogDebug("upstream url path is {upstreamUrlPath}", upstreamUrlPath);
|
_logger.LogDebug("upstream url path is {upstreamUrlPath}", upstreamUrlPath);
|
||||||
|
|
||||||
var downstreamRoute = await _downstreamRouteFinder.FindDownstreamRoute(upstreamUrlPath, context.Request.Method);
|
var downstreamRoute = _downstreamRouteFinder.FindDownstreamRoute(upstreamUrlPath, context.Request.Method, configuration.Data);
|
||||||
|
|
||||||
if (downstreamRoute.IsError)
|
if (downstreamRoute.IsError)
|
||||||
{
|
{
|
||||||
|
@ -13,7 +13,7 @@ namespace Ocelot.DownstreamRouteFinder.UrlMatcher
|
|||||||
|
|
||||||
for (int counterForTemplate = 0; counterForTemplate < upstreamUrlPathTemplate.Length; counterForTemplate++)
|
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]))
|
if (IsPlaceholder(upstreamUrlPathTemplate[counterForTemplate]))
|
||||||
{
|
{
|
||||||
|
@ -10,5 +10,10 @@ namespace Ocelot.Errors
|
|||||||
|
|
||||||
public string Message { get; private set; }
|
public string Message { get; private set; }
|
||||||
public OcelotErrorCode Code { 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;
|
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))
|
if(_httpContextAccessor.HttpContext.Items.TryGetValue(key, out obj))
|
||||||
{
|
{
|
||||||
var data = (T) obj;
|
var data = (T) obj;
|
||||||
|
@ -5,6 +5,6 @@ namespace Ocelot.LoadBalancer.LoadBalancers
|
|||||||
{
|
{
|
||||||
public interface ILoadBalancerFactory
|
public interface ILoadBalancerFactory
|
||||||
{
|
{
|
||||||
Task<ILoadBalancer> Get(ReRoute reRoute);
|
Task<ILoadBalancer> Get(ReRoute reRoute, ServiceProviderConfiguration config);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,10 +1,11 @@
|
|||||||
using Ocelot.Responses;
|
using System.Threading.Tasks;
|
||||||
|
using Ocelot.Configuration;
|
||||||
|
using Ocelot.Responses;
|
||||||
|
|
||||||
namespace Ocelot.LoadBalancer.LoadBalancers
|
namespace Ocelot.LoadBalancer.LoadBalancers
|
||||||
{
|
{
|
||||||
public interface ILoadBalancerHouse
|
public interface ILoadBalancerHouse
|
||||||
{
|
{
|
||||||
Response<ILoadBalancer> Get(string key);
|
Task<Response<ILoadBalancer>> Get(ReRoute reRoute, ServiceProviderConfiguration config);
|
||||||
Response Add(string key, ILoadBalancer loadBalancer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,14 +8,14 @@ using Ocelot.Values;
|
|||||||
|
|
||||||
namespace Ocelot.LoadBalancer.LoadBalancers
|
namespace Ocelot.LoadBalancer.LoadBalancers
|
||||||
{
|
{
|
||||||
public class LeastConnectionLoadBalancer : ILoadBalancer
|
public class LeastConnection : ILoadBalancer
|
||||||
{
|
{
|
||||||
private readonly Func<Task<List<Service>>> _services;
|
private readonly Func<Task<List<Service>>> _services;
|
||||||
private readonly List<Lease> _leases;
|
private readonly List<Lease> _leases;
|
||||||
private readonly string _serviceName;
|
private readonly string _serviceName;
|
||||||
private static readonly object _syncLock = new object();
|
private static readonly object _syncLock = new object();
|
||||||
|
|
||||||
public LeastConnectionLoadBalancer(Func<Task<List<Service>>> services, string serviceName)
|
public LeastConnection(Func<Task<List<Service>>> services, string serviceName)
|
||||||
{
|
{
|
||||||
_services = services;
|
_services = services;
|
||||||
_serviceName = serviceName;
|
_serviceName = serviceName;
|
@ -12,16 +12,16 @@ namespace Ocelot.LoadBalancer.LoadBalancers
|
|||||||
_serviceProviderFactory = serviceProviderFactory;
|
_serviceProviderFactory = serviceProviderFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ILoadBalancer> Get(ReRoute reRoute)
|
public async Task<ILoadBalancer> Get(ReRoute reRoute, ServiceProviderConfiguration config)
|
||||||
{
|
{
|
||||||
var serviceProvider = _serviceProviderFactory.Get(reRoute.ServiceProviderConfiguraion);
|
var serviceProvider = _serviceProviderFactory.Get(config, reRoute);
|
||||||
|
|
||||||
switch (reRoute.LoadBalancer)
|
switch (reRoute.LoadBalancer)
|
||||||
{
|
{
|
||||||
case "RoundRobin":
|
case "RoundRobin":
|
||||||
return new RoundRobinLoadBalancer(async () => await serviceProvider.Get());
|
return new RoundRobin(async () => await serviceProvider.Get());
|
||||||
case "LeastConnection":
|
case "LeastConnection":
|
||||||
return new LeastConnectionLoadBalancer(async () => await serviceProvider.Get(), reRoute.ServiceProviderConfiguraion.ServiceName);
|
return new LeastConnection(async () => await serviceProvider.Get(), reRoute.ServiceName);
|
||||||
default:
|
default:
|
||||||
return new NoLoadBalancer(await serviceProvider.Get());
|
return new NoLoadBalancer(await serviceProvider.Get());
|
||||||
}
|
}
|
||||||
|
@ -1,42 +1,56 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Ocelot.Configuration;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
|
|
||||||
namespace Ocelot.LoadBalancer.LoadBalancers
|
namespace Ocelot.LoadBalancer.LoadBalancers
|
||||||
{
|
{
|
||||||
public class LoadBalancerHouse : ILoadBalancerHouse
|
public class LoadBalancerHouse : ILoadBalancerHouse
|
||||||
{
|
{
|
||||||
private readonly Dictionary<string, ILoadBalancer> _loadBalancers;
|
private readonly ILoadBalancerFactory _factory;
|
||||||
|
private readonly ConcurrentDictionary<string, ILoadBalancer> _loadBalancers;
|
||||||
|
|
||||||
public LoadBalancerHouse()
|
public LoadBalancerHouse(ILoadBalancerFactory factory)
|
||||||
{
|
{
|
||||||
_loadBalancers = new Dictionary<string, ILoadBalancer>();
|
_factory = factory;
|
||||||
|
_loadBalancers = new ConcurrentDictionary<string, ILoadBalancer>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Response<ILoadBalancer> Get(string key)
|
public async Task<Response<ILoadBalancer>> Get(ReRoute reRoute, ServiceProviderConfiguration config)
|
||||||
{
|
{
|
||||||
ILoadBalancer loadBalancer;
|
try
|
||||||
|
|
||||||
if(_loadBalancers.TryGetValue(key, out loadBalancer))
|
|
||||||
{
|
{
|
||||||
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>()
|
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.AddOrUpdate(key, loadBalancer, (x, y) => loadBalancer);
|
||||||
{
|
|
||||||
_loadBalancers.Add(key, loadBalancer);
|
|
||||||
}
|
|
||||||
|
|
||||||
_loadBalancers.Remove(key);
|
|
||||||
_loadBalancers.Add(key, loadBalancer);
|
|
||||||
return new OkResponse();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,13 +6,13 @@ using System;
|
|||||||
|
|
||||||
namespace Ocelot.LoadBalancer.LoadBalancers
|
namespace Ocelot.LoadBalancer.LoadBalancers
|
||||||
{
|
{
|
||||||
public class RoundRobinLoadBalancer : ILoadBalancer
|
public class RoundRobin : ILoadBalancer
|
||||||
{
|
{
|
||||||
private readonly Func<Task<List<Service>>> _services;
|
private readonly Func<Task<List<Service>>> _services;
|
||||||
|
|
||||||
private int _last;
|
private int _last;
|
||||||
|
|
||||||
public RoundRobinLoadBalancer(Func<Task<List<Service>>> services)
|
public RoundRobin(Func<Task<List<Service>>> services)
|
||||||
{
|
{
|
||||||
_services = services;
|
_services = services;
|
||||||
}
|
}
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Ocelot.Configuration.Provider;
|
||||||
using Ocelot.Infrastructure.RequestData;
|
using Ocelot.Infrastructure.RequestData;
|
||||||
using Ocelot.LoadBalancer.LoadBalancers;
|
using Ocelot.LoadBalancer.LoadBalancers;
|
||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
@ -28,7 +29,7 @@ namespace Ocelot.LoadBalancer.Middleware
|
|||||||
|
|
||||||
public async Task Invoke(HttpContext context)
|
public async Task Invoke(HttpContext context)
|
||||||
{
|
{
|
||||||
var loadBalancer = _loadBalancerHouse.Get(DownstreamRoute.ReRoute.ReRouteKey);
|
var loadBalancer = await _loadBalancerHouse.Get(DownstreamRoute.ReRoute, ServiceProviderConfiguration);
|
||||||
if(loadBalancer.IsError)
|
if(loadBalancer.IsError)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("there was an error retriving the loadbalancer, setting pipeline error");
|
_logger.LogDebug("there was an error retriving the loadbalancer, setting pipeline error");
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using Ocelot.Configuration;
|
||||||
using Ocelot.DownstreamRouteFinder;
|
using Ocelot.DownstreamRouteFinder;
|
||||||
using Ocelot.Errors;
|
using Ocelot.Errors;
|
||||||
using Ocelot.Infrastructure.RequestData;
|
using Ocelot.Infrastructure.RequestData;
|
||||||
@ -30,11 +31,18 @@ namespace Ocelot.Middleware
|
|||||||
|
|
||||||
public HttpResponseMessage HttpResponseMessage => _requestScopedDataRepository.Get<HttpResponseMessage>("HttpResponseMessage").Data;
|
public HttpResponseMessage HttpResponseMessage => _requestScopedDataRepository.Get<HttpResponseMessage>("HttpResponseMessage").Data;
|
||||||
|
|
||||||
|
public ServiceProviderConfiguration ServiceProviderConfiguration => _requestScopedDataRepository.Get<ServiceProviderConfiguration>("ServiceProviderConfiguration").Data;
|
||||||
|
|
||||||
public void SetDownstreamRouteForThisRequest(DownstreamRoute downstreamRoute)
|
public void SetDownstreamRouteForThisRequest(DownstreamRoute downstreamRoute)
|
||||||
{
|
{
|
||||||
_requestScopedDataRepository.Add("DownstreamRoute", downstreamRoute);
|
_requestScopedDataRepository.Add("DownstreamRoute", downstreamRoute);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetServiceProviderConfigurationForThisRequest(ServiceProviderConfiguration serviceProviderConfiguration)
|
||||||
|
{
|
||||||
|
_requestScopedDataRepository.Add("ServiceProviderConfiguration", serviceProviderConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
public void SetUpstreamRequestForThisRequest(Request.Request request)
|
public void SetUpstreamRequestForThisRequest(Request.Request request)
|
||||||
{
|
{
|
||||||
_requestScopedDataRepository.Add("Request", request);
|
_requestScopedDataRepository.Add("Request", request);
|
||||||
|
@ -23,16 +23,20 @@ using Ocelot.RateLimit.Middleware;
|
|||||||
namespace Ocelot.Middleware
|
namespace Ocelot.Middleware
|
||||||
{
|
{
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Authorisation.Middleware;
|
using Authorisation.Middleware;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
|
using Ocelot.Configuration.Creator;
|
||||||
using Ocelot.Configuration.File;
|
using Ocelot.Configuration.File;
|
||||||
using Ocelot.Configuration.Provider;
|
using Ocelot.Configuration.Provider;
|
||||||
|
using Ocelot.Configuration.Repository;
|
||||||
using Ocelot.Configuration.Setter;
|
using Ocelot.Configuration.Setter;
|
||||||
using Ocelot.LoadBalancer.Middleware;
|
using Ocelot.LoadBalancer.Middleware;
|
||||||
|
using Ocelot.Responses;
|
||||||
|
|
||||||
public static class OcelotMiddlewareExtensions
|
public static class OcelotMiddlewareExtensions
|
||||||
{
|
{
|
||||||
@ -56,7 +60,9 @@ namespace Ocelot.Middleware
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder, OcelotMiddlewareConfiguration middlewareConfiguration)
|
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);
|
ConfigureDiagnosticListener(builder);
|
||||||
|
|
||||||
@ -145,38 +151,110 @@ namespace Ocelot.Middleware
|
|||||||
|
|
||||||
private static async Task<IOcelotConfiguration> CreateConfiguration(IApplicationBuilder builder)
|
private static async Task<IOcelotConfiguration> CreateConfiguration(IApplicationBuilder builder)
|
||||||
{
|
{
|
||||||
var fileConfig = (IOptions<FileConfiguration>)builder.ApplicationServices.GetService(typeof(IOptions<FileConfiguration>));
|
var deps = GetDependencies(builder);
|
||||||
|
|
||||||
var configSetter = (IFileConfigurationSetter)builder.ApplicationServices.GetService(typeof(IFileConfigurationSetter));
|
var ocelotConfiguration = await deps.provider.Get();
|
||||||
|
|
||||||
var configProvider = (IOcelotConfigurationProvider)builder.ApplicationServices.GetService(typeof(IOcelotConfigurationProvider));
|
if (ConfigurationNotSetUp(ocelotConfiguration))
|
||||||
|
|
||||||
var ocelotConfiguration = await configProvider.Get();
|
|
||||||
|
|
||||||
if (ocelotConfiguration == null || ocelotConfiguration.Data == null || ocelotConfiguration.IsError)
|
|
||||||
{
|
{
|
||||||
var config = await configSetter.Set(fileConfig.Value);
|
var response = await SetConfig(builder, deps.fileConfiguration, deps.setter, deps.provider, deps.repo);
|
||||||
|
|
||||||
if (config == null || config.IsError)
|
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)
|
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;
|
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));
|
var identityServerConfiguration = (IIdentityServerConfiguration)builder.ApplicationServices.GetService(typeof(IIdentityServerConfiguration));
|
||||||
|
|
||||||
if(!string.IsNullOrEmpty(configuration.AdministrationPath) && identityServerConfiguration != null)
|
if(!string.IsNullOrEmpty(configuration.AdministrationPath) && identityServerConfiguration != null)
|
||||||
|
@ -32,7 +32,7 @@ namespace Ocelot.Request.Middleware
|
|||||||
{
|
{
|
||||||
_logger.LogDebug("started calling request builder middleware");
|
_logger.LogDebug("started calling request builder middleware");
|
||||||
|
|
||||||
var qosProvider = _qosProviderHouse.Get(DownstreamRoute.ReRoute.ReRouteKey);
|
var qosProvider = _qosProviderHouse.Get(DownstreamRoute.ReRoute);
|
||||||
|
|
||||||
if (qosProvider.IsError)
|
if (qosProvider.IsError)
|
||||||
{
|
{
|
||||||
|
@ -31,7 +31,6 @@ namespace Ocelot.Requester
|
|||||||
|
|
||||||
private HttpMessageHandler CreateHttpMessageHandler(HttpMessageHandler httpMessageHandler)
|
private HttpMessageHandler CreateHttpMessageHandler(HttpMessageHandler httpMessageHandler)
|
||||||
{
|
{
|
||||||
|
|
||||||
_handlers
|
_handlers
|
||||||
.OrderByDescending(handler => handler.Key)
|
.OrderByDescending(handler => handler.Key)
|
||||||
.Select(handler => handler.Value)
|
.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 Ocelot.Configuration;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Net.Http;
|
|
||||||
using Ocelot.Configuration;
|
|
||||||
using Ocelot.LoadBalancer.LoadBalancers;
|
using Ocelot.LoadBalancer.LoadBalancers;
|
||||||
using Ocelot.Logging;
|
|
||||||
using Ocelot.Responses;
|
|
||||||
using Polly;
|
|
||||||
using Polly.CircuitBreaker;
|
|
||||||
using Polly.Timeout;
|
|
||||||
|
|
||||||
namespace Ocelot.Requester.QoS
|
namespace Ocelot.Requester.QoS
|
||||||
{
|
{
|
||||||
@ -15,131 +7,4 @@ namespace Ocelot.Requester.QoS
|
|||||||
{
|
{
|
||||||
IQoSProvider Get(ReRoute reRoute);
|
IQoSProvider Get(ReRoute reRoute);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class QoSProviderFactory : IQoSProviderFactory
|
|
||||||
{
|
|
||||||
private readonly IOcelotLoggerFactory _loggerFactory;
|
|
||||||
|
|
||||||
public QoSProviderFactory(IOcelotLoggerFactory loggerFactory)
|
|
||||||
{
|
|
||||||
_loggerFactory = loggerFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IQoSProvider Get(ReRoute reRoute)
|
|
||||||
{
|
|
||||||
if (reRoute.IsQos)
|
|
||||||
{
|
|
||||||
return new PollyQoSProvider(reRoute, _loggerFactory);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new NoQoSProvider();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IQoSProvider
|
|
||||||
{
|
|
||||||
CircuitBreaker CircuitBreaker { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class NoQoSProvider : IQoSProvider
|
|
||||||
{
|
|
||||||
public CircuitBreaker CircuitBreaker { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PollyQoSProvider : IQoSProvider
|
|
||||||
{
|
|
||||||
private readonly CircuitBreakerPolicy _circuitBreakerPolicy;
|
|
||||||
private readonly TimeoutPolicy _timeoutPolicy;
|
|
||||||
private readonly IOcelotLogger _logger;
|
|
||||||
private readonly CircuitBreaker _circuitBreaker;
|
|
||||||
|
|
||||||
public PollyQoSProvider(ReRoute reRoute, IOcelotLoggerFactory loggerFactory)
|
|
||||||
{
|
|
||||||
_logger = loggerFactory.CreateLogger<PollyQoSProvider>();
|
|
||||||
|
|
||||||
_timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromMilliseconds(reRoute.QosOptionsOptions.TimeoutValue), reRoute.QosOptionsOptions.TimeoutStrategy);
|
|
||||||
|
|
||||||
_circuitBreakerPolicy = Policy
|
|
||||||
.Handle<HttpRequestException>()
|
|
||||||
.Or<TimeoutRejectedException>()
|
|
||||||
.Or<TimeoutException>()
|
|
||||||
.CircuitBreakerAsync(
|
|
||||||
exceptionsAllowedBeforeBreaking: reRoute.QosOptionsOptions.ExceptionsAllowedBeforeBreaking,
|
|
||||||
durationOfBreak: TimeSpan.FromMilliseconds(reRoute.QosOptionsOptions.DurationOfBreak),
|
|
||||||
onBreak: (ex, breakDelay) =>
|
|
||||||
{
|
|
||||||
_logger.LogError(
|
|
||||||
".Breaker logging: Breaking the circuit for " + breakDelay.TotalMilliseconds + "ms!", ex);
|
|
||||||
},
|
|
||||||
onReset: () =>
|
|
||||||
{
|
|
||||||
_logger.LogDebug(".Breaker logging: Call ok! Closed the circuit again.");
|
|
||||||
},
|
|
||||||
onHalfOpen: () =>
|
|
||||||
{
|
|
||||||
_logger.LogDebug(".Breaker logging: Half-open; next call is a trial.");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
_circuitBreaker = new CircuitBreaker(_circuitBreakerPolicy, _timeoutPolicy);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CircuitBreaker CircuitBreaker => _circuitBreaker;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CircuitBreaker
|
|
||||||
{
|
|
||||||
public CircuitBreaker(CircuitBreakerPolicy circuitBreakerPolicy, TimeoutPolicy timeoutPolicy)
|
|
||||||
{
|
|
||||||
CircuitBreakerPolicy = circuitBreakerPolicy;
|
|
||||||
TimeoutPolicy = timeoutPolicy;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CircuitBreakerPolicy CircuitBreakerPolicy { get; private set; }
|
|
||||||
public TimeoutPolicy TimeoutPolicy { get; private set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public interface IQosProviderHouse
|
|
||||||
{
|
|
||||||
Response<IQoSProvider> Get(string key);
|
|
||||||
Response Add(string key, IQoSProvider loadBalancer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class QosProviderHouse : IQosProviderHouse
|
|
||||||
{
|
|
||||||
private readonly Dictionary<string, IQoSProvider> _qoSProviders;
|
|
||||||
|
|
||||||
public QosProviderHouse()
|
|
||||||
{
|
|
||||||
_qoSProviders = new Dictionary<string, IQoSProvider>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Response<IQoSProvider> Get(string key)
|
|
||||||
{
|
|
||||||
IQoSProvider qoSProvider;
|
|
||||||
|
|
||||||
if (_qoSProviders.TryGetValue(key, out qoSProvider))
|
|
||||||
{
|
|
||||||
return new OkResponse<IQoSProvider>(_qoSProviders[key]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ErrorResponse<IQoSProvider>(new List<Ocelot.Errors.Error>()
|
|
||||||
{
|
|
||||||
new UnableToFindQoSProviderError($"unabe to find qos provider for {key}")
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public Response Add(string key, IQoSProvider loadBalancer)
|
|
||||||
{
|
|
||||||
if (!_qoSProviders.ContainsKey(key))
|
|
||||||
{
|
|
||||||
_qoSProviders.Add(key, loadBalancer);
|
|
||||||
}
|
|
||||||
|
|
||||||
_qoSProviders.Remove(key);
|
|
||||||
_qoSProviders.Add(key, loadBalancer);
|
|
||||||
return new OkResponse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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 class ConsulRegistryConfiguration
|
||||||
{
|
{
|
||||||
public ConsulRegistryConfiguration(string hostName, int port, string serviceName)
|
public ConsulRegistryConfiguration(string hostName, int port, string keyOfServiceInConsul)
|
||||||
{
|
{
|
||||||
HostName = hostName;
|
HostName = hostName;
|
||||||
Port = port;
|
Port = port;
|
||||||
ServiceName = serviceName;
|
KeyOfServiceInConsul = keyOfServiceInConsul;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ServiceName { get; private set; }
|
public string KeyOfServiceInConsul { get; private set; }
|
||||||
public string HostName { get; private set; }
|
public string HostName { get; private set; }
|
||||||
public int Port { get; private set; }
|
public int Port { get; private set; }
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ namespace Ocelot.ServiceDiscovery
|
|||||||
{
|
{
|
||||||
public class ConsulServiceDiscoveryProvider : IServiceDiscoveryProvider
|
public class ConsulServiceDiscoveryProvider : IServiceDiscoveryProvider
|
||||||
{
|
{
|
||||||
private readonly ConsulRegistryConfiguration _configuration;
|
private readonly ConsulRegistryConfiguration _consulConfig;
|
||||||
private readonly ConsulClient _consul;
|
private readonly ConsulClient _consul;
|
||||||
private const string VersionPrefix = "version-";
|
private const string VersionPrefix = "version-";
|
||||||
|
|
||||||
@ -18,17 +18,17 @@ namespace Ocelot.ServiceDiscovery
|
|||||||
{
|
{
|
||||||
var consulHost = string.IsNullOrEmpty(consulRegistryConfiguration?.HostName) ? "localhost" : consulRegistryConfiguration.HostName;
|
var consulHost = string.IsNullOrEmpty(consulRegistryConfiguration?.HostName) ? "localhost" : consulRegistryConfiguration.HostName;
|
||||||
var consulPort = consulRegistryConfiguration?.Port ?? 8500;
|
var consulPort = consulRegistryConfiguration?.Port ?? 8500;
|
||||||
_configuration = new ConsulRegistryConfiguration(consulHost, consulPort, consulRegistryConfiguration?.ServiceName);
|
_consulConfig = new ConsulRegistryConfiguration(consulHost, consulPort, consulRegistryConfiguration?.KeyOfServiceInConsul);
|
||||||
|
|
||||||
_consul = new ConsulClient(config =>
|
_consul = new ConsulClient(config =>
|
||||||
{
|
{
|
||||||
config.Address = new Uri($"http://{_configuration.HostName}:{_configuration.Port}");
|
config.Address = new Uri($"http://{_consulConfig.HostName}:{_consulConfig.Port}");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<Service>> Get()
|
public async Task<List<Service>> Get()
|
||||||
{
|
{
|
||||||
var queryResult = await _consul.Health.Service(_configuration.ServiceName, string.Empty, true);
|
var queryResult = await _consul.Health.Service(_consulConfig.KeyOfServiceInConsul, string.Empty, true);
|
||||||
|
|
||||||
var services = queryResult.Response.Select(BuildService);
|
var services = queryResult.Response.Select(BuildService);
|
||||||
|
|
||||||
|
@ -4,6 +4,6 @@ namespace Ocelot.ServiceDiscovery
|
|||||||
{
|
{
|
||||||
public interface IServiceDiscoveryProviderFactory
|
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 class ServiceDiscoveryProviderFactory : IServiceDiscoveryProviderFactory
|
||||||
{
|
{
|
||||||
public IServiceDiscoveryProvider Get(ServiceProviderConfiguration serviceConfig)
|
public IServiceDiscoveryProvider Get(ServiceProviderConfiguration serviceConfig, ReRoute reRoute)
|
||||||
{
|
{
|
||||||
if (serviceConfig.UseServiceDiscovery)
|
if (reRoute.UseServiceDiscovery)
|
||||||
{
|
{
|
||||||
return GetServiceDiscoveryProvider(serviceConfig.ServiceName, serviceConfig.ServiceDiscoveryProvider, serviceConfig.ServiceProviderHost, serviceConfig.ServiceProviderPort);
|
return GetServiceDiscoveryProvider(reRoute.ServiceName, serviceConfig.ServiceProviderHost, serviceConfig.ServiceProviderPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
var services = new List<Service>()
|
var services = new List<Service>()
|
||||||
{
|
{
|
||||||
new Service(serviceConfig.ServiceName,
|
new Service(reRoute.ServiceName,
|
||||||
new HostAndPort(serviceConfig.DownstreamHost, serviceConfig.DownstreamPort),
|
new HostAndPort(reRoute.DownstreamHost, reRoute.DownstreamPort),
|
||||||
string.Empty,
|
string.Empty,
|
||||||
string.Empty,
|
string.Empty,
|
||||||
new string[0])
|
new string[0])
|
||||||
@ -25,9 +25,9 @@ namespace Ocelot.ServiceDiscovery
|
|||||||
return new ConfigurationServiceProvider(services);
|
return new ConfigurationServiceProvider(services);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IServiceDiscoveryProvider GetServiceDiscoveryProvider(string serviceName, string serviceProviderName, string providerHostName, int providerPort)
|
private IServiceDiscoveryProvider GetServiceDiscoveryProvider(string keyOfServiceInConsul, string providerHostName, int providerPort)
|
||||||
{
|
{
|
||||||
var consulRegistryConfiguration = new ConsulRegistryConfiguration(providerHostName, providerPort, serviceName);
|
var consulRegistryConfiguration = new ConsulRegistryConfiguration(providerHostName, providerPort, keyOfServiceInConsul);
|
||||||
return new ConsulServiceDiscoveryProvider(consulRegistryConfiguration);
|
return new ConsulServiceDiscoveryProvider(consulRegistryConfiguration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
|
using Ocelot.Configuration.Builder;
|
||||||
using Ocelot.Configuration.File;
|
using Ocelot.Configuration.File;
|
||||||
using Ocelot.ServiceDiscovery;
|
|
||||||
using TestStack.BDDfy;
|
using TestStack.BDDfy;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Ocelot.AcceptanceTests
|
namespace Ocelot.AcceptanceTests
|
||||||
{
|
{
|
||||||
public class ConfigurationInConsul : IDisposable
|
public class ConfigurationInConsulTests : IDisposable
|
||||||
{
|
{
|
||||||
private IWebHost _builder;
|
private IWebHost _builder;
|
||||||
private readonly Steps _steps;
|
private readonly Steps _steps;
|
||||||
private IWebHost _fakeConsulBuilder;
|
private IWebHost _fakeConsulBuilder;
|
||||||
private IOcelotConfiguration _config;
|
private FileConfiguration _config;
|
||||||
|
|
||||||
public ConfigurationInConsul()
|
public ConfigurationInConsulTests()
|
||||||
{
|
{
|
||||||
_steps = new Steps();
|
_steps = new Steps();
|
||||||
}
|
}
|
||||||
@ -48,7 +50,6 @@ namespace Ocelot.AcceptanceTests
|
|||||||
{
|
{
|
||||||
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
|
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
|
||||||
{
|
{
|
||||||
Provider = "Consul",
|
|
||||||
Host = "localhost",
|
Host = "localhost",
|
||||||
Port = 9500
|
Port = 9500
|
||||||
}
|
}
|
||||||
@ -57,18 +58,162 @@ namespace Ocelot.AcceptanceTests
|
|||||||
|
|
||||||
var fakeConsulServiceDiscoveryUrl = "http://localhost:9500";
|
var fakeConsulServiceDiscoveryUrl = "http://localhost:9500";
|
||||||
|
|
||||||
var consulConfig = new ConsulRegistryConfiguration("localhost", 9500, "Ocelot");
|
|
||||||
|
|
||||||
this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl))
|
this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl))
|
||||||
.And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51779", 200, "Hello from Laura"))
|
.And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51779", "", 200, "Hello from Laura"))
|
||||||
.And(x => _steps.GivenThereIsAConfiguration(configuration))
|
.And(x => _steps.GivenThereIsAConfiguration(configuration))
|
||||||
.And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfig(consulConfig))
|
.And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfig())
|
||||||
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
|
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
|
||||||
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
||||||
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
|
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_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)
|
private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url)
|
||||||
{
|
{
|
||||||
_fakeConsulBuilder = new WebHostBuilder()
|
_fakeConsulBuilder = new WebHostBuilder()
|
||||||
@ -102,7 +247,7 @@ namespace Ocelot.AcceptanceTests
|
|||||||
|
|
||||||
var json = reader.ReadToEnd();
|
var json = reader.ReadToEnd();
|
||||||
|
|
||||||
_config = JsonConvert.DeserializeObject<OcelotConfiguration>(json);
|
_config = JsonConvert.DeserializeObject<FileConfiguration>(json);
|
||||||
|
|
||||||
var response = JsonConvert.SerializeObject(true);
|
var response = JsonConvert.SerializeObject(true);
|
||||||
|
|
||||||
@ -137,7 +282,7 @@ namespace Ocelot.AcceptanceTests
|
|||||||
public string Session => "adf4238a-882b-9ddc-4a9d-5b6758e4159e";
|
public string Session => "adf4238a-882b-9ddc-4a9d-5b6758e4159e";
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody)
|
private void GivenThereIsAServiceRunningOn(string url, string basePath, int statusCode, string responseBody)
|
||||||
{
|
{
|
||||||
_builder = new WebHostBuilder()
|
_builder = new WebHostBuilder()
|
||||||
.UseUrls(url)
|
.UseUrls(url)
|
||||||
@ -147,6 +292,8 @@ namespace Ocelot.AcceptanceTests
|
|||||||
.UseUrls(url)
|
.UseUrls(url)
|
||||||
.Configure(app =>
|
.Configure(app =>
|
||||||
{
|
{
|
||||||
|
app.UsePathBase(basePath);
|
||||||
|
|
||||||
app.Run(async context =>
|
app.Run(async context =>
|
||||||
{
|
{
|
||||||
context.Response.StatusCode = statusCode;
|
context.Response.StatusCode = statusCode;
|
||||||
|
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]
|
[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
|
var configuration = new FileConfiguration
|
||||||
{
|
{
|
||||||
@ -187,7 +187,7 @@ namespace Ocelot.AcceptanceTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[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
|
var configuration = new FileConfiguration
|
||||||
{
|
{
|
||||||
@ -209,8 +209,7 @@ namespace Ocelot.AcceptanceTests
|
|||||||
.And(x => _steps.GivenThereIsAConfiguration(configuration))
|
.And(x => _steps.GivenThereIsAConfiguration(configuration))
|
||||||
.And(x => _steps.GivenOcelotIsRunning())
|
.And(x => _steps.GivenOcelotIsRunning())
|
||||||
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/products/"))
|
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/products/"))
|
||||||
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound))
|
||||||
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
|
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -483,6 +482,41 @@ namespace Ocelot.AcceptanceTests
|
|||||||
.BDDfy();
|
.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)
|
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody)
|
||||||
{
|
{
|
||||||
_builder = new WebHostBuilder()
|
_builder = new WebHostBuilder()
|
||||||
@ -495,7 +529,7 @@ namespace Ocelot.AcceptanceTests
|
|||||||
app.UsePathBase(basePath);
|
app.UsePathBase(basePath);
|
||||||
app.Run(async context =>
|
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;
|
context.Response.StatusCode = statusCode;
|
||||||
await context.Response.WriteAsync(responseBody);
|
await context.Response.WriteAsync(responseBody);
|
||||||
});
|
});
|
||||||
|
@ -33,10 +33,11 @@ namespace Ocelot.AcceptanceTests
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void should_use_service_discovery_and_load_balance_request()
|
public void should_use_service_discovery_and_load_balance_request()
|
||||||
{
|
{
|
||||||
|
var consulPort = 8501;
|
||||||
var serviceName = "product";
|
var serviceName = "product";
|
||||||
var downstreamServiceOneUrl = "http://localhost:50879";
|
var downstreamServiceOneUrl = "http://localhost:50879";
|
||||||
var downstreamServiceTwoUrl = "http://localhost:50880";
|
var downstreamServiceTwoUrl = "http://localhost:50880";
|
||||||
var fakeConsulServiceDiscoveryUrl = "http://localhost:8500";
|
var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}";
|
||||||
var serviceEntryOne = new ServiceEntry()
|
var serviceEntryOne = new ServiceEntry()
|
||||||
{
|
{
|
||||||
Service = new AgentService()
|
Service = new AgentService()
|
||||||
@ -72,15 +73,15 @@ namespace Ocelot.AcceptanceTests
|
|||||||
UpstreamHttpMethod = new List<string> { "Get" },
|
UpstreamHttpMethod = new List<string> { "Get" },
|
||||||
ServiceName = serviceName,
|
ServiceName = serviceName,
|
||||||
LoadBalancer = "LeastConnection",
|
LoadBalancer = "LeastConnection",
|
||||||
|
UseServiceDiscovery = true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
GlobalConfiguration = new FileGlobalConfiguration()
|
GlobalConfiguration = new FileGlobalConfiguration()
|
||||||
{
|
{
|
||||||
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
|
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
|
||||||
{
|
{
|
||||||
Provider = "Consul",
|
|
||||||
Host = "localhost",
|
Host = "localhost",
|
||||||
Port = 8500
|
Port = consulPort
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -99,8 +100,8 @@ namespace Ocelot.AcceptanceTests
|
|||||||
|
|
||||||
private void ThenBothServicesCalledRealisticAmountOfTimes()
|
private void ThenBothServicesCalledRealisticAmountOfTimes()
|
||||||
{
|
{
|
||||||
_counterOne.ShouldBe(25);
|
_counterOne.ShouldBeInRange(24,26);
|
||||||
_counterTwo.ShouldBe(25);
|
_counterOne.ShouldBeInRange(24,26);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenTheTwoServicesShouldHaveBeenCalledTimes(int expected)
|
private void ThenTheTwoServicesShouldHaveBeenCalledTimes(int expected)
|
||||||
|
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();
|
_ocelotClient = _ocelotServer.CreateClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GivenOcelotIsRunningUsingConsulToStoreConfig(ConsulRegistryConfiguration consulConfig)
|
public void GivenOcelotIsRunningUsingConsulToStoreConfig()
|
||||||
{
|
{
|
||||||
_webHostBuilder = new WebHostBuilder();
|
_webHostBuilder = new WebHostBuilder();
|
||||||
|
|
||||||
_webHostBuilder.ConfigureServices(s =>
|
_webHostBuilder.ConfigureServices(s =>
|
||||||
{
|
{
|
||||||
s.AddSingleton(_webHostBuilder);
|
s.AddSingleton(_webHostBuilder);
|
||||||
s.AddOcelotStoreConfigurationInConsul(consulConfig);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
_ocelotServer = new TestServer(_webHostBuilder
|
_ocelotServer = new TestServer(_webHostBuilder
|
||||||
.UseStartup<Startup>());
|
.UseStartup<ConsulStartup>());
|
||||||
|
|
||||||
_ocelotClient = _ocelotServer.CreateClient();
|
_ocelotClient = _ocelotServer.CreateClient();
|
||||||
}
|
}
|
||||||
@ -131,7 +130,6 @@ namespace Ocelot.AcceptanceTests
|
|||||||
response.GlobalConfiguration.RequestIdKey.ShouldBe(expected.GlobalConfiguration.RequestIdKey);
|
response.GlobalConfiguration.RequestIdKey.ShouldBe(expected.GlobalConfiguration.RequestIdKey);
|
||||||
response.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Host);
|
response.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Host);
|
||||||
response.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Port);
|
response.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Port);
|
||||||
response.GlobalConfiguration.ServiceDiscoveryProvider.Provider.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Provider);
|
|
||||||
|
|
||||||
for(var i = 0; i < response.ReRoutes.Count; i++)
|
for(var i = 0; i < response.ReRoutes.Count; i++)
|
||||||
{
|
{
|
||||||
@ -175,7 +173,7 @@ namespace Ocelot.AcceptanceTests
|
|||||||
.WithDictionaryHandle();
|
.WithDictionaryHandle();
|
||||||
};
|
};
|
||||||
|
|
||||||
s.AddOcelot(configuration, settings);
|
s.AddOcelot(configuration);
|
||||||
})
|
})
|
||||||
.ConfigureLogging(l =>
|
.ConfigureLogging(l =>
|
||||||
{
|
{
|
||||||
@ -381,42 +379,4 @@ namespace Ocelot.AcceptanceTests
|
|||||||
_response.Headers.GetValues(RequestIdKey).First().ShouldBe(expected);
|
_response.Headers.GetValues(RequestIdKey).First().ShouldBe(expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Startup
|
|
||||||
{
|
|
||||||
public Startup(IHostingEnvironment env)
|
|
||||||
{
|
|
||||||
var builder = new ConfigurationBuilder()
|
|
||||||
.SetBasePath(env.ContentRootPath)
|
|
||||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
|
||||||
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
|
|
||||||
.AddJsonFile("configuration.json")
|
|
||||||
.AddEnvironmentVariables();
|
|
||||||
|
|
||||||
Configuration = builder.Build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IConfigurationRoot Configuration { get; }
|
|
||||||
|
|
||||||
public void ConfigureServices(IServiceCollection services)
|
|
||||||
{
|
|
||||||
Action<ConfigurationBuilderCachePart> settings = (x) =>
|
|
||||||
{
|
|
||||||
x.WithMicrosoftLogging(log =>
|
|
||||||
{
|
|
||||||
log.AddConsole(LogLevel.Debug);
|
|
||||||
})
|
|
||||||
.WithDictionaryHandle();
|
|
||||||
};
|
|
||||||
|
|
||||||
services.AddOcelot(Configuration, settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
|
||||||
{
|
|
||||||
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
|
|
||||||
|
|
||||||
app.UseOcelot().Wait();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,6 @@ namespace Ocelot.IntegrationTests
|
|||||||
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
|
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
|
||||||
{
|
{
|
||||||
Host = "127.0.0.1",
|
Host = "127.0.0.1",
|
||||||
Provider = "test"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
@ -332,7 +331,6 @@ namespace Ocelot.IntegrationTests
|
|||||||
response.GlobalConfiguration.RequestIdKey.ShouldBe(expected.GlobalConfiguration.RequestIdKey);
|
response.GlobalConfiguration.RequestIdKey.ShouldBe(expected.GlobalConfiguration.RequestIdKey);
|
||||||
response.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Host);
|
response.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Host);
|
||||||
response.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Port);
|
response.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Port);
|
||||||
response.GlobalConfiguration.ServiceDiscoveryProvider.Provider.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Provider);
|
|
||||||
|
|
||||||
for (var i = 0; i < response.ReRoutes.Count; i++)
|
for (var i = 0; i < response.ReRoutes.Count; i++)
|
||||||
{
|
{
|
||||||
|
@ -38,7 +38,7 @@ namespace Ocelot.IntegrationTests
|
|||||||
.WithDictionaryHandle();
|
.WithDictionaryHandle();
|
||||||
};
|
};
|
||||||
|
|
||||||
services.AddOcelot(Configuration, settings);
|
services.AddOcelot(Configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
||||||
|
@ -45,7 +45,7 @@ namespace Ocelot.ManualTest
|
|||||||
x.Audience = "test";
|
x.Audience = "test";
|
||||||
});
|
});
|
||||||
|
|
||||||
services.AddOcelot(Configuration, settings);
|
services.AddOcelot(Configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
||||||
|
@ -1,133 +1,62 @@
|
|||||||
// using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
// using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
// using Ocelot.Configuration.Builder;
|
using Ocelot.Configuration.Builder;
|
||||||
// using Ocelot.Configuration.Creator;
|
using Ocelot.Configuration.Creator;
|
||||||
// using Ocelot.Configuration.File;
|
using Ocelot.Configuration.File;
|
||||||
// using Shouldly;
|
using Shouldly;
|
||||||
// using TestStack.BDDfy;
|
using TestStack.BDDfy;
|
||||||
// using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
// namespace Ocelot.UnitTests.Configuration
|
namespace Ocelot.UnitTests.Configuration
|
||||||
// {
|
{
|
||||||
// public class AuthenticationOptionsCreatorTests
|
public class AuthenticationOptionsCreatorTests
|
||||||
// {
|
{
|
||||||
// private readonly AuthenticationOptionsCreator _authOptionsCreator;
|
private readonly AuthenticationOptionsCreator _authOptionsCreator;
|
||||||
// private FileReRoute _fileReRoute;
|
private FileReRoute _fileReRoute;
|
||||||
// private AuthenticationOptions _result;
|
private AuthenticationOptions _result;
|
||||||
|
|
||||||
// public AuthenticationOptionsCreatorTests()
|
public AuthenticationOptionsCreatorTests()
|
||||||
// {
|
{
|
||||||
// _authOptionsCreator = new AuthenticationOptionsCreator(new AuthenticationProviderConfigCreator());
|
_authOptionsCreator = new AuthenticationOptionsCreator();
|
||||||
// }
|
}
|
||||||
|
|
||||||
// [Fact]
|
[Fact]
|
||||||
// public void should_return_auth_options()
|
public void should_return_auth_options()
|
||||||
// {
|
{
|
||||||
// var fileReRoute = new FileReRoute()
|
var fileReRoute = new FileReRoute()
|
||||||
// {
|
{
|
||||||
// AuthenticationOptions = new FileAuthenticationOptions
|
AuthenticationOptions = new FileAuthenticationOptions
|
||||||
// {
|
{
|
||||||
// Provider = "Geoff",
|
AuthenticationProviderKey = "Test",
|
||||||
// IdentityServerConfig = new FileIdentityServerConfig()
|
AllowedScopes = new List<string> { "cheese" },
|
||||||
// {
|
}
|
||||||
// ProviderRootUrl = "http://www.bbc.co.uk/",
|
};
|
||||||
// ApiName = "Laura",
|
|
||||||
// RequireHttps = true,
|
|
||||||
// ApiSecret = "secret"
|
|
||||||
// },
|
|
||||||
// AllowedScopes = new List<string> { "cheese" },
|
|
||||||
|
|
||||||
// }
|
var expected = new AuthenticationOptionsBuilder()
|
||||||
// };
|
.WithAllowedScopes(fileReRoute.AuthenticationOptions?.AllowedScopes)
|
||||||
|
.WithAuthenticationProviderKey("Test")
|
||||||
|
.Build();
|
||||||
|
|
||||||
// var authenticationConfig = new IdentityServerConfigBuilder()
|
this.Given(x => x.GivenTheFollowing(fileReRoute))
|
||||||
// .WithProviderRootUrl(fileReRoute.AuthenticationOptions?.IdentityServerConfig?.ProviderRootUrl)
|
.When(x => x.WhenICreateTheAuthenticationOptions())
|
||||||
// .WithApiName(fileReRoute.AuthenticationOptions?.IdentityServerConfig?.ApiName)
|
.Then(x => x.ThenTheFollowingConfigIsReturned(expected))
|
||||||
// .WithRequireHttps(fileReRoute.AuthenticationOptions.IdentityServerConfig.RequireHttps)
|
.BDDfy();
|
||||||
// .WithApiSecret(fileReRoute.AuthenticationOptions?.IdentityServerConfig?.ApiSecret)
|
}
|
||||||
// .Build();
|
|
||||||
|
|
||||||
// var expected = new AuthenticationOptionsBuilder()
|
private void GivenTheFollowing(FileReRoute fileReRoute)
|
||||||
// .WithProvider(fileReRoute.AuthenticationOptions?.Provider)
|
{
|
||||||
// .WithAllowedScopes(fileReRoute.AuthenticationOptions?.AllowedScopes)
|
_fileReRoute = fileReRoute;
|
||||||
// .WithConfig(authenticationConfig)
|
}
|
||||||
// .Build();
|
|
||||||
|
|
||||||
// this.Given(x => x.GivenTheFollowing(fileReRoute))
|
private void WhenICreateTheAuthenticationOptions()
|
||||||
// .When(x => x.WhenICreateTheAuthenticationOptions())
|
{
|
||||||
// .Then(x => x.ThenTheFollowingIdentityServerConfigIsReturned(expected))
|
_result = _authOptionsCreator.Create(_fileReRoute);
|
||||||
// .BDDfy();
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
// [Fact]
|
private void ThenTheFollowingConfigIsReturned(AuthenticationOptions expected)
|
||||||
// public void should_return_Jwt_auth_options()
|
{
|
||||||
// {
|
_result.AllowedScopes.ShouldBe(expected.AllowedScopes);
|
||||||
// var fileReRoute = new FileReRoute()
|
_result.AuthenticationProviderKey.ShouldBe(expected.AuthenticationProviderKey);
|
||||||
// {
|
}
|
||||||
// AuthenticationOptions = new FileAuthenticationOptions
|
}
|
||||||
// {
|
}
|
||||||
// Provider = "Jwt",
|
|
||||||
// JwtConfig = new FileJwtConfig()
|
|
||||||
// {
|
|
||||||
// Audience = "Audience",
|
|
||||||
// Authority = "Authority"
|
|
||||||
// },
|
|
||||||
// AllowedScopes = new List<string> { "cheese" }
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// var authenticationConfig = new JwtConfigBuilder()
|
|
||||||
// .WithAudience(fileReRoute.AuthenticationOptions?.JwtConfig?.Audience)
|
|
||||||
// .WithAuthority(fileReRoute.AuthenticationOptions?.JwtConfig?.Authority)
|
|
||||||
// .Build();
|
|
||||||
|
|
||||||
// var expected = new AuthenticationOptionsBuilder()
|
|
||||||
// .WithProvider(fileReRoute.AuthenticationOptions?.Provider)
|
|
||||||
// .WithAllowedScopes(fileReRoute.AuthenticationOptions?.AllowedScopes)
|
|
||||||
// .WithConfig(authenticationConfig)
|
|
||||||
// .Build();
|
|
||||||
|
|
||||||
// this.Given(x => x.GivenTheFollowing(fileReRoute))
|
|
||||||
// .When(x => x.WhenICreateTheAuthenticationOptions())
|
|
||||||
// .Then(x => x.ThenTheFollowingJwtConfigIsReturned(expected))
|
|
||||||
// .BDDfy();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// private void GivenTheFollowing(FileReRoute fileReRoute)
|
|
||||||
// {
|
|
||||||
// _fileReRoute = fileReRoute;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// private void WhenICreateTheAuthenticationOptions()
|
|
||||||
// {
|
|
||||||
// _result = _authOptionsCreator.Create(_fileReRoute);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// private void ThenTheFollowingJwtConfigIsReturned(AuthenticationOptions expected)
|
|
||||||
// {
|
|
||||||
// _result.AllowedScopes.ShouldBe(expected.AllowedScopes);
|
|
||||||
// _result.Provider.ShouldBe(expected.Provider);
|
|
||||||
|
|
||||||
// var _resultSettings = _result.Config as JwtConfig;
|
|
||||||
// var expectedSettngs = expected.Config as JwtConfig;
|
|
||||||
|
|
||||||
// _resultSettings.Audience.ShouldBe(expectedSettngs.Audience);
|
|
||||||
// _resultSettings.Authority.ShouldBe(expectedSettngs.Authority);
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// private void ThenTheFollowingIdentityServerConfigIsReturned(AuthenticationOptions expected)
|
|
||||||
// {
|
|
||||||
// _result.AllowedScopes.ShouldBe(expected.AllowedScopes);
|
|
||||||
// _result.Provider.ShouldBe(expected.Provider);
|
|
||||||
|
|
||||||
// var _resultSettings = _result.Config as IdentityServerConfig;
|
|
||||||
// var expectedSettngs = expected.Config as IdentityServerConfig;
|
|
||||||
|
|
||||||
// _resultSettings.ProviderRootUrl.ShouldBe(expectedSettngs.ProviderRootUrl);
|
|
||||||
// _resultSettings.RequireHttps.ShouldBe(expectedSettngs.RequireHttps);
|
|
||||||
// _resultSettings.ApiName.ShouldBe(expectedSettngs.ApiName);
|
|
||||||
// _resultSettings.ApiSecret.ShouldBe(expectedSettngs.ApiSecret);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
@ -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 System.Collections.Generic;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Ocelot.Cache;
|
using Ocelot.Cache;
|
||||||
@ -8,9 +7,7 @@ using Ocelot.Configuration.Builder;
|
|||||||
using Ocelot.Configuration.Creator;
|
using Ocelot.Configuration.Creator;
|
||||||
using Ocelot.Configuration.File;
|
using Ocelot.Configuration.File;
|
||||||
using Ocelot.Configuration.Validator;
|
using Ocelot.Configuration.Validator;
|
||||||
using Ocelot.LoadBalancer.LoadBalancers;
|
|
||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
using Ocelot.Requester.QoS;
|
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
using Shouldly;
|
using Shouldly;
|
||||||
using TestStack.BDDfy;
|
using TestStack.BDDfy;
|
||||||
@ -18,8 +15,7 @@ using Xunit;
|
|||||||
|
|
||||||
namespace Ocelot.UnitTests.Configuration
|
namespace Ocelot.UnitTests.Configuration
|
||||||
{
|
{
|
||||||
using System.Collections;
|
using Ocelot.Errors;
|
||||||
|
|
||||||
using Ocelot.UnitTests.TestData;
|
using Ocelot.UnitTests.TestData;
|
||||||
|
|
||||||
public class FileConfigurationCreatorTests
|
public class FileConfigurationCreatorTests
|
||||||
@ -30,12 +26,6 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
private FileConfiguration _fileConfiguration;
|
private FileConfiguration _fileConfiguration;
|
||||||
private readonly Mock<IOcelotLoggerFactory> _logger;
|
private readonly Mock<IOcelotLoggerFactory> _logger;
|
||||||
private readonly FileOcelotConfigurationCreator _ocelotConfigurationCreator;
|
private readonly FileOcelotConfigurationCreator _ocelotConfigurationCreator;
|
||||||
private readonly Mock<ILoadBalancerFactory> _loadBalancerFactory;
|
|
||||||
private readonly Mock<ILoadBalancerHouse> _loadBalancerHouse;
|
|
||||||
private readonly Mock<ILoadBalancer> _loadBalancer;
|
|
||||||
private readonly Mock<IQoSProviderFactory> _qosProviderFactory;
|
|
||||||
private readonly Mock<IQosProviderHouse> _qosProviderHouse;
|
|
||||||
private readonly Mock<IQoSProvider> _qosProvider;
|
|
||||||
private Mock<IClaimsToThingCreator> _claimsToThingCreator;
|
private Mock<IClaimsToThingCreator> _claimsToThingCreator;
|
||||||
private Mock<IAuthenticationOptionsCreator> _authOptionsCreator;
|
private Mock<IAuthenticationOptionsCreator> _authOptionsCreator;
|
||||||
private Mock<IUpstreamTemplatePatternCreator> _upstreamTemplatePatternCreator;
|
private Mock<IUpstreamTemplatePatternCreator> _upstreamTemplatePatternCreator;
|
||||||
@ -49,15 +39,9 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
|
|
||||||
public FileConfigurationCreatorTests()
|
public FileConfigurationCreatorTests()
|
||||||
{
|
{
|
||||||
_qosProviderFactory = new Mock<IQoSProviderFactory>();
|
|
||||||
_qosProviderHouse = new Mock<IQosProviderHouse>();
|
|
||||||
_qosProvider = new Mock<IQoSProvider>();
|
|
||||||
_logger = new Mock<IOcelotLoggerFactory>();
|
_logger = new Mock<IOcelotLoggerFactory>();
|
||||||
_validator = new Mock<IConfigurationValidator>();
|
_validator = new Mock<IConfigurationValidator>();
|
||||||
_fileConfig = new Mock<IOptions<FileConfiguration>>();
|
_fileConfig = new Mock<IOptions<FileConfiguration>>();
|
||||||
_loadBalancerFactory = new Mock<ILoadBalancerFactory>();
|
|
||||||
_loadBalancerHouse = new Mock<ILoadBalancerHouse>();
|
|
||||||
_loadBalancer = new Mock<ILoadBalancer>();
|
|
||||||
_claimsToThingCreator = new Mock<IClaimsToThingCreator>();
|
_claimsToThingCreator = new Mock<IClaimsToThingCreator>();
|
||||||
_authOptionsCreator = new Mock<IAuthenticationOptionsCreator>();
|
_authOptionsCreator = new Mock<IAuthenticationOptionsCreator>();
|
||||||
_upstreamTemplatePatternCreator = new Mock<IUpstreamTemplatePatternCreator>();
|
_upstreamTemplatePatternCreator = new Mock<IUpstreamTemplatePatternCreator>();
|
||||||
@ -71,13 +55,35 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
|
|
||||||
_ocelotConfigurationCreator = new FileOcelotConfigurationCreator(
|
_ocelotConfigurationCreator = new FileOcelotConfigurationCreator(
|
||||||
_fileConfig.Object, _validator.Object, _logger.Object,
|
_fileConfig.Object, _validator.Object, _logger.Object,
|
||||||
_loadBalancerFactory.Object, _loadBalancerHouse.Object,
|
_claimsToThingCreator.Object,
|
||||||
_qosProviderFactory.Object, _qosProviderHouse.Object, _claimsToThingCreator.Object,
|
|
||||||
_authOptionsCreator.Object, _upstreamTemplatePatternCreator.Object, _requestIdKeyCreator.Object,
|
_authOptionsCreator.Object, _upstreamTemplatePatternCreator.Object, _requestIdKeyCreator.Object,
|
||||||
_serviceProviderConfigCreator.Object, _qosOptionsCreator.Object, _fileReRouteOptionsCreator.Object,
|
_serviceProviderConfigCreator.Object, _qosOptionsCreator.Object, _fileReRouteOptionsCreator.Object,
|
||||||
_rateLimitOptions.Object, _regionCreator.Object, _httpHandlerOptionsCreator.Object);
|
_rateLimitOptions.Object, _regionCreator.Object, _httpHandlerOptionsCreator.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_call_service_provider_config_creator()
|
||||||
|
{
|
||||||
|
var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
|
||||||
|
|
||||||
|
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
|
||||||
|
{
|
||||||
|
GlobalConfiguration = new FileGlobalConfiguration
|
||||||
|
{
|
||||||
|
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
|
||||||
|
{
|
||||||
|
Host = "localhost",
|
||||||
|
Port = 8500,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.And(x => x.GivenTheFollowingIsReturned(serviceProviderConfig))
|
||||||
|
.And(x => x.GivenTheConfigIsValid())
|
||||||
|
.When(x => x.WhenICreateTheConfig())
|
||||||
|
.Then(x => x.ThenTheServiceProviderCreatorIsCalledCorrectly())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_call_region_creator()
|
public void should_call_region_creator()
|
||||||
{
|
{
|
||||||
@ -109,19 +115,6 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
.BDDfy();
|
.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]
|
[Fact]
|
||||||
public void should_call_rate_limit_options_creator()
|
public void should_call_rate_limit_options_creator()
|
||||||
{
|
{
|
||||||
@ -182,43 +175,12 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
}))
|
}))
|
||||||
.And(x => x.GivenTheConfigIsValid())
|
.And(x => x.GivenTheConfigIsValid())
|
||||||
.And(x => x.GivenTheFollowingOptionsAreReturned(serviceOptions))
|
.And(x => x.GivenTheFollowingOptionsAreReturned(serviceOptions))
|
||||||
.And(x => x.GivenTheQosProviderFactoryReturns())
|
|
||||||
.And(x => x.GivenTheQosOptionsCreatorReturns(expected))
|
.And(x => x.GivenTheQosOptionsCreatorReturns(expected))
|
||||||
.When(x => x.WhenICreateTheConfig())
|
.When(x => x.WhenICreateTheConfig())
|
||||||
.Then(x => x.ThenTheQosOptionsAre(expected))
|
.Then(x => x.ThenTheQosOptionsAre(expected))
|
||||||
.And(x => x.TheQosProviderFactoryIsCalledCorrectly())
|
|
||||||
.And(x => x.ThenTheQosProviderHouseIsCalledCorrectly())
|
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
[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]
|
[Fact]
|
||||||
public void should_use_downstream_host()
|
public void should_use_downstream_host()
|
||||||
{
|
{
|
||||||
@ -310,7 +272,6 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
{
|
{
|
||||||
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
|
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
|
||||||
{
|
{
|
||||||
Provider = "consul",
|
|
||||||
Host = "127.0.0.1"
|
Host = "127.0.0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -324,12 +285,8 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
.WithDownstreamPathTemplate("/products/{productId}")
|
.WithDownstreamPathTemplate("/products/{productId}")
|
||||||
.WithUpstreamPathTemplate("/api/products/{productId}")
|
.WithUpstreamPathTemplate("/api/products/{productId}")
|
||||||
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
||||||
.WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder()
|
.WithUseServiceDiscovery(true)
|
||||||
.WithUseServiceDiscovery(true)
|
.WithServiceName("ProductService")
|
||||||
.WithServiceDiscoveryProvider("consul")
|
|
||||||
.WithServiceDiscoveryProviderHost("127.0.0.1")
|
|
||||||
.WithServiceName("ProductService")
|
|
||||||
.Build())
|
|
||||||
.Build()
|
.Build()
|
||||||
}))
|
}))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
@ -363,9 +320,7 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
.WithDownstreamPathTemplate("/products/{productId}")
|
.WithDownstreamPathTemplate("/products/{productId}")
|
||||||
.WithUpstreamPathTemplate("/api/products/{productId}")
|
.WithUpstreamPathTemplate("/api/products/{productId}")
|
||||||
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
||||||
.WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder()
|
.WithUseServiceDiscovery(false)
|
||||||
.WithUseServiceDiscovery(false)
|
|
||||||
.Build())
|
|
||||||
.Build()
|
.Build()
|
||||||
}))
|
}))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
@ -474,17 +429,6 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
.BDDfy();
|
.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]
|
[Theory]
|
||||||
[MemberData(nameof(AuthenticationConfigTestData.GetAuthenticationData), MemberType = typeof(AuthenticationConfigTestData))]
|
[MemberData(nameof(AuthenticationConfigTestData.GetAuthenticationData), MemberType = typeof(AuthenticationConfigTestData))]
|
||||||
public void should_create_with_headers_to_extract(FileConfiguration fileConfig)
|
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.GivenTheAuthOptionsCreatorReturns(authenticationOptions))
|
||||||
.And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
|
.And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
|
||||||
.And(x => x.GivenTheClaimsToThingCreatorReturns(new List<ClaimToThing> { new ClaimToThing("CustomerId", "CustomerId", "", 0) }))
|
.And(x => x.GivenTheClaimsToThingCreatorReturns(new List<ClaimToThing> { new ClaimToThing("CustomerId", "CustomerId", "", 0) }))
|
||||||
.And(x => x.GivenTheLoadBalancerFactoryReturns())
|
|
||||||
.When(x => x.WhenICreateTheConfig())
|
.When(x => x.WhenICreateTheConfig())
|
||||||
.Then(x => x.ThenTheReRoutesAre(expected))
|
.Then(x => x.ThenTheReRoutesAre(expected))
|
||||||
.And(x => x.ThenTheAuthenticationOptionsAre(expected))
|
.And(x => x.ThenTheAuthenticationOptionsAre(expected))
|
||||||
@ -550,7 +493,6 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
.And(x => x.GivenTheConfigIsValid())
|
.And(x => x.GivenTheConfigIsValid())
|
||||||
.And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
|
.And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
|
||||||
.And(x => x.GivenTheAuthOptionsCreatorReturns(authenticationOptions))
|
.And(x => x.GivenTheAuthOptionsCreatorReturns(authenticationOptions))
|
||||||
.And(x => x.GivenTheLoadBalancerFactoryReturns())
|
|
||||||
.When(x => x.WhenICreateTheConfig())
|
.When(x => x.WhenICreateTheConfig())
|
||||||
.Then(x => x.ThenTheReRoutesAre(expected))
|
.Then(x => x.ThenTheReRoutesAre(expected))
|
||||||
.And(x => x.ThenTheAuthenticationOptionsAre(expected))
|
.And(x => x.ThenTheAuthenticationOptionsAre(expected))
|
||||||
@ -558,6 +500,31 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
.BDDfy();
|
.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)
|
private void GivenTheFollowingOptionsAreReturned(ReRouteOptions fileReRouteOptions)
|
||||||
{
|
{
|
||||||
_fileReRouteOptionsCreator
|
_fileReRouteOptionsCreator
|
||||||
@ -588,7 +555,7 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
|
|
||||||
private void WhenICreateTheConfig()
|
private void WhenICreateTheConfig()
|
||||||
{
|
{
|
||||||
_config = _ocelotConfigurationCreator.Create().Result;
|
_config = _ocelotConfigurationCreator.Create(_fileConfiguration).Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenTheReRoutesAre(List<ReRoute> expectedReRoutes)
|
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)
|
private void ThenTheAuthenticationOptionsAre(List<ReRoute> expectedReRoutes)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < _config.Data.ReRoutes.Count; i++)
|
for (int i = 0; i < _config.Data.ReRoutes.Count; i++)
|
||||||
@ -634,44 +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)
|
private void GivenTheClaimsToThingCreatorReturns(List<ClaimToThing> claimsToThing)
|
||||||
{
|
{
|
||||||
_claimsToThingCreator
|
_claimsToThingCreator
|
||||||
@ -726,5 +641,42 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
_config.Data.ReRoutes[0].QosOptionsOptions.ExceptionsAllowedBeforeBreaking.ShouldBe(qosOptions.ExceptionsAllowedBeforeBreaking);
|
_config.Data.ReRoutes[0].QosOptionsOptions.ExceptionsAllowedBeforeBreaking.ShouldBe(qosOptions.ExceptionsAllowedBeforeBreaking);
|
||||||
_config.Data.ReRoutes[0].QosOptionsOptions.TimeoutValue.ShouldBe(qosOptions.TimeoutValue);
|
_config.Data.ReRoutes[0].QosOptionsOptions.TimeoutValue.ShouldBe(qosOptions.TimeoutValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ThenTheServiceProviderCreatorIsCalledCorrectly()
|
||||||
|
{
|
||||||
|
_serviceProviderConfigCreator
|
||||||
|
.Verify(x => x.Create(_fileConfiguration.GlobalConfiguration), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenTheFollowingIsReturned(ServiceProviderConfiguration serviceProviderConfiguration)
|
||||||
|
{
|
||||||
|
_serviceProviderConfigCreator
|
||||||
|
.Setup(x => x.Create(It.IsAny<FileGlobalConfiguration>())).Returns(serviceProviderConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
_fileConfiguration = fileConfiguration;
|
||||||
_repo
|
_repo
|
||||||
.Setup(x => x.Get())
|
.Setup(x => x.Get())
|
||||||
.Returns(new OkResponse<FileConfiguration>(fileConfiguration));
|
.ReturnsAsync(new OkResponse<FileConfiguration>(fileConfiguration));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WhenIGetTheReRoutes()
|
private void WhenIGetTheReRoutes()
|
||||||
{
|
{
|
||||||
_result = _provider.Get().Data;
|
_result = _provider.Get().Result.Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenTheRepoIsCalledCorrectly()
|
private void ThenTheRepoIsCalledCorrectly()
|
||||||
|
@ -1,31 +1,176 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Ocelot.Configuration;
|
|
||||||
using Ocelot.Configuration.File;
|
using Ocelot.Configuration.File;
|
||||||
using Ocelot.Responses;
|
|
||||||
using Shouldly;
|
using Shouldly;
|
||||||
using TestStack.BDDfy;
|
using TestStack.BDDfy;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Ocelot.Configuration.Repository;
|
using Ocelot.Configuration.Repository;
|
||||||
|
|
||||||
namespace Ocelot.UnitTests.Configuration
|
namespace Ocelot.UnitTests.Configuration
|
||||||
{
|
{
|
||||||
public class FileConfigurationRepositoryTests
|
public class FileConfigurationRepositoryTests
|
||||||
{
|
{
|
||||||
private readonly IFileConfigurationRepository _repo;
|
private readonly Mock<IHostingEnvironment> _hostingEnvironment = new Mock<IHostingEnvironment>();
|
||||||
|
private IFileConfigurationRepository _repo;
|
||||||
private FileConfiguration _result;
|
private FileConfiguration _result;
|
||||||
private FileConfiguration _fileConfiguration;
|
private FileConfiguration _fileConfiguration;
|
||||||
|
private string _environmentName = "DEV";
|
||||||
|
|
||||||
public FileConfigurationRepositoryTests()
|
public FileConfigurationRepositoryTests()
|
||||||
{
|
{
|
||||||
_repo = new FileConfigurationRepository();
|
_hostingEnvironment.Setup(he => he.EnvironmentName).Returns(_environmentName);
|
||||||
|
_repo = new FileConfigurationRepository(_hostingEnvironment.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_return_file_configuration()
|
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>
|
var reRoutes = new List<FileReRoute>
|
||||||
{
|
{
|
||||||
@ -43,119 +188,16 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
AdministrationPath = "testy",
|
AdministrationPath = "testy",
|
||||||
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
|
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
|
||||||
{
|
{
|
||||||
Provider = "consul",
|
|
||||||
Port = 198,
|
Port = 198,
|
||||||
Host = "blah"
|
Host = "blah"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var config = new FileConfiguration();
|
return 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>
|
|
||||||
{
|
{
|
||||||
new FileReRoute
|
GlobalConfiguration = globalConfiguration,
|
||||||
{
|
ReRoutes = reRoutes
|
||||||
DownstreamHost = "123.12.12.12",
|
|
||||||
DownstreamPort = 80,
|
|
||||||
DownstreamScheme = "https",
|
|
||||||
DownstreamPathTemplate = "/asdfs/test/{test}"
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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 System.Collections.Generic;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
|
using Ocelot.Configuration.Builder;
|
||||||
using Ocelot.Configuration.Creator;
|
using Ocelot.Configuration.Creator;
|
||||||
using Ocelot.Configuration.File;
|
using Ocelot.Configuration.File;
|
||||||
using Ocelot.Configuration.Repository;
|
using Ocelot.Configuration.Repository;
|
||||||
@ -36,7 +37,8 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
public void should_set_configuration()
|
public void should_set_configuration()
|
||||||
{
|
{
|
||||||
var fileConfig = new FileConfiguration();
|
var fileConfig = new FileConfiguration();
|
||||||
var config = new OcelotConfiguration(new List<ReRoute>(), string.Empty);
|
var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
|
||||||
|
var config = new OcelotConfiguration(new List<ReRoute>(), string.Empty, serviceProviderConfig);
|
||||||
|
|
||||||
this.Given(x => GivenTheFollowingConfiguration(fileConfig))
|
this.Given(x => GivenTheFollowingConfiguration(fileConfig))
|
||||||
.And(x => GivenTheRepoReturns(new OkResponse()))
|
.And(x => GivenTheRepoReturns(new OkResponse()))
|
||||||
@ -76,7 +78,7 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
{
|
{
|
||||||
_repo
|
_repo
|
||||||
.Setup(x => x.Set(It.IsAny<FileConfiguration>()))
|
.Setup(x => x.Set(It.IsAny<FileConfiguration>()))
|
||||||
.Returns(response);
|
.ReturnsAsync(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenAnErrorResponseIsReturned()
|
private void ThenAnErrorResponseIsReturned()
|
||||||
|
@ -92,6 +92,8 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
};
|
};
|
||||||
|
|
||||||
public string AdministrationPath {get;}
|
public string AdministrationPath {get;}
|
||||||
|
|
||||||
|
public ServiceProviderConfiguration ServiceProviderConfiguration => throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
|
using Ocelot.Configuration.Builder;
|
||||||
using Ocelot.Configuration.Creator;
|
using Ocelot.Configuration.Creator;
|
||||||
using Ocelot.Configuration.Provider;
|
using Ocelot.Configuration.Provider;
|
||||||
using Ocelot.Configuration.Repository;
|
using Ocelot.Configuration.Repository;
|
||||||
@ -27,9 +28,11 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void should_get_config()
|
public void should_get_config()
|
||||||
{
|
{
|
||||||
this.Given(x => x.GivenTheRepoReturns(new OkResponse<IOcelotConfiguration>(new OcelotConfiguration(new List<ReRoute>(), string.Empty))))
|
var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
|
||||||
|
|
||||||
|
this.Given(x => x.GivenTheRepoReturns(new OkResponse<IOcelotConfiguration>(new OcelotConfiguration(new List<ReRoute>(), string.Empty, serviceProviderConfig))))
|
||||||
.When(x => x.WhenIGetTheConfig())
|
.When(x => x.WhenIGetTheConfig())
|
||||||
.Then(x => x.TheFollowingIsReturned(new OkResponse<IOcelotConfiguration>(new OcelotConfiguration(new List<ReRoute>(), string.Empty))))
|
.Then(x => x.TheFollowingIsReturned(new OkResponse<IOcelotConfiguration>(new OcelotConfiguration(new List<ReRoute>(), string.Empty, serviceProviderConfig))))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,14 +29,12 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
{
|
{
|
||||||
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
|
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
|
||||||
{
|
{
|
||||||
Provider = "consul",
|
|
||||||
Host = "127.0.0.1",
|
Host = "127.0.0.1",
|
||||||
Port = 1234
|
Port = 1234
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var expected = new ServiceProviderConfigurationBuilder()
|
var expected = new ServiceProviderConfigurationBuilder()
|
||||||
.WithServiceDiscoveryProvider("consul")
|
|
||||||
.WithServiceDiscoveryProviderHost("127.0.0.1")
|
.WithServiceDiscoveryProviderHost("127.0.0.1")
|
||||||
.WithServiceDiscoveryProviderPort(1234)
|
.WithServiceDiscoveryProviderPort(1234)
|
||||||
.Build();
|
.Build();
|
||||||
@ -60,15 +58,11 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
|
|
||||||
private void WhenICreate()
|
private void WhenICreate()
|
||||||
{
|
{
|
||||||
_result = _creator.Create(_reRoute, _globalConfig);
|
_result = _creator.Create(_globalConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenTheConfigIs(ServiceProviderConfiguration expected)
|
private void ThenTheConfigIs(ServiceProviderConfiguration expected)
|
||||||
{
|
{
|
||||||
_result.DownstreamHost.ShouldBe(expected.DownstreamHost);
|
|
||||||
_result.DownstreamPort.ShouldBe(expected.DownstreamPort);
|
|
||||||
_result.ServiceDiscoveryProvider.ShouldBe(expected.ServiceDiscoveryProvider);
|
|
||||||
_result.ServiceName.ShouldBe(expected.ServiceName);
|
|
||||||
_result.ServiceProviderHost.ShouldBe(expected.ServiceProviderHost);
|
_result.ServiceProviderHost.ShouldBe(expected.ServiceProviderHost);
|
||||||
_result.ServiceProviderPort.ShouldBe(expected.ServiceProviderPort);
|
_result.ServiceProviderPort.ShouldBe(expected.ServiceProviderPort);
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,23 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
|
|
||||||
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
|
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
|
||||||
.When(x => x.WhenICreateTheTemplatePattern())
|
.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();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +58,7 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
};
|
};
|
||||||
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
|
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
|
||||||
.When(x => x.WhenICreateTheTemplatePattern())
|
.When(x => x.WhenICreateTheTemplatePattern())
|
||||||
.Then(x => x.ThenTheFollowingIsReturned("^/PRODUCTS/.*/$"))
|
.Then(x => x.ThenTheFollowingIsReturned("^/PRODUCTS/[0-9a-zA-Z].*$"))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +73,7 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
|
|
||||||
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
|
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
|
||||||
.When(x => x.WhenICreateTheTemplatePattern())
|
.When(x => x.WhenICreateTheTemplatePattern())
|
||||||
.Then(x => x.ThenTheFollowingIsReturned("^/api/products/.*/$"))
|
.Then(x => x.ThenTheFollowingIsReturned("^/api/products/[0-9a-zA-Z].*$"))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,9 +88,10 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
|
|
||||||
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
|
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
|
||||||
.When(x => x.WhenICreateTheTemplatePattern())
|
.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();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_create_template_pattern_that_matches_more_than_one_placeholder_with_trailing_slash()
|
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))
|
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
|
||||||
.When(x => x.WhenICreateTheTemplatePattern())
|
.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();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,12 +107,12 @@ namespace Ocelot.UnitTests.Controllers
|
|||||||
{
|
{
|
||||||
_configGetter
|
_configGetter
|
||||||
.Setup(x => x.Get())
|
.Setup(x => x.Get())
|
||||||
.Returns(fileConfiguration);
|
.ReturnsAsync(fileConfiguration);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WhenIGetTheFileConfiguration()
|
private void WhenIGetTheFileConfiguration()
|
||||||
{
|
{
|
||||||
_result = _controller.Get();
|
_result = _controller.Get().Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TheTheGetFileConfigurationIsCalledCorrectly()
|
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.AspNetCore.Builder;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
using Ocelot.Configuration;
|
||||||
using Ocelot.Configuration.Builder;
|
using Ocelot.Configuration.Builder;
|
||||||
|
using Ocelot.Configuration.Provider;
|
||||||
using Ocelot.DownstreamRouteFinder;
|
using Ocelot.DownstreamRouteFinder;
|
||||||
using Ocelot.DownstreamRouteFinder.Finder;
|
using Ocelot.DownstreamRouteFinder.Finder;
|
||||||
using Ocelot.DownstreamRouteFinder.Middleware;
|
using Ocelot.DownstreamRouteFinder.Middleware;
|
||||||
@ -17,10 +19,13 @@
|
|||||||
public class DownstreamRouteFinderMiddlewareTests : ServerHostedMiddlewareTest
|
public class DownstreamRouteFinderMiddlewareTests : ServerHostedMiddlewareTest
|
||||||
{
|
{
|
||||||
private readonly Mock<IDownstreamRouteFinder> _downstreamRouteFinder;
|
private readonly Mock<IDownstreamRouteFinder> _downstreamRouteFinder;
|
||||||
|
private readonly Mock<IOcelotConfigurationProvider> _provider;
|
||||||
private Response<DownstreamRoute> _downstreamRoute;
|
private Response<DownstreamRoute> _downstreamRoute;
|
||||||
|
private IOcelotConfiguration _config;
|
||||||
|
|
||||||
public DownstreamRouteFinderMiddlewareTests()
|
public DownstreamRouteFinderMiddlewareTests()
|
||||||
{
|
{
|
||||||
|
_provider = new Mock<IOcelotConfigurationProvider>();
|
||||||
_downstreamRouteFinder = new Mock<IDownstreamRouteFinder>();
|
_downstreamRouteFinder = new Mock<IDownstreamRouteFinder>();
|
||||||
|
|
||||||
GivenTheTestServerIsConfigured();
|
GivenTheTestServerIsConfigured();
|
||||||
@ -29,6 +34,8 @@
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void should_call_scoped_data_repository_correctly()
|
public void should_call_scoped_data_repository_correctly()
|
||||||
{
|
{
|
||||||
|
var config = new OcelotConfiguration(null, null, new ServiceProviderConfigurationBuilder().Build());
|
||||||
|
|
||||||
this.Given(x => x.GivenTheDownStreamRouteFinderReturns(
|
this.Given(x => x.GivenTheDownStreamRouteFinderReturns(
|
||||||
new DownstreamRoute(
|
new DownstreamRoute(
|
||||||
new List<UrlPathPlaceholderNameAndValue>(),
|
new List<UrlPathPlaceholderNameAndValue>(),
|
||||||
@ -36,16 +43,26 @@
|
|||||||
.WithDownstreamPathTemplate("any old string")
|
.WithDownstreamPathTemplate("any old string")
|
||||||
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
||||||
.Build())))
|
.Build())))
|
||||||
|
.And(x => GivenTheFollowingConfig(config))
|
||||||
.When(x => x.WhenICallTheMiddleware())
|
.When(x => x.WhenICallTheMiddleware())
|
||||||
.Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly())
|
.Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly())
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void GivenTheFollowingConfig(IOcelotConfiguration config)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
_provider
|
||||||
|
.Setup(x => x.Get())
|
||||||
|
.ReturnsAsync(new OkResponse<IOcelotConfiguration>(_config));
|
||||||
|
}
|
||||||
|
|
||||||
protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services)
|
protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
|
services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
|
||||||
services.AddLogging();
|
services.AddLogging();
|
||||||
services.AddSingleton(_downstreamRouteFinder.Object);
|
services.AddSingleton(_downstreamRouteFinder.Object);
|
||||||
|
services.AddSingleton(_provider.Object);
|
||||||
services.AddSingleton(ScopedRepository.Object);
|
services.AddSingleton(ScopedRepository.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,14 +75,17 @@
|
|||||||
{
|
{
|
||||||
_downstreamRoute = new OkResponse<DownstreamRoute>(downstreamRoute);
|
_downstreamRoute = new OkResponse<DownstreamRoute>(downstreamRoute);
|
||||||
_downstreamRouteFinder
|
_downstreamRouteFinder
|
||||||
.Setup(x => x.FindDownstreamRoute(It.IsAny<string>(), It.IsAny<string>()))
|
.Setup(x => x.FindDownstreamRoute(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<IOcelotConfiguration>()))
|
||||||
.ReturnsAsync(_downstreamRoute);
|
.Returns(_downstreamRoute);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenTheScopedDataRepositoryIsCalledCorrectly()
|
private void ThenTheScopedDataRepositoryIsCalledCorrectly()
|
||||||
{
|
{
|
||||||
ScopedRepository
|
ScopedRepository
|
||||||
.Verify(x => x.Add("DownstreamRoute", _downstreamRoute.Data), Times.Once());
|
.Verify(x => x.Add("DownstreamRoute", _downstreamRoute.Data), Times.Once());
|
||||||
|
|
||||||
|
ScopedRepository
|
||||||
|
.Verify(x => x.Add("ServiceProviderConfiguration", _config.ServiceProviderConfiguration), Times.Once());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,26 +16,27 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
|
|||||||
public class DownstreamRouteFinderTests
|
public class DownstreamRouteFinderTests
|
||||||
{
|
{
|
||||||
private readonly IDownstreamRouteFinder _downstreamRouteFinder;
|
private readonly IDownstreamRouteFinder _downstreamRouteFinder;
|
||||||
private readonly Mock<IOcelotConfigurationProvider> _mockConfig;
|
|
||||||
private readonly Mock<IUrlPathToUrlTemplateMatcher> _mockMatcher;
|
private readonly Mock<IUrlPathToUrlTemplateMatcher> _mockMatcher;
|
||||||
private readonly Mock<IUrlPathPlaceholderNameAndValueFinder> _finder;
|
private readonly Mock<IUrlPathPlaceholderNameAndValueFinder> _finder;
|
||||||
private string _upstreamUrlPath;
|
private string _upstreamUrlPath;
|
||||||
private Response<DownstreamRoute> _result;
|
private Response<DownstreamRoute> _result;
|
||||||
private List<ReRoute> _reRoutesConfig;
|
private List<ReRoute> _reRoutesConfig;
|
||||||
|
private OcelotConfiguration _config;
|
||||||
private Response<UrlMatch> _match;
|
private Response<UrlMatch> _match;
|
||||||
private string _upstreamHttpMethod;
|
private string _upstreamHttpMethod;
|
||||||
|
|
||||||
public DownstreamRouteFinderTests()
|
public DownstreamRouteFinderTests()
|
||||||
{
|
{
|
||||||
_mockConfig = new Mock<IOcelotConfigurationProvider>();
|
|
||||||
_mockMatcher = new Mock<IUrlPathToUrlTemplateMatcher>();
|
_mockMatcher = new Mock<IUrlPathToUrlTemplateMatcher>();
|
||||||
_finder = new Mock<IUrlPathPlaceholderNameAndValueFinder>();
|
_finder = new Mock<IUrlPathPlaceholderNameAndValueFinder>();
|
||||||
_downstreamRouteFinder = new Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteFinder(_mockConfig.Object, _mockMatcher.Object, _finder.Object);
|
_downstreamRouteFinder = new Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteFinder(_mockMatcher.Object, _finder.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_return_route()
|
public void should_return_route()
|
||||||
{
|
{
|
||||||
|
var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
|
||||||
|
|
||||||
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher/"))
|
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher/"))
|
||||||
.And(x =>x.GivenTheTemplateVariableAndNameFinderReturns(
|
.And(x =>x.GivenTheTemplateVariableAndNameFinderReturns(
|
||||||
new OkResponse<List<UrlPathPlaceholderNameAndValue>>(
|
new OkResponse<List<UrlPathPlaceholderNameAndValue>>(
|
||||||
@ -48,7 +49,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
|
|||||||
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
||||||
.WithUpstreamTemplatePattern("someUpstreamPath")
|
.WithUpstreamTemplatePattern("someUpstreamPath")
|
||||||
.Build()
|
.Build()
|
||||||
}, string.Empty
|
}, string.Empty, serviceProviderConfig
|
||||||
))
|
))
|
||||||
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
|
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
|
||||||
.And(x => x.GivenTheUpstreamHttpMethodIs("Get"))
|
.And(x => x.GivenTheUpstreamHttpMethodIs("Get"))
|
||||||
@ -67,8 +68,10 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
|
|||||||
|
|
||||||
|
|
||||||
[Fact]
|
[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"))
|
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher"))
|
||||||
.And(x =>x.GivenTheTemplateVariableAndNameFinderReturns(
|
.And(x =>x.GivenTheTemplateVariableAndNameFinderReturns(
|
||||||
new OkResponse<List<UrlPathPlaceholderNameAndValue>>(
|
new OkResponse<List<UrlPathPlaceholderNameAndValue>>(
|
||||||
@ -81,7 +84,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
|
|||||||
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
||||||
.WithUpstreamTemplatePattern("someUpstreamPath")
|
.WithUpstreamTemplatePattern("someUpstreamPath")
|
||||||
.Build()
|
.Build()
|
||||||
}, string.Empty
|
}, string.Empty, serviceProviderConfig
|
||||||
))
|
))
|
||||||
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
|
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
|
||||||
.And(x => x.GivenTheUpstreamHttpMethodIs("Get"))
|
.And(x => x.GivenTheUpstreamHttpMethodIs("Get"))
|
||||||
@ -94,13 +97,15 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
|
|||||||
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
||||||
.Build()
|
.Build()
|
||||||
)))
|
)))
|
||||||
.And(x => x.ThenTheUrlMatcherIsCalledCorrectly("matchInUrlMatcher/"))
|
.And(x => x.ThenTheUrlMatcherIsCalledCorrectly("matchInUrlMatcher"))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_return_route_if_upstream_path_and_upstream_template_are_the_same()
|
public void should_return_route_if_upstream_path_and_upstream_template_are_the_same()
|
||||||
{
|
{
|
||||||
|
var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
|
||||||
|
|
||||||
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath"))
|
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath"))
|
||||||
.And(
|
.And(
|
||||||
x =>
|
x =>
|
||||||
@ -114,7 +119,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
|
|||||||
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
||||||
.WithUpstreamTemplatePattern("someUpstreamPath")
|
.WithUpstreamTemplatePattern("someUpstreamPath")
|
||||||
.Build()
|
.Build()
|
||||||
}, string.Empty
|
}, string.Empty, serviceProviderConfig
|
||||||
))
|
))
|
||||||
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
|
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
|
||||||
.And(x => x.GivenTheUpstreamHttpMethodIs("Get"))
|
.And(x => x.GivenTheUpstreamHttpMethodIs("Get"))
|
||||||
@ -133,6 +138,8 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void should_return_correct_route_for_http_verb()
|
public void should_return_correct_route_for_http_verb()
|
||||||
{
|
{
|
||||||
|
var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
|
||||||
|
|
||||||
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath"))
|
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath"))
|
||||||
.And(
|
.And(
|
||||||
x =>
|
x =>
|
||||||
@ -152,7 +159,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
|
|||||||
.WithUpstreamHttpMethod(new List<string> { "Post" })
|
.WithUpstreamHttpMethod(new List<string> { "Post" })
|
||||||
.WithUpstreamTemplatePattern("")
|
.WithUpstreamTemplatePattern("")
|
||||||
.Build()
|
.Build()
|
||||||
}, string.Empty
|
}, string.Empty, serviceProviderConfig
|
||||||
))
|
))
|
||||||
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
|
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
|
||||||
.And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
|
.And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
|
||||||
@ -170,6 +177,8 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void should_not_return_route()
|
public void should_not_return_route()
|
||||||
{
|
{
|
||||||
|
var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
|
||||||
|
|
||||||
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("dontMatchPath/"))
|
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("dontMatchPath/"))
|
||||||
.And(x => x.GivenTheConfigurationIs(new List<ReRoute>
|
.And(x => x.GivenTheConfigurationIs(new List<ReRoute>
|
||||||
{
|
{
|
||||||
@ -179,7 +188,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
|
|||||||
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
||||||
.WithUpstreamTemplatePattern("somePath")
|
.WithUpstreamTemplatePattern("somePath")
|
||||||
.Build(),
|
.Build(),
|
||||||
}, string.Empty
|
}, string.Empty, serviceProviderConfig
|
||||||
))
|
))
|
||||||
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(false))))
|
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(false))))
|
||||||
.And(x => x.GivenTheUpstreamHttpMethodIs("Get"))
|
.And(x => x.GivenTheUpstreamHttpMethodIs("Get"))
|
||||||
@ -193,6 +202,8 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void should_return_correct_route_for_http_verb_setting_multiple_upstream_http_method()
|
public void should_return_correct_route_for_http_verb_setting_multiple_upstream_http_method()
|
||||||
{
|
{
|
||||||
|
var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
|
||||||
|
|
||||||
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath"))
|
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath"))
|
||||||
.And(
|
.And(
|
||||||
x =>
|
x =>
|
||||||
@ -206,7 +217,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
|
|||||||
.WithUpstreamHttpMethod(new List<string> { "Get", "Post" })
|
.WithUpstreamHttpMethod(new List<string> { "Get", "Post" })
|
||||||
.WithUpstreamTemplatePattern("")
|
.WithUpstreamTemplatePattern("")
|
||||||
.Build()
|
.Build()
|
||||||
}, string.Empty
|
}, string.Empty, serviceProviderConfig
|
||||||
))
|
))
|
||||||
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
|
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
|
||||||
.And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
|
.And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
|
||||||
@ -224,6 +235,8 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void should_return_correct_route_for_http_verb_setting_all_upstream_http_method()
|
public void should_return_correct_route_for_http_verb_setting_all_upstream_http_method()
|
||||||
{
|
{
|
||||||
|
var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
|
||||||
|
|
||||||
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath"))
|
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath"))
|
||||||
.And(
|
.And(
|
||||||
x =>
|
x =>
|
||||||
@ -237,7 +250,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
|
|||||||
.WithUpstreamHttpMethod(new List<string>())
|
.WithUpstreamHttpMethod(new List<string>())
|
||||||
.WithUpstreamTemplatePattern("")
|
.WithUpstreamTemplatePattern("")
|
||||||
.Build()
|
.Build()
|
||||||
}, string.Empty
|
}, string.Empty, serviceProviderConfig
|
||||||
))
|
))
|
||||||
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
|
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
|
||||||
.And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
|
.And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
|
||||||
@ -255,6 +268,8 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void should_not_return_route_for_http_verb_not_setting_in_upstream_http_method()
|
public void should_not_return_route_for_http_verb_not_setting_in_upstream_http_method()
|
||||||
{
|
{
|
||||||
|
var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
|
||||||
|
|
||||||
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath"))
|
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath"))
|
||||||
.And(
|
.And(
|
||||||
x =>
|
x =>
|
||||||
@ -268,7 +283,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
|
|||||||
.WithUpstreamHttpMethod(new List<string> { "Get", "Patch", "Delete" })
|
.WithUpstreamHttpMethod(new List<string> { "Get", "Patch", "Delete" })
|
||||||
.WithUpstreamTemplatePattern("")
|
.WithUpstreamTemplatePattern("")
|
||||||
.Build()
|
.Build()
|
||||||
}, string.Empty
|
}, string.Empty, serviceProviderConfig
|
||||||
))
|
))
|
||||||
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
|
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
|
||||||
.And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
|
.And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
|
||||||
@ -322,12 +337,10 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
|
|||||||
.Returns(_match);
|
.Returns(_match);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenTheConfigurationIs(List<ReRoute> reRoutesConfig, string adminPath)
|
private void GivenTheConfigurationIs(List<ReRoute> reRoutesConfig, string adminPath, ServiceProviderConfiguration serviceProviderConfig)
|
||||||
{
|
{
|
||||||
_reRoutesConfig = reRoutesConfig;
|
_reRoutesConfig = reRoutesConfig;
|
||||||
_mockConfig
|
_config = new OcelotConfiguration(_reRoutesConfig, adminPath, serviceProviderConfig);
|
||||||
.Setup(x => x.Get())
|
|
||||||
.ReturnsAsync(new OkResponse<IOcelotConfiguration>(new OcelotConfiguration(_reRoutesConfig, adminPath)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenThereIsAnUpstreamUrlPath(string upstreamUrlPath)
|
private void GivenThereIsAnUpstreamUrlPath(string upstreamUrlPath)
|
||||||
@ -337,7 +350,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
|
|||||||
|
|
||||||
private void WhenICallTheFinder()
|
private void WhenICallTheFinder()
|
||||||
{
|
{
|
||||||
_result = _downstreamRouteFinder.FindDownstreamRoute(_upstreamUrlPath, _upstreamHttpMethod).Result;
|
_result = _downstreamRouteFinder.FindDownstreamRoute(_upstreamUrlPath, _upstreamHttpMethod, _config);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenTheFollowingIsReturned(DownstreamRoute expected)
|
private void ThenTheFollowingIsReturned(DownstreamRoute expected)
|
||||||
|
@ -30,6 +30,16 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
|
|||||||
.BDDfy();
|
.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]
|
[Fact]
|
||||||
public void can_match_down_stream_url_with_no_slash()
|
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 HostAndPort _hostAndPort;
|
||||||
private Response<HostAndPort> _result;
|
private Response<HostAndPort> _result;
|
||||||
private LeastConnectionLoadBalancer _leastConnection;
|
private LeastConnection _leastConnection;
|
||||||
private List<Service> _services;
|
private List<Service> _services;
|
||||||
private Random _random;
|
private Random _random;
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ namespace Ocelot.UnitTests.LoadBalancer
|
|||||||
};
|
};
|
||||||
|
|
||||||
_services = availableServices;
|
_services = availableServices;
|
||||||
_leastConnection = new LeastConnectionLoadBalancer(() => Task.FromResult(_services), serviceName);
|
_leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName);
|
||||||
|
|
||||||
var tasks = new Task[100];
|
var tasks = new Task[100];
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ namespace Ocelot.UnitTests.LoadBalancer
|
|||||||
};
|
};
|
||||||
|
|
||||||
_services = availableServices;
|
_services = availableServices;
|
||||||
_leastConnection = new LeastConnectionLoadBalancer(() => Task.FromResult(_services), serviceName);
|
_leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName);
|
||||||
|
|
||||||
var response = _leastConnection.Lease().Result;
|
var response = _leastConnection.Lease().Result;
|
||||||
|
|
||||||
@ -113,7 +113,7 @@ namespace Ocelot.UnitTests.LoadBalancer
|
|||||||
};
|
};
|
||||||
|
|
||||||
_services = availableServices;
|
_services = availableServices;
|
||||||
_leastConnection = new LeastConnectionLoadBalancer(() => Task.FromResult(_services), serviceName);
|
_leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName);
|
||||||
|
|
||||||
var response = _leastConnection.Lease().Result;
|
var response = _leastConnection.Lease().Result;
|
||||||
|
|
||||||
@ -144,7 +144,7 @@ namespace Ocelot.UnitTests.LoadBalancer
|
|||||||
};
|
};
|
||||||
|
|
||||||
_services = availableServices;
|
_services = availableServices;
|
||||||
_leastConnection = new LeastConnectionLoadBalancer(() => Task.FromResult(_services), serviceName);
|
_leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName);
|
||||||
|
|
||||||
var response = _leastConnection.Lease().Result;
|
var response = _leastConnection.Lease().Result;
|
||||||
|
|
||||||
@ -211,7 +211,7 @@ namespace Ocelot.UnitTests.LoadBalancer
|
|||||||
private void GivenTheLoadBalancerStarts(List<Service> services, string serviceName)
|
private void GivenTheLoadBalancerStarts(List<Service> services, string serviceName)
|
||||||
{
|
{
|
||||||
_services = services;
|
_services = services;
|
||||||
_leastConnection = new LeastConnectionLoadBalancer(() => Task.FromResult(_services), serviceName);
|
_leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WhenTheLoadBalancerStarts(List<Service> services, string serviceName)
|
private void WhenTheLoadBalancerStarts(List<Service> services, string serviceName)
|
||||||
|
@ -17,6 +17,7 @@ namespace Ocelot.UnitTests.LoadBalancer
|
|||||||
private ILoadBalancer _result;
|
private ILoadBalancer _result;
|
||||||
private Mock<IServiceDiscoveryProviderFactory> _serviceProviderFactory;
|
private Mock<IServiceDiscoveryProviderFactory> _serviceProviderFactory;
|
||||||
private Mock<IServiceDiscoveryProvider> _serviceProvider;
|
private Mock<IServiceDiscoveryProvider> _serviceProvider;
|
||||||
|
private ServiceProviderConfiguration _serviceProviderConfig;
|
||||||
|
|
||||||
public LoadBalancerFactoryTests()
|
public LoadBalancerFactoryTests()
|
||||||
{
|
{
|
||||||
@ -29,11 +30,11 @@ namespace Ocelot.UnitTests.LoadBalancer
|
|||||||
public void should_return_no_load_balancer()
|
public void should_return_no_load_balancer()
|
||||||
{
|
{
|
||||||
var reRoute = new ReRouteBuilder()
|
var reRoute = new ReRouteBuilder()
|
||||||
.WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder().Build())
|
|
||||||
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
this.Given(x => x.GivenAReRoute(reRoute))
|
this.Given(x => x.GivenAReRoute(reRoute))
|
||||||
|
.And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build()))
|
||||||
.And(x => x.GivenTheServiceProviderFactoryReturns())
|
.And(x => x.GivenTheServiceProviderFactoryReturns())
|
||||||
.When(x => x.WhenIGetTheLoadBalancer())
|
.When(x => x.WhenIGetTheLoadBalancer())
|
||||||
.Then(x => x.ThenTheLoadBalancerIsReturned<NoLoadBalancer>())
|
.Then(x => x.ThenTheLoadBalancerIsReturned<NoLoadBalancer>())
|
||||||
@ -46,13 +47,13 @@ namespace Ocelot.UnitTests.LoadBalancer
|
|||||||
var reRoute = new ReRouteBuilder()
|
var reRoute = new ReRouteBuilder()
|
||||||
.WithLoadBalancer("RoundRobin")
|
.WithLoadBalancer("RoundRobin")
|
||||||
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
||||||
.WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder().Build())
|
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
this.Given(x => x.GivenAReRoute(reRoute))
|
this.Given(x => x.GivenAReRoute(reRoute))
|
||||||
|
.And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build()))
|
||||||
.And(x => x.GivenTheServiceProviderFactoryReturns())
|
.And(x => x.GivenTheServiceProviderFactoryReturns())
|
||||||
.When(x => x.WhenIGetTheLoadBalancer())
|
.When(x => x.WhenIGetTheLoadBalancer())
|
||||||
.Then(x => x.ThenTheLoadBalancerIsReturned<RoundRobinLoadBalancer>())
|
.Then(x => x.ThenTheLoadBalancerIsReturned<RoundRobin>())
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,13 +63,13 @@ namespace Ocelot.UnitTests.LoadBalancer
|
|||||||
var reRoute = new ReRouteBuilder()
|
var reRoute = new ReRouteBuilder()
|
||||||
.WithLoadBalancer("LeastConnection")
|
.WithLoadBalancer("LeastConnection")
|
||||||
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
||||||
.WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder().Build())
|
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
this.Given(x => x.GivenAReRoute(reRoute))
|
this.Given(x => x.GivenAReRoute(reRoute))
|
||||||
|
.And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build()))
|
||||||
.And(x => x.GivenTheServiceProviderFactoryReturns())
|
.And(x => x.GivenTheServiceProviderFactoryReturns())
|
||||||
.When(x => x.WhenIGetTheLoadBalancer())
|
.When(x => x.WhenIGetTheLoadBalancer())
|
||||||
.Then(x => x.ThenTheLoadBalancerIsReturned<LeastConnectionLoadBalancer>())
|
.Then(x => x.ThenTheLoadBalancerIsReturned<LeastConnection>())
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,27 +79,32 @@ namespace Ocelot.UnitTests.LoadBalancer
|
|||||||
var reRoute = new ReRouteBuilder()
|
var reRoute = new ReRouteBuilder()
|
||||||
.WithLoadBalancer("RoundRobin")
|
.WithLoadBalancer("RoundRobin")
|
||||||
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
||||||
.WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder().Build())
|
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
this.Given(x => x.GivenAReRoute(reRoute))
|
this.Given(x => x.GivenAReRoute(reRoute))
|
||||||
|
.And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build()))
|
||||||
.And(x => x.GivenTheServiceProviderFactoryReturns())
|
.And(x => x.GivenTheServiceProviderFactoryReturns())
|
||||||
.When(x => x.WhenIGetTheLoadBalancer())
|
.When(x => x.WhenIGetTheLoadBalancer())
|
||||||
.Then(x => x.ThenTheServiceProviderIsCalledCorrectly())
|
.Then(x => x.ThenTheServiceProviderIsCalledCorrectly())
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void GivenAServiceProviderConfig(ServiceProviderConfiguration serviceProviderConfig)
|
||||||
|
{
|
||||||
|
_serviceProviderConfig = serviceProviderConfig;
|
||||||
|
}
|
||||||
|
|
||||||
private void GivenTheServiceProviderFactoryReturns()
|
private void GivenTheServiceProviderFactoryReturns()
|
||||||
{
|
{
|
||||||
_serviceProviderFactory
|
_serviceProviderFactory
|
||||||
.Setup(x => x.Get(It.IsAny<ServiceProviderConfiguration>()))
|
.Setup(x => x.Get(It.IsAny<ServiceProviderConfiguration>(), It.IsAny<ReRoute>()))
|
||||||
.Returns(_serviceProvider.Object);
|
.Returns(_serviceProvider.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenTheServiceProviderIsCalledCorrectly()
|
private void ThenTheServiceProviderIsCalledCorrectly()
|
||||||
{
|
{
|
||||||
_serviceProviderFactory
|
_serviceProviderFactory
|
||||||
.Verify(x => x.Get(It.IsAny<ServiceProviderConfiguration>()), Times.Once);
|
.Verify(x => x.Get(It.IsAny<ServiceProviderConfiguration>(), It.IsAny<ReRoute>()), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenAReRoute(ReRoute reRoute)
|
private void GivenAReRoute(ReRoute reRoute)
|
||||||
@ -108,7 +114,7 @@ namespace Ocelot.UnitTests.LoadBalancer
|
|||||||
|
|
||||||
private void WhenIGetTheLoadBalancer()
|
private void WhenIGetTheLoadBalancer()
|
||||||
{
|
{
|
||||||
_result = _factory.Get(_reRoute).Result;
|
_result = _factory.Get(_reRoute, _serviceProviderConfig).Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenTheLoadBalancerIsReturned<T>()
|
private void ThenTheLoadBalancerIsReturned<T>()
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Moq;
|
||||||
|
using Ocelot.Configuration;
|
||||||
|
using Ocelot.Configuration.Builder;
|
||||||
using Ocelot.LoadBalancer.LoadBalancers;
|
using Ocelot.LoadBalancer.LoadBalancers;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
using Ocelot.Values;
|
using Ocelot.Values;
|
||||||
@ -11,35 +14,38 @@ namespace Ocelot.UnitTests.LoadBalancer
|
|||||||
{
|
{
|
||||||
public class LoadBalancerHouseTests
|
public class LoadBalancerHouseTests
|
||||||
{
|
{
|
||||||
|
private ReRoute _reRoute;
|
||||||
private ILoadBalancer _loadBalancer;
|
private ILoadBalancer _loadBalancer;
|
||||||
private readonly LoadBalancerHouse _loadBalancerHouse;
|
private readonly LoadBalancerHouse _loadBalancerHouse;
|
||||||
private Response _addResult;
|
private Response _addResult;
|
||||||
private Response<ILoadBalancer> _getResult;
|
private Response<ILoadBalancer> _getResult;
|
||||||
private string _key;
|
private string _key;
|
||||||
|
private Mock<ILoadBalancerFactory> _factory;
|
||||||
|
private ServiceProviderConfiguration _serviceProviderConfig;
|
||||||
|
|
||||||
public LoadBalancerHouseTests()
|
public LoadBalancerHouseTests()
|
||||||
{
|
{
|
||||||
_loadBalancerHouse = new LoadBalancerHouse();
|
_factory = new Mock<ILoadBalancerFactory>();
|
||||||
|
_loadBalancerHouse = new LoadBalancerHouse(_factory.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_store_load_balancer()
|
public void should_store_load_balancer_on_first_request()
|
||||||
{
|
{
|
||||||
var key = "test";
|
var reRoute = new ReRouteBuilder().WithReRouteKey("test").Build();
|
||||||
|
|
||||||
this.Given(x => x.GivenThereIsALoadBalancer(key, new FakeLoadBalancer()))
|
this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
|
||||||
.When(x => x.WhenIAddTheLoadBalancer())
|
|
||||||
.Then(x => x.ThenItIsAdded())
|
.Then(x => x.ThenItIsAdded())
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_get_load_balancer()
|
public void should_not_store_load_balancer_on_second_request()
|
||||||
{
|
{
|
||||||
var key = "test";
|
var reRoute = new ReRouteBuilder().WithLoadBalancer("FakeLoadBalancer").WithReRouteKey("test").Build();
|
||||||
|
|
||||||
this.Given(x => x.GivenThereIsALoadBalancer(key, new FakeLoadBalancer()))
|
this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
|
||||||
.When(x => x.WhenWeGetTheLoadBalancer(key))
|
.When(x => x.WhenWeGetTheLoadBalancer(reRoute))
|
||||||
.Then(x => x.ThenItIsReturned())
|
.Then(x => x.ThenItIsReturned())
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
@ -47,26 +53,50 @@ namespace Ocelot.UnitTests.LoadBalancer
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void should_store_load_balancers_by_key()
|
public void should_store_load_balancers_by_key()
|
||||||
{
|
{
|
||||||
var key = "test";
|
var reRoute = new ReRouteBuilder().WithReRouteKey("test").Build();
|
||||||
var keyTwo = "testTwo";
|
var reRouteTwo = new ReRouteBuilder().WithReRouteKey("testtwo").Build();
|
||||||
|
|
||||||
this.Given(x => x.GivenThereIsALoadBalancer(key, new FakeLoadBalancer()))
|
this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
|
||||||
.And(x => x.GivenThereIsALoadBalancer(keyTwo, new FakeRoundRobinLoadBalancer()))
|
.And(x => x.GivenThereIsALoadBalancer(reRouteTwo, new FakeRoundRobinLoadBalancer()))
|
||||||
.When(x => x.WhenWeGetTheLoadBalancer(key))
|
.When(x => x.WhenWeGetTheLoadBalancer(reRoute))
|
||||||
.Then(x => x.ThenTheLoadBalancerIs<FakeLoadBalancer>())
|
.Then(x => x.ThenTheLoadBalancerIs<FakeLoadBalancer>())
|
||||||
.When(x => x.WhenWeGetTheLoadBalancer(keyTwo))
|
.When(x => x.WhenWeGetTheLoadBalancer(reRouteTwo))
|
||||||
.Then(x => x.ThenTheLoadBalancerIs<FakeRoundRobinLoadBalancer>())
|
.Then(x => x.ThenTheLoadBalancerIs<FakeRoundRobinLoadBalancer>())
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_return_error_if_no_load_balancer_with_key()
|
public void should_return_error_if_exception()
|
||||||
{
|
{
|
||||||
this.When(x => x.WhenWeGetTheLoadBalancer("test"))
|
var reRoute = new ReRouteBuilder().Build();
|
||||||
|
|
||||||
|
this.When(x => x.WhenWeGetTheLoadBalancer(reRoute))
|
||||||
.Then(x => x.ThenAnErrorIsReturned())
|
.Then(x => x.ThenAnErrorIsReturned())
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_get_new_load_balancer_if_reroute_load_balancer_has_changed()
|
||||||
|
{
|
||||||
|
var reRoute = new ReRouteBuilder().WithLoadBalancer("FakeLoadBalancer").WithReRouteKey("test").Build();
|
||||||
|
|
||||||
|
var reRouteTwo = new ReRouteBuilder().WithLoadBalancer("LeastConnection").WithReRouteKey("test").Build();
|
||||||
|
|
||||||
|
this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
|
||||||
|
.When(x => x.WhenWeGetTheLoadBalancer(reRoute))
|
||||||
|
.Then(x => x.ThenTheLoadBalancerIs<FakeLoadBalancer>())
|
||||||
|
.When(x => x.WhenIGetTheReRouteWithTheSameKeyButDifferentLoadBalancer(reRouteTwo))
|
||||||
|
.Then(x => x.ThenTheLoadBalancerIs<LeastConnection>())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WhenIGetTheReRouteWithTheSameKeyButDifferentLoadBalancer(ReRoute reRoute)
|
||||||
|
{
|
||||||
|
_reRoute = reRoute;
|
||||||
|
_factory.Setup(x => x.Get(_reRoute, _serviceProviderConfig)).ReturnsAsync(new LeastConnection(null, null));
|
||||||
|
_getResult = _loadBalancerHouse.Get(_reRoute, _serviceProviderConfig).Result;
|
||||||
|
}
|
||||||
|
|
||||||
private void ThenAnErrorIsReturned()
|
private void ThenAnErrorIsReturned()
|
||||||
{
|
{
|
||||||
_getResult.IsError.ShouldBeTrue();
|
_getResult.IsError.ShouldBeTrue();
|
||||||
@ -80,31 +110,30 @@ namespace Ocelot.UnitTests.LoadBalancer
|
|||||||
|
|
||||||
private void ThenItIsAdded()
|
private void ThenItIsAdded()
|
||||||
{
|
{
|
||||||
_addResult.IsError.ShouldBe(false);
|
_getResult.IsError.ShouldBe(false);
|
||||||
_addResult.ShouldBeOfType<OkResponse>();
|
_getResult.ShouldBeOfType<OkResponse<ILoadBalancer>>();
|
||||||
}
|
_getResult.Data.ShouldBe(_loadBalancer);
|
||||||
|
_factory.Verify(x => x.Get(_reRoute, _serviceProviderConfig), Times.Once);
|
||||||
private void WhenIAddTheLoadBalancer()
|
|
||||||
{
|
|
||||||
_addResult = _loadBalancerHouse.Add(_key, _loadBalancer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void GivenThereIsALoadBalancer(string key, ILoadBalancer loadBalancer)
|
private void GivenThereIsALoadBalancer(ReRoute reRoute, ILoadBalancer loadBalancer)
|
||||||
{
|
{
|
||||||
_key = key;
|
_reRoute = reRoute;
|
||||||
_loadBalancer = loadBalancer;
|
_loadBalancer = loadBalancer;
|
||||||
WhenIAddTheLoadBalancer();
|
_factory.Setup(x => x.Get(_reRoute, _serviceProviderConfig)).ReturnsAsync(loadBalancer);
|
||||||
|
_getResult = _loadBalancerHouse.Get(reRoute, _serviceProviderConfig).Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WhenWeGetTheLoadBalancer(string key)
|
private void WhenWeGetTheLoadBalancer(ReRoute reRoute)
|
||||||
{
|
{
|
||||||
_getResult = _loadBalancerHouse.Get(key);
|
_getResult = _loadBalancerHouse.Get(reRoute, _serviceProviderConfig).Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenItIsReturned()
|
private void ThenItIsReturned()
|
||||||
{
|
{
|
||||||
_getResult.Data.ShouldBe(_loadBalancer);
|
_getResult.Data.ShouldBe(_loadBalancer);
|
||||||
|
_factory.Verify(x => x.Get(_reRoute, _serviceProviderConfig), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
class FakeLoadBalancer : ILoadBalancer
|
class FakeLoadBalancer : ILoadBalancer
|
||||||
|
@ -5,7 +5,9 @@ namespace Ocelot.UnitTests.LoadBalancer
|
|||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
using Ocelot.Configuration;
|
||||||
using Ocelot.Configuration.Builder;
|
using Ocelot.Configuration.Builder;
|
||||||
|
using Ocelot.Configuration.Provider;
|
||||||
using Ocelot.DownstreamRouteFinder;
|
using Ocelot.DownstreamRouteFinder;
|
||||||
using Ocelot.Errors;
|
using Ocelot.Errors;
|
||||||
using Ocelot.LoadBalancer.LoadBalancers;
|
using Ocelot.LoadBalancer.LoadBalancers;
|
||||||
@ -26,13 +28,13 @@ namespace Ocelot.UnitTests.LoadBalancer
|
|||||||
private ErrorResponse<ILoadBalancer> _getLoadBalancerHouseError;
|
private ErrorResponse<ILoadBalancer> _getLoadBalancerHouseError;
|
||||||
private ErrorResponse<HostAndPort> _getHostAndPortError;
|
private ErrorResponse<HostAndPort> _getHostAndPortError;
|
||||||
private HttpRequestMessage _downstreamRequest;
|
private HttpRequestMessage _downstreamRequest;
|
||||||
|
private ServiceProviderConfiguration _config;
|
||||||
|
|
||||||
public LoadBalancerMiddlewareTests()
|
public LoadBalancerMiddlewareTests()
|
||||||
{
|
{
|
||||||
_loadBalancerHouse = new Mock<ILoadBalancerHouse>();
|
_loadBalancerHouse = new Mock<ILoadBalancerHouse>();
|
||||||
_loadBalancer = new Mock<ILoadBalancer>();
|
_loadBalancer = new Mock<ILoadBalancer>();
|
||||||
_loadBalancerHouse = new Mock<ILoadBalancerHouse>();
|
_loadBalancerHouse = new Mock<ILoadBalancerHouse>();
|
||||||
|
|
||||||
_downstreamRequest = new HttpRequestMessage(HttpMethod.Get, "");
|
_downstreamRequest = new HttpRequestMessage(HttpMethod.Get, "");
|
||||||
|
|
||||||
ScopedRepository
|
ScopedRepository
|
||||||
@ -50,7 +52,11 @@ namespace Ocelot.UnitTests.LoadBalancer
|
|||||||
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
||||||
.Build());
|
.Build());
|
||||||
|
|
||||||
|
var serviceProviderConfig = new ServiceProviderConfigurationBuilder()
|
||||||
|
.Build();
|
||||||
|
|
||||||
this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123"))
|
this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123"))
|
||||||
|
.And(x => GivenTheConfigurationIs(serviceProviderConfig))
|
||||||
.And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
|
.And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
|
||||||
.And(x => x.GivenTheLoadBalancerHouseReturns())
|
.And(x => x.GivenTheLoadBalancerHouseReturns())
|
||||||
.And(x => x.GivenTheLoadBalancerReturns())
|
.And(x => x.GivenTheLoadBalancerReturns())
|
||||||
@ -67,7 +73,11 @@ namespace Ocelot.UnitTests.LoadBalancer
|
|||||||
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
||||||
.Build());
|
.Build());
|
||||||
|
|
||||||
|
var serviceProviderConfig = new ServiceProviderConfigurationBuilder()
|
||||||
|
.Build();
|
||||||
|
|
||||||
this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123"))
|
this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123"))
|
||||||
|
.And(x => GivenTheConfigurationIs(serviceProviderConfig))
|
||||||
.And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
|
.And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
|
||||||
.And(x => x.GivenTheLoadBalancerHouseReturnsAnError())
|
.And(x => x.GivenTheLoadBalancerHouseReturnsAnError())
|
||||||
.When(x => x.WhenICallTheMiddleware())
|
.When(x => x.WhenICallTheMiddleware())
|
||||||
@ -83,7 +93,11 @@ namespace Ocelot.UnitTests.LoadBalancer
|
|||||||
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
||||||
.Build());
|
.Build());
|
||||||
|
|
||||||
|
var serviceProviderConfig = new ServiceProviderConfigurationBuilder()
|
||||||
|
.Build();
|
||||||
|
|
||||||
this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123"))
|
this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123"))
|
||||||
|
.And(x => GivenTheConfigurationIs(serviceProviderConfig))
|
||||||
.And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
|
.And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
|
||||||
.And(x => x.GivenTheLoadBalancerHouseReturns())
|
.And(x => x.GivenTheLoadBalancerHouseReturns())
|
||||||
.And(x => x.GivenTheLoadBalancerReturnsAnError())
|
.And(x => x.GivenTheLoadBalancerReturnsAnError())
|
||||||
@ -92,6 +106,13 @@ namespace Ocelot.UnitTests.LoadBalancer
|
|||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void GivenTheConfigurationIs(ServiceProviderConfiguration config)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
ScopedRepository
|
||||||
|
.Setup(x => x.Get<ServiceProviderConfiguration>("ServiceProviderConfiguration")).Returns(new OkResponse<ServiceProviderConfiguration>(config));
|
||||||
|
}
|
||||||
|
|
||||||
protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services)
|
protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
|
services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
|
||||||
@ -137,8 +158,8 @@ namespace Ocelot.UnitTests.LoadBalancer
|
|||||||
private void GivenTheLoadBalancerHouseReturns()
|
private void GivenTheLoadBalancerHouseReturns()
|
||||||
{
|
{
|
||||||
_loadBalancerHouse
|
_loadBalancerHouse
|
||||||
.Setup(x => x.Get(It.IsAny<string>()))
|
.Setup(x => x.Get(It.IsAny<ReRoute>(), It.IsAny<ServiceProviderConfiguration>()))
|
||||||
.Returns(new OkResponse<ILoadBalancer>(_loadBalancer.Object));
|
.ReturnsAsync(new OkResponse<ILoadBalancer>(_loadBalancer.Object));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenTheLoadBalancerHouseReturnsAnError()
|
private void GivenTheLoadBalancerHouseReturnsAnError()
|
||||||
@ -149,8 +170,8 @@ namespace Ocelot.UnitTests.LoadBalancer
|
|||||||
});
|
});
|
||||||
|
|
||||||
_loadBalancerHouse
|
_loadBalancerHouse
|
||||||
.Setup(x => x.Get(It.IsAny<string>()))
|
.Setup(x => x.Get(It.IsAny<ReRoute>(), It.IsAny<ServiceProviderConfiguration>()))
|
||||||
.Returns(_getLoadBalancerHouseError);
|
.ReturnsAsync(_getLoadBalancerHouseError);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenAnErrorStatingLoadBalancerCouldNotBeFoundIsSetOnPipeline()
|
private void ThenAnErrorStatingLoadBalancerCouldNotBeFoundIsSetOnPipeline()
|
||||||
|
@ -12,7 +12,7 @@ namespace Ocelot.UnitTests.LoadBalancer
|
|||||||
{
|
{
|
||||||
public class RoundRobinTests
|
public class RoundRobinTests
|
||||||
{
|
{
|
||||||
private readonly RoundRobinLoadBalancer _roundRobin;
|
private readonly RoundRobin _roundRobin;
|
||||||
private readonly List<Service> _services;
|
private readonly List<Service> _services;
|
||||||
private Response<HostAndPort> _hostAndPort;
|
private Response<HostAndPort> _hostAndPort;
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ namespace Ocelot.UnitTests.LoadBalancer
|
|||||||
new Service("product", new HostAndPort("127.0.0.1", 5001), string.Empty, string.Empty, new string[0])
|
new Service("product", new HostAndPort("127.0.0.1", 5001), string.Empty, string.Empty, new string[0])
|
||||||
};
|
};
|
||||||
|
|
||||||
_roundRobin = new RoundRobinLoadBalancer(() => Task.FromResult(_services));
|
_roundRobin = new RoundRobin(() => Task.FromResult(_services));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -31,6 +31,12 @@
|
|||||||
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
|
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="idsrv3test.pfx">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.0.0" />
|
||||||
|
@ -88,7 +88,7 @@
|
|||||||
private void GivenTheQosProviderHouseReturns(Response<IQoSProvider> qosProvider)
|
private void GivenTheQosProviderHouseReturns(Response<IQoSProvider> qosProvider)
|
||||||
{
|
{
|
||||||
_qosProviderHouse
|
_qosProviderHouse
|
||||||
.Setup(x => x.Get(It.IsAny<string>()))
|
.Setup(x => x.Get(It.IsAny<ReRoute>()))
|
||||||
.Returns(qosProvider);
|
.Returns(qosProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
using Ocelot.Requester.QoS;
|
using Moq;
|
||||||
|
using Ocelot.Configuration;
|
||||||
|
using Ocelot.Configuration.Builder;
|
||||||
|
using Ocelot.LoadBalancer.LoadBalancers;
|
||||||
|
using Ocelot.Requester.QoS;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
|
using Ocelot.UnitTests.LoadBalancer;
|
||||||
using Shouldly;
|
using Shouldly;
|
||||||
using TestStack.BDDfy;
|
using TestStack.BDDfy;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
@ -12,31 +17,32 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
private readonly QosProviderHouse _qosProviderHouse;
|
private readonly QosProviderHouse _qosProviderHouse;
|
||||||
private Response _addResult;
|
private Response _addResult;
|
||||||
private Response<IQoSProvider> _getResult;
|
private Response<IQoSProvider> _getResult;
|
||||||
private string _key;
|
private ReRoute _reRoute;
|
||||||
|
private readonly Mock<IQoSProviderFactory> _factory;
|
||||||
|
|
||||||
public QosProviderHouseTests()
|
public QosProviderHouseTests()
|
||||||
{
|
{
|
||||||
_qosProviderHouse = new QosProviderHouse();
|
_factory = new Mock<IQoSProviderFactory>();
|
||||||
|
_qosProviderHouse = new QosProviderHouse(_factory.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_store_qos_provider()
|
public void should_store_qos_provider_on_first_request()
|
||||||
{
|
{
|
||||||
var key = "test";
|
var reRoute = new ReRouteBuilder().WithReRouteKey("test").Build();
|
||||||
|
|
||||||
this.Given(x => x.GivenThereIsAQoSProvider(key, new FakeQoSProvider()))
|
this.Given(x => x.GivenThereIsAQoSProvider(reRoute, new FakeQoSProvider()))
|
||||||
.When(x => x.WhenIAddTheQoSProvider())
|
|
||||||
.Then(x => x.ThenItIsAdded())
|
.Then(x => x.ThenItIsAdded())
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_get_qos_provider()
|
public void should_not_store_qos_provider_on_first_request()
|
||||||
{
|
{
|
||||||
var key = "test";
|
var reRoute = new ReRouteBuilder().WithReRouteKey("test").Build();
|
||||||
|
|
||||||
this.Given(x => x.GivenThereIsAQoSProvider(key, new FakeQoSProvider()))
|
this.Given(x => x.GivenThereIsAQoSProvider(reRoute, new FakeQoSProvider()))
|
||||||
.When(x => x.WhenWeGetTheQoSProvider(key))
|
.When(x => x.WhenWeGetTheQoSProvider(reRoute))
|
||||||
.Then(x => x.ThenItIsReturned())
|
.Then(x => x.ThenItIsReturned())
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
@ -44,14 +50,14 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void should_store_qos_providers_by_key()
|
public void should_store_qos_providers_by_key()
|
||||||
{
|
{
|
||||||
var key = "test";
|
var reRoute = new ReRouteBuilder().WithReRouteKey("test").Build();
|
||||||
var keyTwo = "testTwo";
|
var reRouteTwo = new ReRouteBuilder().WithReRouteKey("testTwo").Build();
|
||||||
|
|
||||||
this.Given(x => x.GivenThereIsAQoSProvider(key, new FakeQoSProvider()))
|
this.Given(x => x.GivenThereIsAQoSProvider(reRoute, new FakeQoSProvider()))
|
||||||
.And(x => x.GivenThereIsAQoSProvider(keyTwo, new FakePollyQoSProvider()))
|
.And(x => x.GivenThereIsAQoSProvider(reRouteTwo, new FakePollyQoSProvider()))
|
||||||
.When(x => x.WhenWeGetTheQoSProvider(key))
|
.When(x => x.WhenWeGetTheQoSProvider(reRoute))
|
||||||
.Then(x => x.ThenTheQoSProviderIs<FakeQoSProvider>())
|
.Then(x => x.ThenTheQoSProviderIs<FakeQoSProvider>())
|
||||||
.When(x => x.WhenWeGetTheQoSProvider(keyTwo))
|
.When(x => x.WhenWeGetTheQoSProvider(reRouteTwo))
|
||||||
.Then(x => x.ThenTheQoSProviderIs<FakePollyQoSProvider>())
|
.Then(x => x.ThenTheQoSProviderIs<FakePollyQoSProvider>())
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
@ -59,11 +65,35 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void should_return_error_if_no_qos_provider_with_key()
|
public void should_return_error_if_no_qos_provider_with_key()
|
||||||
{
|
{
|
||||||
this.When(x => x.WhenWeGetTheQoSProvider("test"))
|
var reRoute = new ReRouteBuilder().Build();
|
||||||
|
|
||||||
|
this.When(x => x.WhenWeGetTheQoSProvider(reRoute))
|
||||||
.Then(x => x.ThenAnErrorIsReturned())
|
.Then(x => x.ThenAnErrorIsReturned())
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_get_new_qos_provider_if_reroute_qos_provider_has_changed()
|
||||||
|
{
|
||||||
|
var reRoute = new ReRouteBuilder().WithReRouteKey("test").Build();
|
||||||
|
|
||||||
|
var reRouteTwo = new ReRouteBuilder().WithReRouteKey("test").WithIsQos(true).Build();
|
||||||
|
|
||||||
|
this.Given(x => x.GivenThereIsAQoSProvider(reRoute, new FakeQoSProvider()))
|
||||||
|
.When(x => x.WhenWeGetTheQoSProvider(reRoute))
|
||||||
|
.Then(x => x.ThenTheQoSProviderIs<FakeQoSProvider>())
|
||||||
|
.When(x => x.WhenIGetTheReRouteWithTheSameKeyButDifferentQosProvider(reRouteTwo))
|
||||||
|
.Then(x => x.ThenTheQoSProviderIs<FakePollyQoSProvider>())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WhenIGetTheReRouteWithTheSameKeyButDifferentQosProvider(ReRoute reRoute)
|
||||||
|
{
|
||||||
|
_reRoute = reRoute;
|
||||||
|
_factory.Setup(x => x.Get(_reRoute)).Returns(new FakePollyQoSProvider());
|
||||||
|
_getResult = _qosProviderHouse.Get(_reRoute);
|
||||||
|
}
|
||||||
|
|
||||||
private void ThenAnErrorIsReturned()
|
private void ThenAnErrorIsReturned()
|
||||||
{
|
{
|
||||||
_getResult.IsError.ShouldBeTrue();
|
_getResult.IsError.ShouldBeTrue();
|
||||||
@ -77,31 +107,30 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
|
|
||||||
private void ThenItIsAdded()
|
private void ThenItIsAdded()
|
||||||
{
|
{
|
||||||
_addResult.IsError.ShouldBe(false);
|
_getResult.IsError.ShouldBe(false);
|
||||||
_addResult.ShouldBeOfType<OkResponse>();
|
_getResult.ShouldBeOfType<OkResponse<IQoSProvider>>();
|
||||||
}
|
_factory.Verify(x => x.Get(_reRoute), Times.Once);
|
||||||
|
_getResult.Data.ShouldBe(_qoSProvider);
|
||||||
private void WhenIAddTheQoSProvider()
|
|
||||||
{
|
|
||||||
_addResult = _qosProviderHouse.Add(_key, _qoSProvider);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void GivenThereIsAQoSProvider(string key, IQoSProvider qoSProvider)
|
private void GivenThereIsAQoSProvider(ReRoute reRoute, IQoSProvider qoSProvider)
|
||||||
{
|
{
|
||||||
_key = key;
|
_reRoute = reRoute;
|
||||||
_qoSProvider = qoSProvider;
|
_qoSProvider = qoSProvider;
|
||||||
WhenIAddTheQoSProvider();
|
_factory.Setup(x => x.Get(_reRoute)).Returns(_qoSProvider);
|
||||||
|
_getResult = _qosProviderHouse.Get(reRoute);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WhenWeGetTheQoSProvider(string key)
|
private void WhenWeGetTheQoSProvider(ReRoute reRoute)
|
||||||
{
|
{
|
||||||
_getResult = _qosProviderHouse.Get(key);
|
_getResult = _qosProviderHouse.Get(reRoute);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenItIsReturned()
|
private void ThenItIsReturned()
|
||||||
{
|
{
|
||||||
_getResult.Data.ShouldBe(_qoSProvider);
|
_getResult.Data.ShouldBe(_qoSProvider);
|
||||||
|
_factory.Verify(x => x.Get(_reRoute), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
class FakeQoSProvider : IQoSProvider
|
class FakeQoSProvider : IQoSProvider
|
||||||
|
@ -12,6 +12,7 @@ namespace Ocelot.UnitTests.ServiceDiscovery
|
|||||||
private ServiceProviderConfiguration _serviceConfig;
|
private ServiceProviderConfiguration _serviceConfig;
|
||||||
private IServiceDiscoveryProvider _result;
|
private IServiceDiscoveryProvider _result;
|
||||||
private readonly ServiceDiscoveryProviderFactory _factory;
|
private readonly ServiceDiscoveryProviderFactory _factory;
|
||||||
|
private ReRoute _reRoute;
|
||||||
|
|
||||||
public ServiceProviderFactoryTests()
|
public ServiceProviderFactoryTests()
|
||||||
{
|
{
|
||||||
@ -22,12 +23,11 @@ namespace Ocelot.UnitTests.ServiceDiscovery
|
|||||||
public void should_return_no_service_provider()
|
public void should_return_no_service_provider()
|
||||||
{
|
{
|
||||||
var serviceConfig = new ServiceProviderConfigurationBuilder()
|
var serviceConfig = new ServiceProviderConfigurationBuilder()
|
||||||
.WithDownstreamHost("127.0.0.1")
|
|
||||||
.WithDownstreamPort(80)
|
|
||||||
.WithUseServiceDiscovery(false)
|
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
this.Given(x => x.GivenTheReRoute(serviceConfig))
|
var reRoute = new ReRouteBuilder().Build();
|
||||||
|
|
||||||
|
this.Given(x => x.GivenTheReRoute(serviceConfig, reRoute))
|
||||||
.When(x => x.WhenIGetTheServiceProvider())
|
.When(x => x.WhenIGetTheServiceProvider())
|
||||||
.Then(x => x.ThenTheServiceProviderIs<ConfigurationServiceProvider>())
|
.Then(x => x.ThenTheServiceProviderIs<ConfigurationServiceProvider>())
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
@ -36,26 +36,29 @@ namespace Ocelot.UnitTests.ServiceDiscovery
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void should_return_consul_service_provider()
|
public void should_return_consul_service_provider()
|
||||||
{
|
{
|
||||||
var serviceConfig = new ServiceProviderConfigurationBuilder()
|
var reRoute = new ReRouteBuilder()
|
||||||
.WithServiceName("product")
|
.WithServiceName("product")
|
||||||
.WithUseServiceDiscovery(true)
|
.WithUseServiceDiscovery(true)
|
||||||
.WithServiceDiscoveryProvider("Consul")
|
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
this.Given(x => x.GivenTheReRoute(serviceConfig))
|
var serviceConfig = new ServiceProviderConfigurationBuilder()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
this.Given(x => x.GivenTheReRoute(serviceConfig, reRoute))
|
||||||
.When(x => x.WhenIGetTheServiceProvider())
|
.When(x => x.WhenIGetTheServiceProvider())
|
||||||
.Then(x => x.ThenTheServiceProviderIs<ConsulServiceDiscoveryProvider>())
|
.Then(x => x.ThenTheServiceProviderIs<ConsulServiceDiscoveryProvider>())
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenTheReRoute(ServiceProviderConfiguration serviceConfig)
|
private void GivenTheReRoute(ServiceProviderConfiguration serviceConfig, ReRoute reRoute)
|
||||||
{
|
{
|
||||||
_serviceConfig = serviceConfig;
|
_serviceConfig = serviceConfig;
|
||||||
|
_reRoute = reRoute;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WhenIGetTheServiceProvider()
|
private void WhenIGetTheServiceProvider()
|
||||||
{
|
{
|
||||||
_result = _factory.Get(_serviceConfig);
|
_result = _factory.Get(_serviceConfig, _reRoute);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenTheServiceProviderIs<T>()
|
private void ThenTheServiceProviderIs<T>()
|
||||||
|
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