Merge pull request #58 from TomPallister/feature/refactor-config-creator

Feature/refactor config creator
This commit is contained in:
Tom Pallister 2017-03-05 17:08:07 +00:00 committed by GitHub
commit a70a279487
39 changed files with 1502 additions and 445 deletions

View File

@ -0,0 +1,71 @@
using System.Collections.Generic;
namespace Ocelot.Configuration.Builder
{
public class RateLimitOptionsBuilder
{
private bool _enableRateLimiting;
private string _clientIdHeader;
private List<string> _clientWhitelist;
private bool _disableRateLimitHeaders;
private string _quotaExceededMessage;
private string _rateLimitCounterPrefix;
private RateLimitRule _rateLimitRule;
private int _httpStatusCode;
public RateLimitOptionsBuilder WithEnableRateLimiting(bool enableRateLimiting)
{
_enableRateLimiting = enableRateLimiting;
return this;
}
public RateLimitOptionsBuilder WithClientIdHeader(string clientIdheader)
{
_clientIdHeader = clientIdheader;
return this;
}
public RateLimitOptionsBuilder WithClientWhiteList(List<string> clientWhitelist)
{
_clientWhitelist = clientWhitelist;
return this;
}
public RateLimitOptionsBuilder WithDisableRateLimitHeaders(bool disableRateLimitHeaders)
{
_disableRateLimitHeaders = disableRateLimitHeaders;
return this;
}
public RateLimitOptionsBuilder WithQuotaExceededMessage(string quotaExceededMessage)
{
_quotaExceededMessage = quotaExceededMessage;
return this;
}
public RateLimitOptionsBuilder WithRateLimitCounterPrefix(string rateLimitCounterPrefix)
{
_rateLimitCounterPrefix = rateLimitCounterPrefix;
return this;
}
public RateLimitOptionsBuilder WithRateLimitRule(RateLimitRule rateLimitRule)
{
_rateLimitRule = rateLimitRule;
return this;
}
public RateLimitOptionsBuilder WithHttpStatusCode(int httpStatusCode)
{
_httpStatusCode = httpStatusCode;
return this;
}
public RateLimitOptions Build()
{
return new RateLimitOptions(_enableRateLimiting, _clientIdHeader, _clientWhitelist,
_disableRateLimitHeaders, _quotaExceededMessage, _rateLimitCounterPrefix,
_rateLimitRule, _httpStatusCode);
}
}
}

View File

@ -25,7 +25,7 @@ namespace Ocelot.Configuration.Builder
private string _downstreamHost; private string _downstreamHost;
private int _downstreamPort; private int _downstreamPort;
private string _loadBalancer; private string _loadBalancer;
private ServiceProviderConfiguraion _serviceProviderConfiguraion; private ServiceProviderConfiguration _serviceProviderConfiguraion;
private bool _useQos; private bool _useQos;
private QoSOptions _qosOptions; private QoSOptions _qosOptions;
public bool _enableRateLimiting; public bool _enableRateLimiting;
@ -150,7 +150,7 @@ namespace Ocelot.Configuration.Builder
return this; return this;
} }
public ReRouteBuilder WithServiceProviderConfiguraion(ServiceProviderConfiguraion serviceProviderConfiguraion) public ReRouteBuilder WithServiceProviderConfiguraion(ServiceProviderConfiguration serviceProviderConfiguraion)
{ {
_serviceProviderConfiguraion = serviceProviderConfiguraion; _serviceProviderConfiguraion = serviceProviderConfiguraion;
return this; return this;

View File

@ -0,0 +1,46 @@
namespace Ocelot.Configuration.Builder
{
public class ReRouteOptionsBuilder
{
private bool _isAuthenticated;
private bool _isAuthorised;
private bool _isCached;
private bool _isQoS;
private bool _enableRateLimiting;
public ReRouteOptionsBuilder WithIsCached(bool isCached)
{
_isCached = isCached;
return this;
}
public ReRouteOptionsBuilder WithIsAuthenticated(bool isAuthenticated)
{
_isAuthenticated = isAuthenticated;
return this;
}
public ReRouteOptionsBuilder WithIsAuthorised(bool isAuthorised)
{
_isAuthorised = isAuthorised;
return this;
}
public ReRouteOptionsBuilder WithIsQos(bool isQoS)
{
_isQoS = isQoS;
return this;
}
public ReRouteOptionsBuilder WithRateLimiting(bool enableRateLimiting)
{
_enableRateLimiting = enableRateLimiting;
return this;
}
public ReRouteOptions Build()
{
return new ReRouteOptions(_isAuthenticated, _isAuthorised, _isCached, _isQoS, _enableRateLimiting);
}
}
}

View File

@ -1,6 +1,6 @@
namespace Ocelot.Configuration.Builder namespace Ocelot.Configuration.Builder
{ {
public class ServiceProviderConfiguraionBuilder public class ServiceProviderConfigurationBuilder
{ {
private string _serviceName; private string _serviceName;
private string _downstreamHost; private string _downstreamHost;
@ -10,52 +10,52 @@ namespace Ocelot.Configuration.Builder
private string _serviceDiscoveryProviderHost; private string _serviceDiscoveryProviderHost;
private int _serviceDiscoveryProviderPort; private int _serviceDiscoveryProviderPort;
public ServiceProviderConfiguraionBuilder WithServiceName(string serviceName) public ServiceProviderConfigurationBuilder WithServiceName(string serviceName)
{ {
_serviceName = serviceName; _serviceName = serviceName;
return this; return this;
} }
public ServiceProviderConfiguraionBuilder WithDownstreamHost(string downstreamHost) public ServiceProviderConfigurationBuilder WithDownstreamHost(string downstreamHost)
{ {
_downstreamHost = downstreamHost; _downstreamHost = downstreamHost;
return this; return this;
} }
public ServiceProviderConfiguraionBuilder WithDownstreamPort(int downstreamPort) public ServiceProviderConfigurationBuilder WithDownstreamPort(int downstreamPort)
{ {
_downstreamPort = downstreamPort; _downstreamPort = downstreamPort;
return this; return this;
} }
public ServiceProviderConfiguraionBuilder WithUseServiceDiscovery(bool userServiceDiscovery) public ServiceProviderConfigurationBuilder WithUseServiceDiscovery(bool userServiceDiscovery)
{ {
_userServiceDiscovery = userServiceDiscovery; _userServiceDiscovery = userServiceDiscovery;
return this; return this;
} }
public ServiceProviderConfiguraionBuilder WithServiceDiscoveryProvider(string serviceDiscoveryProvider) public ServiceProviderConfigurationBuilder WithServiceDiscoveryProvider(string serviceDiscoveryProvider)
{ {
_serviceDiscoveryProvider = serviceDiscoveryProvider; _serviceDiscoveryProvider = serviceDiscoveryProvider;
return this; return this;
} }
public ServiceProviderConfiguraionBuilder WithServiceDiscoveryProviderHost(string serviceDiscoveryProviderHost) public ServiceProviderConfigurationBuilder WithServiceDiscoveryProviderHost(string serviceDiscoveryProviderHost)
{ {
_serviceDiscoveryProviderHost = serviceDiscoveryProviderHost; _serviceDiscoveryProviderHost = serviceDiscoveryProviderHost;
return this; return this;
} }
public ServiceProviderConfiguraionBuilder WithServiceDiscoveryProviderPort(int serviceDiscoveryProviderPort) public ServiceProviderConfigurationBuilder WithServiceDiscoveryProviderPort(int serviceDiscoveryProviderPort)
{ {
_serviceDiscoveryProviderPort = serviceDiscoveryProviderPort; _serviceDiscoveryProviderPort = serviceDiscoveryProviderPort;
return this; return this;
} }
public ServiceProviderConfiguraion Build() public ServiceProviderConfiguration Build()
{ {
return new ServiceProviderConfiguraion(_serviceName, _downstreamHost, _downstreamPort, _userServiceDiscovery, return new ServiceProviderConfiguration(_serviceName, _downstreamHost, _downstreamPort, _userServiceDiscovery,
_serviceDiscoveryProvider, _serviceDiscoveryProviderHost,_serviceDiscoveryProviderPort); _serviceDiscoveryProvider, _serviceDiscoveryProviderHost,_serviceDiscoveryProviderPort);
} }
} }

View File

@ -0,0 +1,20 @@
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.File;
namespace Ocelot.Configuration.Creator
{
public class AuthenticationOptionsCreator : IAuthenticationOptionsCreator
{
public AuthenticationOptions Create(FileReRoute fileReRoute)
{
return new AuthenticationOptionsBuilder()
.WithProvider(fileReRoute.AuthenticationOptions?.Provider)
.WithProviderRootUrl(fileReRoute.AuthenticationOptions?.ProviderRootUrl)
.WithScopeName(fileReRoute.AuthenticationOptions?.ScopeName)
.WithRequireHttps(fileReRoute.AuthenticationOptions.RequireHttps)
.WithAdditionalScopes(fileReRoute.AuthenticationOptions?.AdditionalScopes)
.WithScopeSecret(fileReRoute.AuthenticationOptions?.ScopeSecret)
.Build();
}
}
}

View File

@ -0,0 +1,41 @@
using System.Collections.Generic;
using Ocelot.Configuration.Parser;
using Ocelot.Logging;
namespace Ocelot.Configuration.Creator
{
public class ClaimsToThingCreator : IClaimsToThingCreator
{
private readonly IClaimToThingConfigurationParser _claimToThingConfigParser;
private readonly IOcelotLogger _logger;
public ClaimsToThingCreator(IClaimToThingConfigurationParser claimToThingConfigurationParser,
IOcelotLoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<ClaimsToThingCreator>();
_claimToThingConfigParser = claimToThingConfigurationParser;
}
public List<ClaimToThing> Create(Dictionary<string,string> inputToBeParsed)
{
var claimsToThings = new List<ClaimToThing>();
foreach (var input in inputToBeParsed)
{
var claimToThing = _claimToThingConfigParser.Extract(input.Key, input.Value);
if (claimToThing.IsError)
{
_logger.LogDebug("ClaimsToThingCreator.BuildAddThingsToRequest",
$"Unable to extract configuration for key: {input.Key} and value: {input.Value} your configuration file is incorrect");
}
else
{
claimsToThings.Add(claimToThing.Data);
}
}
return claimsToThings;
}
}
}

View File

@ -22,36 +22,53 @@ namespace Ocelot.Configuration.Creator
{ {
private readonly IOptions<FileConfiguration> _options; private readonly IOptions<FileConfiguration> _options;
private readonly IConfigurationValidator _configurationValidator; private readonly IConfigurationValidator _configurationValidator;
private const string RegExMatchEverything = ".*";
private const string RegExMatchEndString = "$";
private const string RegExIgnoreCase = "(?i)";
private const string RegExForwardSlashOnly = "^/$";
private readonly IClaimToThingConfigurationParser _claimToThingConfigurationParser;
private readonly ILogger<FileOcelotConfigurationCreator> _logger; private readonly ILogger<FileOcelotConfigurationCreator> _logger;
private readonly ILoadBalancerFactory _loadBalanceFactory; private readonly ILoadBalancerFactory _loadBalanceFactory;
private readonly ILoadBalancerHouse _loadBalancerHouse; private readonly ILoadBalancerHouse _loadBalancerHouse;
private readonly IQoSProviderFactory _qoSProviderFactory; private readonly IQoSProviderFactory _qoSProviderFactory;
private readonly IQosProviderHouse _qosProviderHouse; private readonly IQosProviderHouse _qosProviderHouse;
private readonly IClaimsToThingCreator _claimsToThingCreator;
private readonly IAuthenticationOptionsCreator _authOptionsCreator;
private IUpstreamTemplatePatternCreator _upstreamTemplatePatternCreator;
private IRequestIdKeyCreator _requestIdKeyCreator;
private IServiceProviderConfigurationCreator _serviceProviderConfigCreator;
private IQoSOptionsCreator _qosOptionsCreator;
private IReRouteOptionsCreator _fileReRouteOptionsCreator;
private IRateLimitOptionsCreator _rateLimitOptionsCreator;
public FileOcelotConfigurationCreator( public FileOcelotConfigurationCreator(
IOptions<FileConfiguration> options, IOptions<FileConfiguration> options,
IConfigurationValidator configurationValidator, IConfigurationValidator configurationValidator,
IClaimToThingConfigurationParser claimToThingConfigurationParser,
ILogger<FileOcelotConfigurationCreator> logger, ILogger<FileOcelotConfigurationCreator> logger,
ILoadBalancerFactory loadBalancerFactory, ILoadBalancerFactory loadBalancerFactory,
ILoadBalancerHouse loadBalancerHouse, ILoadBalancerHouse loadBalancerHouse,
IQoSProviderFactory qoSProviderFactory, IQoSProviderFactory qoSProviderFactory,
IQosProviderHouse qosProviderHouse) IQosProviderHouse qosProviderHouse,
IClaimsToThingCreator claimsToThingCreator,
IAuthenticationOptionsCreator authOptionsCreator,
IUpstreamTemplatePatternCreator upstreamTemplatePatternCreator,
IRequestIdKeyCreator requestIdKeyCreator,
IServiceProviderConfigurationCreator serviceProviderConfigCreator,
IQoSOptionsCreator qosOptionsCreator,
IReRouteOptionsCreator fileReRouteOptionsCreator,
IRateLimitOptionsCreator rateLimitOptionsCreator
)
{ {
_rateLimitOptionsCreator = rateLimitOptionsCreator;
_requestIdKeyCreator = requestIdKeyCreator;
_upstreamTemplatePatternCreator = upstreamTemplatePatternCreator;
_authOptionsCreator = authOptionsCreator;
_loadBalanceFactory = loadBalancerFactory; _loadBalanceFactory = loadBalancerFactory;
_loadBalancerHouse = loadBalancerHouse; _loadBalancerHouse = loadBalancerHouse;
_qoSProviderFactory = qoSProviderFactory; _qoSProviderFactory = qoSProviderFactory;
_qosProviderHouse = qosProviderHouse; _qosProviderHouse = qosProviderHouse;
_options = options; _options = options;
_configurationValidator = configurationValidator; _configurationValidator = configurationValidator;
_claimToThingConfigurationParser = claimToThingConfigurationParser;
_logger = logger; _logger = logger;
_claimsToThingCreator = claimsToThingCreator;
_serviceProviderConfigCreator = serviceProviderConfigCreator;
_qosOptionsCreator = qosOptionsCreator;
_fileReRouteOptionsCreator = fileReRouteOptionsCreator;
} }
public async Task<Response<IOcelotConfiguration>> Create() public async Task<Response<IOcelotConfiguration>> Create()
@ -97,50 +114,42 @@ namespace Ocelot.Configuration.Creator
private async Task<ReRoute> SetUpReRoute(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration) private async Task<ReRoute> SetUpReRoute(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration)
{ {
var isAuthenticated = IsAuthenticated(fileReRoute); var fileReRouteOptions = _fileReRouteOptionsCreator.Create(fileReRoute);
var isAuthorised = IsAuthorised(fileReRoute); var requestIdKey = _requestIdKeyCreator.Create(fileReRoute, globalConfiguration);
var isCached = IsCached(fileReRoute); var reRouteKey = CreateReRouteKey(fileReRoute);
var requestIdKey = BuildRequestId(fileReRoute, globalConfiguration); var upstreamTemplatePattern = _upstreamTemplatePatternCreator.Create(fileReRoute);
var reRouteKey = BuildReRouteKey(fileReRoute); var serviceProviderConfiguration = _serviceProviderConfigCreator.Create(fileReRoute, globalConfiguration);
var upstreamTemplatePattern = BuildUpstreamTemplatePattern(fileReRoute); var authOptionsForRoute = _authOptionsCreator.Create(fileReRoute);
var isQos = IsQoS(fileReRoute); var claimsToHeaders = _claimsToThingCreator.Create(fileReRoute.AddHeadersToRequest);
var serviceProviderConfiguration = BuildServiceProviderConfiguration(fileReRoute, globalConfiguration); var claimsToClaims = _claimsToThingCreator.Create(fileReRoute.AddClaimsToRequest);
var authOptionsForRoute = BuildAuthenticationOptions(fileReRoute); var claimsToQueries = _claimsToThingCreator.Create(fileReRoute.AddQueriesToRequest);
var claimsToHeaders = BuildAddThingsToRequest(fileReRoute.AddHeadersToRequest); var qosOptions = _qosOptionsCreator.Create(fileReRoute);
var claimsToClaims = BuildAddThingsToRequest(fileReRoute.AddClaimsToRequest); var rateLimitOption = _rateLimitOptionsCreator.Create(fileReRoute, globalConfiguration, fileReRouteOptions.EnableRateLimiting);
var claimsToQueries = BuildAddThingsToRequest(fileReRoute.AddQueriesToRequest);
var qosOptions = BuildQoSOptions(fileReRoute);
var enableRateLimiting = IsEnableRateLimiting(fileReRoute);
var rateLimitOption = BuildRateLimitOptions(fileReRoute, globalConfiguration, enableRateLimiting);
var reRoute = new ReRouteBuilder() var reRoute = new ReRouteBuilder()
.WithDownstreamPathTemplate(fileReRoute.DownstreamPathTemplate) .WithDownstreamPathTemplate(fileReRoute.DownstreamPathTemplate)
.WithUpstreamPathTemplate(fileReRoute.UpstreamPathTemplate) .WithUpstreamPathTemplate(fileReRoute.UpstreamPathTemplate)
.WithUpstreamHttpMethod(fileReRoute.UpstreamHttpMethod) .WithUpstreamHttpMethod(fileReRoute.UpstreamHttpMethod)
.WithUpstreamTemplatePattern(upstreamTemplatePattern) .WithUpstreamTemplatePattern(upstreamTemplatePattern)
.WithIsAuthenticated(isAuthenticated) .WithIsAuthenticated(fileReRouteOptions.IsAuthenticated)
.WithAuthenticationOptions(authOptionsForRoute) .WithAuthenticationOptions(authOptionsForRoute)
.WithClaimsToHeaders(claimsToHeaders) .WithClaimsToHeaders(claimsToHeaders)
.WithClaimsToClaims(claimsToClaims) .WithClaimsToClaims(claimsToClaims)
.WithRouteClaimsRequirement(fileReRoute.RouteClaimsRequirement) .WithRouteClaimsRequirement(fileReRoute.RouteClaimsRequirement)
.WithIsAuthorised(isAuthorised) .WithIsAuthorised(fileReRouteOptions.IsAuthorised)
.WithClaimsToQueries(claimsToQueries) .WithClaimsToQueries(claimsToQueries)
.WithRequestIdKey(requestIdKey) .WithRequestIdKey(requestIdKey)
.WithIsCached(isCached) .WithIsCached(fileReRouteOptions.IsCached)
.WithCacheOptions(new CacheOptions(fileReRoute.FileCacheOptions.TtlSeconds)) .WithCacheOptions(new CacheOptions(fileReRoute.FileCacheOptions.TtlSeconds))
.WithDownstreamScheme(fileReRoute.DownstreamScheme) .WithDownstreamScheme(fileReRoute.DownstreamScheme)
.WithLoadBalancer(fileReRoute.LoadBalancer) .WithLoadBalancer(fileReRoute.LoadBalancer)
@ -148,95 +157,24 @@ namespace Ocelot.Configuration.Creator
.WithDownstreamPort(fileReRoute.DownstreamPort) .WithDownstreamPort(fileReRoute.DownstreamPort)
.WithLoadBalancerKey(reRouteKey) .WithLoadBalancerKey(reRouteKey)
.WithServiceProviderConfiguraion(serviceProviderConfiguration) .WithServiceProviderConfiguraion(serviceProviderConfiguration)
.WithIsQos(isQos) .WithIsQos(fileReRouteOptions.IsQos)
.WithQosOptions(qosOptions) .WithQosOptions(qosOptions)
.WithEnableRateLimiting(enableRateLimiting) .WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting)
.WithRateLimitOptions(rateLimitOption) .WithRateLimitOptions(rateLimitOption)
.Build(); .Build();
await SetupLoadBalancer(reRoute); await SetupLoadBalancer(reRoute);
SetupQosProvider(reRoute); SetupQosProvider(reRoute);
return reRoute; return reRoute;
} }
private static RateLimitOptions BuildRateLimitOptions(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration, bool enableRateLimiting) private string CreateReRouteKey(FileReRoute fileReRoute)
{
RateLimitOptions rateLimitOption = null;
if (enableRateLimiting)
{
rateLimitOption = new RateLimitOptions(enableRateLimiting, globalConfiguration.RateLimitOptions.ClientIdHeader,
fileReRoute.RateLimitOptions.ClientWhitelist, globalConfiguration.RateLimitOptions.DisableRateLimitHeaders,
globalConfiguration.RateLimitOptions.QuotaExceededMessage, globalConfiguration.RateLimitOptions.RateLimitCounterPrefix,
new RateLimitRule(fileReRoute.RateLimitOptions.Period, TimeSpan.FromSeconds(fileReRoute.RateLimitOptions.PeriodTimespan), fileReRoute.RateLimitOptions.Limit)
, globalConfiguration.RateLimitOptions.HttpStatusCode);
}
return rateLimitOption;
}
private static bool IsEnableRateLimiting(FileReRoute fileReRoute)
{
return (fileReRoute.RateLimitOptions != null && fileReRoute.RateLimitOptions.EnableRateLimiting) ? true : false;
}
private QoSOptions BuildQoSOptions(FileReRoute fileReRoute)
{
return new QoSOptionsBuilder()
.WithExceptionsAllowedBeforeBreaking(fileReRoute.QoSOptions.ExceptionsAllowedBeforeBreaking)
.WithDurationOfBreak(fileReRoute.QoSOptions.DurationOfBreak)
.WithTimeoutValue(fileReRoute.QoSOptions.TimeoutValue)
.Build();
}
private bool IsQoS(FileReRoute fileReRoute)
{
return fileReRoute.QoSOptions?.ExceptionsAllowedBeforeBreaking > 0 && fileReRoute.QoSOptions?.TimeoutValue > 0;
}
private bool IsAuthenticated(FileReRoute fileReRoute)
{
return !string.IsNullOrEmpty(fileReRoute.AuthenticationOptions?.Provider);
}
private bool IsAuthorised(FileReRoute fileReRoute)
{
return fileReRoute.RouteClaimsRequirement?.Count > 0;
}
private bool IsCached(FileReRoute fileReRoute)
{
return fileReRoute.FileCacheOptions.TtlSeconds > 0;
}
private string BuildRequestId(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration)
{
var globalRequestIdConfiguration = !string.IsNullOrEmpty(globalConfiguration?.RequestIdKey);
var requestIdKey = globalRequestIdConfiguration
? globalConfiguration.RequestIdKey
: fileReRoute.RequestIdKey;
return requestIdKey;
}
private string BuildReRouteKey(FileReRoute fileReRoute)
{ {
//note - not sure if this is the correct key, but this is probably the only unique key i can think of given my poor brain //note - not sure if this is the correct key, but this is probably the only unique key i can think of given my poor brain
var loadBalancerKey = $"{fileReRoute.UpstreamPathTemplate}{fileReRoute.UpstreamHttpMethod}"; var loadBalancerKey = $"{fileReRoute.UpstreamPathTemplate}{fileReRoute.UpstreamHttpMethod}";
return loadBalancerKey; return loadBalancerKey;
} }
private AuthenticationOptions BuildAuthenticationOptions(FileReRoute fileReRoute)
{
return new AuthenticationOptionsBuilder()
.WithProvider(fileReRoute.AuthenticationOptions?.Provider)
.WithProviderRootUrl(fileReRoute.AuthenticationOptions?.ProviderRootUrl)
.WithScopeName(fileReRoute.AuthenticationOptions?.ScopeName)
.WithRequireHttps(fileReRoute.AuthenticationOptions.RequireHttps)
.WithAdditionalScopes(fileReRoute.AuthenticationOptions?.AdditionalScopes)
.WithScopeSecret(fileReRoute.AuthenticationOptions?.ScopeSecret)
.Build();
}
private async Task SetupLoadBalancer(ReRoute reRoute) private async Task SetupLoadBalancer(ReRoute reRoute)
{ {
var loadBalancer = await _loadBalanceFactory.Get(reRoute); var loadBalancer = await _loadBalanceFactory.Get(reRoute);
@ -248,85 +186,5 @@ namespace Ocelot.Configuration.Creator
var loadBalancer = _qoSProviderFactory.Get(reRoute); var loadBalancer = _qoSProviderFactory.Get(reRoute);
_qosProviderHouse.Add(reRoute.ReRouteKey, loadBalancer); _qosProviderHouse.Add(reRoute.ReRouteKey, loadBalancer);
} }
private ServiceProviderConfiguraion BuildServiceProviderConfiguration(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration)
{
var useServiceDiscovery = !string.IsNullOrEmpty(fileReRoute.ServiceName)
&& !string.IsNullOrEmpty(globalConfiguration?.ServiceDiscoveryProvider?.Provider);
var serviceProviderPort = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0;
return new ServiceProviderConfiguraionBuilder()
.WithServiceName(fileReRoute.ServiceName)
.WithDownstreamHost(fileReRoute.DownstreamHost)
.WithDownstreamPort(fileReRoute.DownstreamPort)
.WithUseServiceDiscovery(useServiceDiscovery)
.WithServiceDiscoveryProvider(globalConfiguration?.ServiceDiscoveryProvider?.Provider)
.WithServiceDiscoveryProviderHost(globalConfiguration?.ServiceDiscoveryProvider?.Host)
.WithServiceDiscoveryProviderPort(serviceProviderPort)
.Build();
}
private string BuildUpstreamTemplatePattern(FileReRoute reRoute)
{
var upstreamTemplate = reRoute.UpstreamPathTemplate;
upstreamTemplate = upstreamTemplate.SetLastCharacterAs('/');
var placeholders = new List<string>();
for (var i = 0; i < upstreamTemplate.Length; i++)
{
if (IsPlaceHolder(upstreamTemplate, i))
{
var postitionOfPlaceHolderClosingBracket = upstreamTemplate.IndexOf('}', i);
var difference = postitionOfPlaceHolderClosingBracket - i + 1;
var variableName = upstreamTemplate.Substring(i, difference);
placeholders.Add(variableName);
}
}
foreach (var placeholder in placeholders)
{
upstreamTemplate = upstreamTemplate.Replace(placeholder, RegExMatchEverything);
}
if (upstreamTemplate == "/")
{
return RegExForwardSlashOnly;
}
var route = reRoute.ReRouteIsCaseSensitive
? $"{upstreamTemplate}{RegExMatchEndString}"
: $"{RegExIgnoreCase}{upstreamTemplate}{RegExMatchEndString}";
return route;
}
private List<ClaimToThing> BuildAddThingsToRequest(Dictionary<string,string> thingBeingAdded)
{
var claimsToTHings = new List<ClaimToThing>();
foreach (var add in thingBeingAdded)
{
var claimToHeader = _claimToThingConfigurationParser.Extract(add.Key, add.Value);
if (claimToHeader.IsError)
{
_logger.LogCritical(new EventId(1, "Application Failed to start"),
$"Unable to extract configuration for key: {add.Key} and value: {add.Value} your configuration file is incorrect");
throw new Exception(claimToHeader.Errors[0].Message);
}
claimsToTHings.Add(claimToHeader.Data);
}
return claimsToTHings;
}
private bool IsPlaceHolder(string upstreamTemplate, int i)
{
return upstreamTemplate[i] == '{';
}
} }
} }

View File

@ -0,0 +1,9 @@
using Ocelot.Configuration.File;
namespace Ocelot.Configuration.Creator
{
public interface IAuthenticationOptionsCreator
{
AuthenticationOptions Create(FileReRoute fileReRoute);
}
}

View File

@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Ocelot.Configuration.Creator
{
public interface IClaimsToThingCreator
{
List<ClaimToThing> Create(Dictionary<string,string> thingsBeingAdded);
}
}

View File

@ -0,0 +1,9 @@
using Ocelot.Configuration.File;
namespace Ocelot.Configuration.Creator
{
public interface IQoSOptionsCreator
{
QoSOptions Create(FileReRoute fileReRoute);
}
}

View File

@ -0,0 +1,9 @@
using Ocelot.Configuration.File;
namespace Ocelot.Configuration.Creator
{
public interface IRateLimitOptionsCreator
{
RateLimitOptions Create(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration, bool enableRateLimiting);
}
}

View File

@ -0,0 +1,9 @@
using Ocelot.Configuration.File;
namespace Ocelot.Configuration.Creator
{
public interface IReRouteOptionsCreator
{
ReRouteOptions Create(FileReRoute fileReRoute);
}
}

View File

@ -0,0 +1,9 @@
using Ocelot.Configuration.File;
namespace Ocelot.Configuration.Creator
{
public interface IRequestIdKeyCreator
{
string Create(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration);
}
}

View File

@ -0,0 +1,9 @@
using Ocelot.Configuration.File;
namespace Ocelot.Configuration.Creator
{
public interface IServiceProviderConfigurationCreator
{
ServiceProviderConfiguration Create(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration);
}
}

View File

@ -0,0 +1,9 @@
using Ocelot.Configuration.File;
namespace Ocelot.Configuration.Creator
{
public interface IUpstreamTemplatePatternCreator
{
string Create(FileReRoute reRoute);
}
}

View File

@ -0,0 +1,17 @@
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.File;
namespace Ocelot.Configuration.Creator
{
public class QoSOptionsCreator : IQoSOptionsCreator
{
public QoSOptions Create(FileReRoute fileReRoute)
{
return new QoSOptionsBuilder()
.WithExceptionsAllowedBeforeBreaking(fileReRoute.QoSOptions.ExceptionsAllowedBeforeBreaking)
.WithDurationOfBreak(fileReRoute.QoSOptions.DurationOfBreak)
.WithTimeoutValue(fileReRoute.QoSOptions.TimeoutValue)
.Build();
}
}
}

View File

@ -0,0 +1,32 @@
using System;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.File;
namespace Ocelot.Configuration.Creator
{
public class RateLimitOptionsCreator : IRateLimitOptionsCreator
{
public RateLimitOptions Create(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration, bool enableRateLimiting)
{
RateLimitOptions rateLimitOption = null;
if (enableRateLimiting)
{
rateLimitOption = new RateLimitOptionsBuilder()
.WithClientIdHeader(globalConfiguration.RateLimitOptions.ClientIdHeader)
.WithClientWhiteList(fileReRoute.RateLimitOptions.ClientWhitelist)
.WithDisableRateLimitHeaders(globalConfiguration.RateLimitOptions.DisableRateLimitHeaders)
.WithEnableRateLimiting(fileReRoute.RateLimitOptions.EnableRateLimiting)
.WithHttpStatusCode(globalConfiguration.RateLimitOptions.HttpStatusCode)
.WithQuotaExceededMessage(globalConfiguration.RateLimitOptions.QuotaExceededMessage)
.WithRateLimitCounterPrefix(globalConfiguration.RateLimitOptions.RateLimitCounterPrefix)
.WithRateLimitRule(new RateLimitRule(fileReRoute.RateLimitOptions.Period,
TimeSpan.FromSeconds(fileReRoute.RateLimitOptions.PeriodTimespan),
fileReRoute.RateLimitOptions.Limit))
.Build();
}
return rateLimitOption;
}
}
}

View File

@ -0,0 +1,52 @@
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.File;
namespace Ocelot.Configuration.Creator
{
public class ReRouteOptionsCreator : IReRouteOptionsCreator
{
public ReRouteOptions Create(FileReRoute fileReRoute)
{
var isAuthenticated = IsAuthenticated(fileReRoute);
var isAuthorised = IsAuthorised(fileReRoute);
var isCached = IsCached(fileReRoute);
var isQos = IsQoS(fileReRoute);
var enableRateLimiting = IsEnableRateLimiting(fileReRoute);
var options = new ReRouteOptionsBuilder()
.WithIsAuthenticated(isAuthenticated)
.WithIsAuthorised(isAuthorised)
.WithIsCached(isCached)
.WithIsQos(isQos)
.WithRateLimiting(enableRateLimiting)
.Build();
return options;
}
private static bool IsEnableRateLimiting(FileReRoute fileReRoute)
{
return (fileReRoute.RateLimitOptions != null && fileReRoute.RateLimitOptions.EnableRateLimiting) ? true : false;
}
private bool IsQoS(FileReRoute fileReRoute)
{
return fileReRoute.QoSOptions?.ExceptionsAllowedBeforeBreaking > 0 && fileReRoute.QoSOptions?.TimeoutValue > 0;
}
private bool IsAuthenticated(FileReRoute fileReRoute)
{
return !string.IsNullOrEmpty(fileReRoute.AuthenticationOptions?.Provider);
}
private bool IsAuthorised(FileReRoute fileReRoute)
{
return fileReRoute.RouteClaimsRequirement?.Count > 0;
}
private bool IsCached(FileReRoute fileReRoute)
{
return fileReRoute.FileCacheOptions.TtlSeconds > 0;
}
}
}

View File

@ -0,0 +1,18 @@
using Ocelot.Configuration.File;
namespace Ocelot.Configuration.Creator
{
public class RequestIdKeyCreator : IRequestIdKeyCreator
{
public string Create(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration)
{
var globalRequestIdConfiguration = !string.IsNullOrEmpty(globalConfiguration?.RequestIdKey);
var requestIdKey = globalRequestIdConfiguration
? globalConfiguration.RequestIdKey
: fileReRoute.RequestIdKey;
return requestIdKey;
}
}
}

View File

@ -0,0 +1,26 @@
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.File;
namespace Ocelot.Configuration.Creator
{
public class ServiceProviderConfigurationCreator : IServiceProviderConfigurationCreator
{
public ServiceProviderConfiguration Create(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration)
{
var useServiceDiscovery = !string.IsNullOrEmpty(fileReRoute.ServiceName)
&& !string.IsNullOrEmpty(globalConfiguration?.ServiceDiscoveryProvider?.Provider);
var serviceProviderPort = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0;
return new ServiceProviderConfigurationBuilder()
.WithServiceName(fileReRoute.ServiceName)
.WithDownstreamHost(fileReRoute.DownstreamHost)
.WithDownstreamPort(fileReRoute.DownstreamPort)
.WithUseServiceDiscovery(useServiceDiscovery)
.WithServiceDiscoveryProvider(globalConfiguration?.ServiceDiscoveryProvider?.Provider)
.WithServiceDiscoveryProviderHost(globalConfiguration?.ServiceDiscoveryProvider?.Host)
.WithServiceDiscoveryProviderPort(serviceProviderPort)
.Build();
}
}
}

View File

@ -0,0 +1,56 @@
using System.Collections.Generic;
using Ocelot.Configuration.File;
using Ocelot.Utilities;
namespace Ocelot.Configuration.Creator
{
public class UpstreamTemplatePatternCreator : IUpstreamTemplatePatternCreator
{
private const string RegExMatchEverything = ".*";
private const string RegExMatchEndString = "$";
private const string RegExIgnoreCase = "(?i)";
private const string RegExForwardSlashOnly = "^/$";
public string Create(FileReRoute reRoute)
{
var upstreamTemplate = reRoute.UpstreamPathTemplate;
upstreamTemplate = upstreamTemplate.SetLastCharacterAs('/');
var placeholders = new List<string>();
for (var i = 0; i < upstreamTemplate.Length; i++)
{
if (IsPlaceHolder(upstreamTemplate, i))
{
var postitionOfPlaceHolderClosingBracket = upstreamTemplate.IndexOf('}', i);
var difference = postitionOfPlaceHolderClosingBracket - i + 1;
var variableName = upstreamTemplate.Substring(i, difference);
placeholders.Add(variableName);
}
}
foreach (var placeholder in placeholders)
{
upstreamTemplate = upstreamTemplate.Replace(placeholder, RegExMatchEverything);
}
if (upstreamTemplate == "/")
{
return RegExForwardSlashOnly;
}
var route = reRoute.ReRouteIsCaseSensitive
? $"{upstreamTemplate}{RegExMatchEndString}"
: $"{RegExIgnoreCase}{upstreamTemplate}{RegExMatchEndString}";
return route;
}
private bool IsPlaceHolder(string upstreamTemplate, int i)
{
return upstreamTemplate[i] == '{';
}
}
}

View File

@ -25,7 +25,7 @@ namespace Ocelot.Configuration
string downstreamHost, string downstreamHost,
int downstreamPort, int downstreamPort,
string reRouteKey, string reRouteKey,
ServiceProviderConfiguraion serviceProviderConfiguraion, ServiceProviderConfiguration serviceProviderConfiguraion,
bool isQos, bool isQos,
QoSOptions qos, QoSOptions qos,
bool enableRateLimit, bool enableRateLimit,
@ -81,7 +81,7 @@ 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 ServiceProviderConfiguraion ServiceProviderConfiguraion { get; private set; } public ServiceProviderConfiguration ServiceProviderConfiguraion { get; private set; }
public bool EnableEndpointRateLimiting { get; private set; } public bool EnableEndpointRateLimiting { get; private set; }
public RateLimitOptions RateLimitOptions { get; private set; } public RateLimitOptions RateLimitOptions { get; private set; }
} }

View File

@ -0,0 +1,20 @@
namespace Ocelot.Configuration
{
public class ReRouteOptions
{
public ReRouteOptions(bool isAuthenticated, bool isAuthorised, bool isCached, bool isQos, bool isEnableRateLimiting)
{
IsAuthenticated = isAuthenticated;
IsAuthorised = isAuthorised;
IsCached = isCached;
IsQos = isQos;
EnableRateLimiting = isEnableRateLimiting;
}
public bool IsAuthenticated { get; private set; }
public bool IsAuthorised { get; private set; }
public bool IsCached { get; private set; }
public bool IsQos { get; private set; }
public bool EnableRateLimiting { get; private set; }
}
}

View File

@ -1,8 +1,8 @@
namespace Ocelot.Configuration namespace Ocelot.Configuration
{ {
public class ServiceProviderConfiguraion public class ServiceProviderConfiguration
{ {
public ServiceProviderConfiguraion(string serviceName, string downstreamHost, public ServiceProviderConfiguration(string serviceName, string downstreamHost,
int downstreamPort, bool useServiceDiscovery, string serviceDiscoveryProvider, string serviceProviderHost, int serviceProviderPort) int downstreamPort, bool useServiceDiscovery, string serviceDiscoveryProvider, string serviceProviderHost, int serviceProviderPort)
{ {
ServiceName = serviceName; ServiceName = serviceName;

View File

@ -60,6 +60,14 @@ namespace Ocelot.DependencyInjection
services.AddSingleton<IOcelotConfigurationRepository, InMemoryOcelotConfigurationRepository>(); services.AddSingleton<IOcelotConfigurationRepository, InMemoryOcelotConfigurationRepository>();
services.AddSingleton<IConfigurationValidator, FileConfigurationValidator>(); services.AddSingleton<IConfigurationValidator, FileConfigurationValidator>();
services.AddSingleton<IBaseUrlFinder, BaseUrlFinder>(); services.AddSingleton<IBaseUrlFinder, BaseUrlFinder>();
services.AddSingleton<IClaimsToThingCreator, ClaimsToThingCreator>();
services.AddSingleton<IAuthenticationOptionsCreator, AuthenticationOptionsCreator>();
services.AddSingleton<IUpstreamTemplatePatternCreator, UpstreamTemplatePatternCreator>();
services.AddSingleton<IRequestIdKeyCreator, RequestIdKeyCreator>();
services.AddSingleton<IServiceProviderConfigurationCreator,ServiceProviderConfigurationCreator>();
services.AddSingleton<IQoSOptionsCreator, QoSOptionsCreator>();
services.AddSingleton<IReRouteOptionsCreator, ReRouteOptionsCreator>();
services.AddSingleton<IRateLimitOptionsCreator, RateLimitOptionsCreator>();
var identityServerConfiguration = IdentityServerConfigurationCreator.GetIdentityServerConfiguration(); var identityServerConfiguration = IdentityServerConfigurationCreator.GetIdentityServerConfiguration();

View File

@ -1,10 +1,9 @@
using System;
using Ocelot.Configuration; using Ocelot.Configuration;
namespace Ocelot.ServiceDiscovery namespace Ocelot.ServiceDiscovery
{ {
public interface IServiceDiscoveryProviderFactory public interface IServiceDiscoveryProviderFactory
{ {
IServiceDiscoveryProvider Get(ServiceProviderConfiguraion serviceConfig); IServiceDiscoveryProvider Get(ServiceProviderConfiguration serviceConfig);
} }
} }

View File

@ -6,7 +6,7 @@ namespace Ocelot.ServiceDiscovery
{ {
public class ServiceDiscoveryProviderFactory : IServiceDiscoveryProviderFactory public class ServiceDiscoveryProviderFactory : IServiceDiscoveryProviderFactory
{ {
public IServiceDiscoveryProvider Get(ServiceProviderConfiguraion serviceConfig) public IServiceDiscoveryProvider Get(ServiceProviderConfiguration serviceConfig)
{ {
if (serviceConfig.UseServiceDiscovery) if (serviceConfig.UseServiceDiscovery)
{ {

View File

@ -0,0 +1,74 @@
using System.Collections.Generic;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration
{
public class AuthenticationOptionsCreatorTests
{
private AuthenticationOptionsCreator _authOptionsCreator;
private FileReRoute _fileReRoute;
private AuthenticationOptions _result;
public AuthenticationOptionsCreatorTests()
{
_authOptionsCreator = new AuthenticationOptionsCreator();
}
[Fact]
public void should_return_auth_options()
{
var fileReRoute = new FileReRoute()
{
AuthenticationOptions = new FileAuthenticationOptions
{
Provider = "Geoff",
ProviderRootUrl = "http://www.bbc.co.uk/",
ScopeName = "Laura",
RequireHttps = true,
AdditionalScopes = new List<string> {"cheese"},
ScopeSecret = "secret"
}
};
var expected = new AuthenticationOptionsBuilder()
.WithProvider(fileReRoute.AuthenticationOptions?.Provider)
.WithProviderRootUrl(fileReRoute.AuthenticationOptions?.ProviderRootUrl)
.WithScopeName(fileReRoute.AuthenticationOptions?.ScopeName)
.WithRequireHttps(fileReRoute.AuthenticationOptions.RequireHttps)
.WithAdditionalScopes(fileReRoute.AuthenticationOptions?.AdditionalScopes)
.WithScopeSecret(fileReRoute.AuthenticationOptions?.ScopeSecret)
.Build();
this.Given(x => x.GivenTheFollowing(fileReRoute))
.When(x => x.WhenICreateTheAuthenticationOptions())
.Then(x => x.ThenTheFollowingIsReturned(expected))
.BDDfy();
}
private void GivenTheFollowing(FileReRoute fileReRoute)
{
_fileReRoute = fileReRoute;
}
private void WhenICreateTheAuthenticationOptions()
{
_result = _authOptionsCreator.Create(_fileReRoute);
}
private void ThenTheFollowingIsReturned(AuthenticationOptions expected)
{
_result.AdditionalScopes.ShouldBe(expected.AdditionalScopes);
_result.Provider.ShouldBe(expected.Provider);
_result.ProviderRootUrl.ShouldBe(expected.ProviderRootUrl);
_result.RequireHttps.ShouldBe(expected.RequireHttps);
_result.ScopeName.ShouldBe(expected.ScopeName);
_result.ScopeSecret.ShouldBe(expected.ScopeSecret);
}
}
}

View File

@ -0,0 +1,110 @@
using System.Collections.Generic;
using System.Linq;
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.Parser;
using Ocelot.Errors;
using Ocelot.Logging;
using Ocelot.Responses;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration
{
public class ClaimsToThingCreatorTests
{
private readonly Mock<IClaimToThingConfigurationParser> _configParser;
private Dictionary<string,string> _claimsToThings;
private ClaimsToThingCreator _claimsToThingsCreator;
private Mock<IOcelotLoggerFactory> _loggerFactory;
private List<ClaimToThing> _result;
private Mock<IOcelotLogger> _logger;
public ClaimsToThingCreatorTests()
{
_loggerFactory = new Mock<IOcelotLoggerFactory>();
_logger = new Mock<IOcelotLogger>();
_loggerFactory
.Setup(x => x.CreateLogger<ClaimsToThingCreator>())
.Returns(_logger.Object);
_configParser = new Mock<IClaimToThingConfigurationParser>();
_claimsToThingsCreator = new ClaimsToThingCreator(_configParser.Object, _loggerFactory.Object);
}
[Fact]
public void should_return_claims_to_things()
{
var userInput = new Dictionary<string,string>()
{
{"CustomerId", "Claims[CustomerId] > value"}
};
var claimsToThing = new OkResponse<ClaimToThing>(new ClaimToThing("CustomerId", "CustomerId", "", 0));
this.Given(x => x.GivenTheFollowingDictionary(userInput))
.And(x => x.GivenTheConfigHeaderExtractorReturns(claimsToThing))
.When(x => x.WhenIGetTheThings())
.Then(x => x.ThenTheConfigParserIsCalledCorrectly())
.And(x => x.ThenClaimsToThingsAreReturned())
.BDDfy();
}
[Fact]
public void should_log_error_if_cannot_parse_claim_to_thing()
{
var userInput = new Dictionary<string,string>()
{
{"CustomerId", "Claims[CustomerId] > value"}
};
var claimsToThing = new ErrorResponse<ClaimToThing>(It.IsAny<Error>());
this.Given(x => x.GivenTheFollowingDictionary(userInput))
.And(x => x.GivenTheConfigHeaderExtractorReturns(claimsToThing))
.When(x => x.WhenIGetTheThings())
.Then(x => x.ThenTheConfigParserIsCalledCorrectly())
.And(x => x.ThenNoClaimsToThingsAreReturned())
.BDDfy();
}
private void ThenTheLoggerIsCalledCorrectly()
{
_logger
.Verify(x => x.LogDebug(It.IsAny<string>(), It.IsAny<string>()), Times.Once);
}
private void ThenClaimsToThingsAreReturned()
{
_result.Count.ShouldBeGreaterThan(0);
}
private void GivenTheFollowingDictionary(Dictionary<string,string> claimsToThings)
{
_claimsToThings = claimsToThings;
}
private void GivenTheConfigHeaderExtractorReturns(Response<ClaimToThing> expected)
{
_configParser
.Setup(x => x.Extract(It.IsAny<string>(), It.IsAny<string>()))
.Returns(expected);
}
private void ThenNoClaimsToThingsAreReturned()
{
_result.Count.ShouldBe(0);
}
private void WhenIGetTheThings()
{
_result = _claimsToThingsCreator.Create(_claimsToThings);
}
private void ThenTheConfigParserIsCalledCorrectly()
{
_configParser
.Verify(x => x.Extract(_claimsToThings.First().Key, _claimsToThings.First().Value), Times.Once);
}
}
}

View File

@ -6,7 +6,6 @@ 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 Ocelot.Configuration.Parser;
using Ocelot.Configuration.Validator; using Ocelot.Configuration.Validator;
using Ocelot.LoadBalancer.LoadBalancers; using Ocelot.LoadBalancer.LoadBalancers;
using Ocelot.Requester.QoS; using Ocelot.Requester.QoS;
@ -23,7 +22,6 @@ namespace Ocelot.UnitTests.Configuration
private readonly Mock<IConfigurationValidator> _validator; private readonly Mock<IConfigurationValidator> _validator;
private Response<IOcelotConfiguration> _config; private Response<IOcelotConfiguration> _config;
private FileConfiguration _fileConfiguration; private FileConfiguration _fileConfiguration;
private readonly Mock<IClaimToThingConfigurationParser> _configParser;
private readonly Mock<ILogger<FileOcelotConfigurationCreator>> _logger; private readonly Mock<ILogger<FileOcelotConfigurationCreator>> _logger;
private readonly FileOcelotConfigurationCreator _ocelotConfigurationCreator; private readonly FileOcelotConfigurationCreator _ocelotConfigurationCreator;
private readonly Mock<ILoadBalancerFactory> _loadBalancerFactory; private readonly Mock<ILoadBalancerFactory> _loadBalancerFactory;
@ -32,6 +30,14 @@ namespace Ocelot.UnitTests.Configuration
private readonly Mock<IQoSProviderFactory> _qosProviderFactory; private readonly Mock<IQoSProviderFactory> _qosProviderFactory;
private readonly Mock<IQosProviderHouse> _qosProviderHouse; private readonly Mock<IQosProviderHouse> _qosProviderHouse;
private readonly Mock<IQoSProvider> _qosProvider; private readonly Mock<IQoSProvider> _qosProvider;
private Mock<IClaimsToThingCreator> _claimsToThingCreator;
private Mock<IAuthenticationOptionsCreator> _authOptionsCreator;
private Mock<IUpstreamTemplatePatternCreator> _upstreamTemplatePatternCreator;
private Mock<IRequestIdKeyCreator> _requestIdKeyCreator;
private Mock<IServiceProviderConfigurationCreator> _serviceProviderConfigCreator;
private Mock<IQoSOptionsCreator> _qosOptionsCreator;
private Mock<IReRouteOptionsCreator> _fileReRouteOptionsCreator;
private Mock<IRateLimitOptionsCreator> _rateLimitOptions;
public FileConfigurationCreatorTests() public FileConfigurationCreatorTests()
{ {
@ -39,46 +45,69 @@ namespace Ocelot.UnitTests.Configuration
_qosProviderHouse = new Mock<IQosProviderHouse>(); _qosProviderHouse = new Mock<IQosProviderHouse>();
_qosProvider = new Mock<IQoSProvider>(); _qosProvider = new Mock<IQoSProvider>();
_logger = new Mock<ILogger<FileOcelotConfigurationCreator>>(); _logger = new Mock<ILogger<FileOcelotConfigurationCreator>>();
_configParser = new Mock<IClaimToThingConfigurationParser>();
_validator = new Mock<IConfigurationValidator>(); _validator = new Mock<IConfigurationValidator>();
_fileConfig = new Mock<IOptions<FileConfiguration>>(); _fileConfig = new Mock<IOptions<FileConfiguration>>();
_loadBalancerFactory = new Mock<ILoadBalancerFactory>(); _loadBalancerFactory = new Mock<ILoadBalancerFactory>();
_loadBalancerHouse = new Mock<ILoadBalancerHouse>(); _loadBalancerHouse = new Mock<ILoadBalancerHouse>();
_loadBalancer = new Mock<ILoadBalancer>(); _loadBalancer = new Mock<ILoadBalancer>();
_claimsToThingCreator = new Mock<IClaimsToThingCreator>();
_authOptionsCreator = new Mock<IAuthenticationOptionsCreator>();
_upstreamTemplatePatternCreator = new Mock<IUpstreamTemplatePatternCreator>();
_requestIdKeyCreator = new Mock<IRequestIdKeyCreator>();
_serviceProviderConfigCreator = new Mock<IServiceProviderConfigurationCreator>();
_qosOptionsCreator = new Mock<IQoSOptionsCreator>();
_fileReRouteOptionsCreator = new Mock<IReRouteOptionsCreator>();
_rateLimitOptions = new Mock<IRateLimitOptionsCreator>();
_ocelotConfigurationCreator = new FileOcelotConfigurationCreator( _ocelotConfigurationCreator = new FileOcelotConfigurationCreator(
_fileConfig.Object, _validator.Object, _configParser.Object, _logger.Object, _fileConfig.Object, _validator.Object, _logger.Object,
_loadBalancerFactory.Object, _loadBalancerHouse.Object, _loadBalancerFactory.Object, _loadBalancerHouse.Object,
_qosProviderFactory.Object, _qosProviderHouse.Object); _qosProviderFactory.Object, _qosProviderHouse.Object, _claimsToThingCreator.Object,
_authOptionsCreator.Object, _upstreamTemplatePatternCreator.Object, _requestIdKeyCreator.Object,
_serviceProviderConfigCreator.Object, _qosOptionsCreator.Object, _fileReRouteOptionsCreator.Object,
_rateLimitOptions.Object);
} }
[Fact] [Fact]
public void should_create_load_balancer() public void should_call_rate_limit_options_creator()
{ {
var reRouteOptions = new ReRouteOptionsBuilder()
.Build();
this.Given(x => x.GivenTheConfigIs(new FileConfiguration this.Given(x => x.GivenTheConfigIs(new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{ {
ReRoutes = new List<FileReRoute> new FileReRoute
{ {
new FileReRoute DownstreamHost = "127.0.0.1",
{ UpstreamPathTemplate = "/api/products/{productId}",
DownstreamHost = "127.0.0.1", DownstreamPathTemplate = "/products/{productId}",
UpstreamPathTemplate = "/api/products/{productId}", UpstreamHttpMethod = "Get",
DownstreamPathTemplate = "/products/{productId}", }
UpstreamHttpMethod = "Get", },
} }))
}, .And(x => x.GivenTheConfigIsValid())
})) .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
.And(x => x.GivenTheConfigIsValid()) .When(x => x.WhenICreateTheConfig())
.And(x => x.GivenTheLoadBalancerFactoryReturns()) .Then(x => x.ThenTheRateLimitOptionsCreatorIsCalledCorrectly())
.When(x => x.WhenICreateTheConfig()) .BDDfy();
.Then(x => x.TheLoadBalancerFactoryIsCalledCorrectly())
.And(x => x.ThenTheLoadBalancerHouseIsCalledCorrectly())
.BDDfy();
} }
[Fact] [Fact]
public void should_create_qos_provider() public void should_call_qos_options_creator()
{ {
this.Given(x => x.GivenTheConfigIs(new FileConfiguration var expected = new QoSOptionsBuilder()
.WithDurationOfBreak(1)
.WithExceptionsAllowedBeforeBreaking(1)
.WithTimeoutValue(1)
.Build();
var serviceOptions = new ReRouteOptionsBuilder()
.WithIsQos(true)
.Build();
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
{ {
ReRoutes = new List<FileReRoute> ReRoutes = new List<FileReRoute>
{ {
@ -98,17 +127,23 @@ namespace Ocelot.UnitTests.Configuration
}, },
})) }))
.And(x => x.GivenTheConfigIsValid()) .And(x => x.GivenTheConfigIsValid())
.And(x => x.GivenTheFollowingOptionsAreReturned(serviceOptions))
.And(x => x.GivenTheQosProviderFactoryReturns()) .And(x => x.GivenTheQosProviderFactoryReturns())
.And(x => x.GivenTheQosOptionsCreatorReturns(expected))
.When(x => x.WhenICreateTheConfig()) .When(x => x.WhenICreateTheConfig())
.Then(x => x.TheQosProviderFactoryIsCalledCorrectly()) .Then(x => x.ThenTheQosOptionsAre(expected))
.And(x => x.TheQosProviderFactoryIsCalledCorrectly())
.And(x => x.ThenTheQosProviderHouseIsCalledCorrectly()) .And(x => x.ThenTheQosProviderHouseIsCalledCorrectly())
.BDDfy(); .BDDfy();
} }
[Fact] [Fact]
public void should_use_downstream_host() public void should_create_load_balancer()
{ {
this.Given(x => x.GivenTheConfigIs(new FileConfiguration var reRouteOptions = new ReRouteOptionsBuilder()
.Build();
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
{ {
ReRoutes = new List<FileReRoute> ReRoutes = new List<FileReRoute>
{ {
@ -122,23 +157,54 @@ namespace Ocelot.UnitTests.Configuration
}, },
})) }))
.And(x => x.GivenTheConfigIsValid()) .And(x => x.GivenTheConfigIsValid())
.And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
.And(x => x.GivenTheLoadBalancerFactoryReturns())
.When(x => x.WhenICreateTheConfig()) .When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheReRoutesAre(new List<ReRoute> .Then(x => x.TheLoadBalancerFactoryIsCalledCorrectly())
{ .And(x => x.ThenTheLoadBalancerHouseIsCalledCorrectly())
new ReRouteBuilder()
.WithDownstreamHost("127.0.0.1")
.WithDownstreamPathTemplate("/products/{productId}")
.WithUpstreamPathTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod("Get")
.WithUpstreamTemplatePattern("(?i)/api/products/.*/$")
.Build()
}))
.BDDfy(); .BDDfy();
} }
[Fact]
public void should_use_downstream_host()
{
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 = "Get",
}
},
}))
.And(x => x.GivenTheConfigIsValid())
.And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
.When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheReRoutesAre(new List<ReRoute>
{
new ReRouteBuilder()
.WithDownstreamHost("127.0.0.1")
.WithDownstreamPathTemplate("/products/{productId}")
.WithUpstreamPathTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod("Get")
.Build()
}))
.BDDfy();
}
[Fact] [Fact]
public void should_use_downstream_scheme() public void should_use_downstream_scheme()
{ {
var reRouteOptions = new ReRouteOptionsBuilder()
.Build();
this.Given(x => x.GivenTheConfigIs(new FileConfiguration this.Given(x => x.GivenTheConfigIs(new FileConfiguration
{ {
ReRoutes = new List<FileReRoute> ReRoutes = new List<FileReRoute>
@ -153,6 +219,7 @@ namespace Ocelot.UnitTests.Configuration
}, },
})) }))
.And(x => x.GivenTheConfigIsValid()) .And(x => x.GivenTheConfigIsValid())
.And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
.When(x => x.WhenICreateTheConfig()) .When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheReRoutesAre(new List<ReRoute> .Then(x => x.ThenTheReRoutesAre(new List<ReRoute>
{ {
@ -161,7 +228,6 @@ namespace Ocelot.UnitTests.Configuration
.WithDownstreamPathTemplate("/products/{productId}") .WithDownstreamPathTemplate("/products/{productId}")
.WithUpstreamPathTemplate("/api/products/{productId}") .WithUpstreamPathTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod("Get") .WithUpstreamHttpMethod("Get")
.WithUpstreamTemplatePattern("(?i)/api/products/.*/$")
.Build() .Build()
})) }))
.BDDfy(); .BDDfy();
@ -170,6 +236,9 @@ namespace Ocelot.UnitTests.Configuration
[Fact] [Fact]
public void should_use_service_discovery_for_downstream_service_host() public void should_use_service_discovery_for_downstream_service_host()
{ {
var reRouteOptions = new ReRouteOptionsBuilder()
.Build();
this.Given(x => x.GivenTheConfigIs(new FileConfiguration this.Given(x => x.GivenTheConfigIs(new FileConfiguration
{ {
ReRoutes = new List<FileReRoute> ReRoutes = new List<FileReRoute>
@ -193,6 +262,7 @@ namespace Ocelot.UnitTests.Configuration
} }
})) }))
.And(x => x.GivenTheConfigIsValid()) .And(x => x.GivenTheConfigIsValid())
.And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
.When(x => x.WhenICreateTheConfig()) .When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheReRoutesAre(new List<ReRoute> .Then(x => x.ThenTheReRoutesAre(new List<ReRoute>
{ {
@ -200,8 +270,7 @@ namespace Ocelot.UnitTests.Configuration
.WithDownstreamPathTemplate("/products/{productId}") .WithDownstreamPathTemplate("/products/{productId}")
.WithUpstreamPathTemplate("/api/products/{productId}") .WithUpstreamPathTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod("Get") .WithUpstreamHttpMethod("Get")
.WithUpstreamTemplatePattern("(?i)/api/products/.*/$") .WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder()
.WithServiceProviderConfiguraion(new ServiceProviderConfiguraionBuilder()
.WithUseServiceDiscovery(true) .WithUseServiceDiscovery(true)
.WithServiceDiscoveryProvider("consul") .WithServiceDiscoveryProvider("consul")
.WithServiceDiscoveryProviderHost("127.0.0.1") .WithServiceDiscoveryProviderHost("127.0.0.1")
@ -215,6 +284,9 @@ namespace Ocelot.UnitTests.Configuration
[Fact] [Fact]
public void should_not_use_service_discovery_for_downstream_host_url_when_no_service_name() public void should_not_use_service_discovery_for_downstream_host_url_when_no_service_name()
{ {
var reRouteOptions = new ReRouteOptionsBuilder()
.Build();
this.Given(x => x.GivenTheConfigIs(new FileConfiguration this.Given(x => x.GivenTheConfigIs(new FileConfiguration
{ {
ReRoutes = new List<FileReRoute> ReRoutes = new List<FileReRoute>
@ -229,6 +301,7 @@ namespace Ocelot.UnitTests.Configuration
} }
})) }))
.And(x => x.GivenTheConfigIsValid()) .And(x => x.GivenTheConfigIsValid())
.And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
.When(x => x.WhenICreateTheConfig()) .When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheReRoutesAre(new List<ReRoute> .Then(x => x.ThenTheReRoutesAre(new List<ReRoute>
{ {
@ -236,8 +309,7 @@ namespace Ocelot.UnitTests.Configuration
.WithDownstreamPathTemplate("/products/{productId}") .WithDownstreamPathTemplate("/products/{productId}")
.WithUpstreamPathTemplate("/api/products/{productId}") .WithUpstreamPathTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod("Get") .WithUpstreamHttpMethod("Get")
.WithUpstreamTemplatePattern("(?i)/api/products/.*/$") .WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder()
.WithServiceProviderConfiguraion(new ServiceProviderConfiguraionBuilder()
.WithUseServiceDiscovery(false) .WithUseServiceDiscovery(false)
.Build()) .Build())
.Build() .Build()
@ -246,8 +318,11 @@ namespace Ocelot.UnitTests.Configuration
} }
[Fact] [Fact]
public void should_use_reroute_case_sensitivity_value() public void should_call_template_pattern_creator_correctly()
{ {
var reRouteOptions = new ReRouteOptionsBuilder()
.Build();
this.Given(x => x.GivenTheConfigIs(new FileConfiguration this.Given(x => x.GivenTheConfigIs(new FileConfiguration
{ {
ReRoutes = new List<FileReRoute> ReRoutes = new List<FileReRoute>
@ -262,6 +337,8 @@ namespace Ocelot.UnitTests.Configuration
} }
})) }))
.And(x => x.GivenTheConfigIsValid()) .And(x => x.GivenTheConfigIsValid())
.And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
.And(x => x.GivenTheUpstreamTemplatePatternCreatorReturns("(?i)/api/products/.*/$"))
.When(x => x.WhenICreateTheConfig()) .When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheReRoutesAre(new List<ReRoute> .Then(x => x.ThenTheReRoutesAre(new List<ReRoute>
{ {
@ -276,67 +353,11 @@ namespace Ocelot.UnitTests.Configuration
} }
[Fact] [Fact]
public void should_set_upstream_template_pattern_to_ignore_case_sensitivity() public void should_call_request_id_creator()
{ {
this.Given(x => x.GivenTheConfigIs(new FileConfiguration var reRouteOptions = new ReRouteOptionsBuilder()
{ .Build();
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
UpstreamPathTemplate = "/api/products/{productId}",
DownstreamPathTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get"
}
}
}))
.And(x => x.GivenTheConfigIsValid())
.When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheReRoutesAre(new List<ReRoute>
{
new ReRouteBuilder()
.WithDownstreamPathTemplate("/products/{productId}")
.WithUpstreamPathTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod("Get")
.WithUpstreamTemplatePattern("(?i)/api/products/.*/$")
.Build()
}))
.BDDfy();
}
[Fact]
public void should_set_upstream_template_pattern_to_respect_case_sensitivity()
{
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
UpstreamPathTemplate = "/api/products/{productId}",
DownstreamPathTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true
}
}
}))
.And(x => x.GivenTheConfigIsValid())
.When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheReRoutesAre(new List<ReRoute>
{
new ReRouteBuilder()
.WithDownstreamPathTemplate("/products/{productId}")
.WithUpstreamPathTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod("Get")
.WithUpstreamTemplatePattern("/api/products/.*/$")
.Build()
}))
.BDDfy();
}
[Fact]
public void should_set_global_request_id_key()
{
this.Given(x => x.GivenTheConfigIs(new FileConfiguration this.Given(x => x.GivenTheConfigIs(new FileConfiguration
{ {
ReRoutes = new List<FileReRoute> ReRoutes = new List<FileReRoute>
@ -355,6 +376,8 @@ namespace Ocelot.UnitTests.Configuration
} }
})) }))
.And(x => x.GivenTheConfigIsValid()) .And(x => x.GivenTheConfigIsValid())
.And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
.And(x => x.GivenTheRequestIdCreatorReturns("blahhhh"))
.When(x => x.WhenICreateTheConfig()) .When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheReRoutesAre(new List<ReRoute> .Then(x => x.ThenTheReRoutesAre(new List<ReRoute>
{ {
@ -362,46 +385,20 @@ namespace Ocelot.UnitTests.Configuration
.WithDownstreamPathTemplate("/products/{productId}") .WithDownstreamPathTemplate("/products/{productId}")
.WithUpstreamPathTemplate("/api/products/{productId}") .WithUpstreamPathTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod("Get") .WithUpstreamHttpMethod("Get")
.WithUpstreamTemplatePattern("/api/products/.*/$")
.WithRequestIdKey("blahhhh") .WithRequestIdKey("blahhhh")
.Build() .Build()
})) }))
.BDDfy(); .And(x => x.ThenTheRequestIdKeyCreatorIsCalledCorrectly())
}
[Fact]
public void should_create_template_pattern_that_matches_anything_to_end_of_string()
{
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
UpstreamPathTemplate = "/api/products/{productId}",
DownstreamPathTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true
}
}
}))
.And(x => x.GivenTheConfigIsValid())
.When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheReRoutesAre(new List<ReRoute>
{
new ReRouteBuilder()
.WithDownstreamPathTemplate("/products/{productId}")
.WithUpstreamPathTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod("Get")
.WithUpstreamTemplatePattern("/api/products/.*/$")
.Build()
}))
.BDDfy(); .BDDfy();
} }
[Fact] [Fact]
public void should_create_with_headers_to_extract() public void should_create_with_headers_to_extract()
{ {
var reRouteOptions = new ReRouteOptionsBuilder()
.WithIsAuthenticated(true)
.Build();
var authenticationOptions = new AuthenticationOptionsBuilder() var authenticationOptions = new AuthenticationOptionsBuilder()
.WithProvider("IdentityServer") .WithProvider("IdentityServer")
.WithProviderRootUrl("http://localhost:51888") .WithProviderRootUrl("http://localhost:51888")
@ -417,7 +414,6 @@ namespace Ocelot.UnitTests.Configuration
.WithDownstreamPathTemplate("/products/{productId}") .WithDownstreamPathTemplate("/products/{productId}")
.WithUpstreamPathTemplate("/api/products/{productId}") .WithUpstreamPathTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod("Get") .WithUpstreamHttpMethod("Get")
.WithUpstreamTemplatePattern("/api/products/.*/$")
.WithAuthenticationOptions(authenticationOptions) .WithAuthenticationOptions(authenticationOptions)
.WithClaimsToHeaders(new List<ClaimToThing> .WithClaimsToHeaders(new List<ClaimToThing>
{ {
@ -453,24 +449,24 @@ namespace Ocelot.UnitTests.Configuration
} }
})) }))
.And(x => x.GivenTheConfigIsValid()) .And(x => x.GivenTheConfigIsValid())
.And(x => x.GivenTheConfigHeaderExtractorReturns(new ClaimToThing("CustomerId", "CustomerId", "", 0))) .And(x => x.GivenTheAuthOptionsCreatorReturns(authenticationOptions))
.And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
.And(x => x.GivenTheClaimsToThingCreatorReturns(new List<ClaimToThing>{new ClaimToThing("CustomerId", "CustomerId", "", 0)}))
.And(x => x.GivenTheLoadBalancerFactoryReturns()) .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))
.And(x => x.ThenTheAuthOptionsCreatorIsCalledCorrectly())
.BDDfy(); .BDDfy();
} }
private void GivenTheConfigHeaderExtractorReturns(ClaimToThing expected)
{
_configParser
.Setup(x => x.Extract(It.IsAny<string>(), It.IsAny<string>()))
.Returns(new OkResponse<ClaimToThing>(expected));
}
[Fact] [Fact]
public void should_create_with_authentication_properties() public void should_create_with_authentication_properties()
{ {
var reRouteOptions = new ReRouteOptionsBuilder()
.WithIsAuthenticated(true)
.Build();
var authenticationOptions = new AuthenticationOptionsBuilder() var authenticationOptions = new AuthenticationOptionsBuilder()
.WithProvider("IdentityServer") .WithProvider("IdentityServer")
.WithProviderRootUrl("http://localhost:51888") .WithProviderRootUrl("http://localhost:51888")
@ -486,7 +482,6 @@ namespace Ocelot.UnitTests.Configuration
.WithDownstreamPathTemplate("/products/{productId}") .WithDownstreamPathTemplate("/products/{productId}")
.WithUpstreamPathTemplate("/api/products/{productId}") .WithUpstreamPathTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod("Get") .WithUpstreamHttpMethod("Get")
.WithUpstreamTemplatePattern("/api/products/.*/$")
.WithAuthenticationOptions(authenticationOptions) .WithAuthenticationOptions(authenticationOptions)
.Build() .Build()
}; };
@ -514,101 +509,27 @@ namespace Ocelot.UnitTests.Configuration
} }
})) }))
.And(x => x.GivenTheConfigIsValid()) .And(x => x.GivenTheConfigIsValid())
.And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
.And(x => x.GivenTheAuthOptionsCreatorReturns(authenticationOptions))
.And(x => x.GivenTheLoadBalancerFactoryReturns()) .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))
.And(x => x.ThenTheAuthOptionsCreatorIsCalledCorrectly())
.BDDfy(); .BDDfy();
} }
[Fact] private void GivenTheFollowingOptionsAreReturned(ReRouteOptions fileReRouteOptions)
public void should_create_template_pattern_that_matches_more_than_one_placeholder()
{ {
this.Given(x => x.GivenTheConfigIs(new FileConfiguration _fileReRouteOptionsCreator
{ .Setup(x => x.Create(It.IsAny<FileReRoute>()))
ReRoutes = new List<FileReRoute> .Returns(fileReRouteOptions);
{
new FileReRoute
{
UpstreamPathTemplate = "/api/products/{productId}/variants/{variantId}",
DownstreamPathTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true
}
}
}))
.And(x => x.GivenTheConfigIsValid())
.When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheReRoutesAre(new List<ReRoute>
{
new ReRouteBuilder()
.WithDownstreamPathTemplate("/products/{productId}")
.WithUpstreamPathTemplate("/api/products/{productId}/variants/{variantId}")
.WithUpstreamHttpMethod("Get")
.WithUpstreamTemplatePattern("/api/products/.*/variants/.*/$")
.Build()
}))
.BDDfy();
} }
[Fact] private void ThenTheRateLimitOptionsCreatorIsCalledCorrectly()
public void should_create_template_pattern_that_matches_more_than_one_placeholder_with_trailing_slash()
{ {
this.Given(x => x.GivenTheConfigIs(new FileConfiguration _rateLimitOptions
{ .Verify(x => x.Create(It.IsAny<FileReRoute>(), It.IsAny<FileGlobalConfiguration>(), It.IsAny<bool>()), Times.Once);
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
UpstreamPathTemplate = "/api/products/{productId}/variants/{variantId}/",
DownstreamPathTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true
}
}
}))
.And(x => x.GivenTheConfigIsValid())
.When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheReRoutesAre(new List<ReRoute>
{
new ReRouteBuilder()
.WithDownstreamPathTemplate("/products/{productId}")
.WithUpstreamPathTemplate("/api/products/{productId}/variants/{variantId}/")
.WithUpstreamHttpMethod("Get")
.WithUpstreamTemplatePattern("/api/products/.*/variants/.*/$")
.Build()
}))
.BDDfy();
}
[Fact]
public void should_create_template_pattern_that_matches_to_end_of_string()
{
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
UpstreamPathTemplate = "/",
DownstreamPathTemplate = "/api/products/",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true
}
}
}))
.And(x => x.GivenTheConfigIsValid())
.When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheReRoutesAre(new List<ReRoute>
{
new ReRouteBuilder()
.WithDownstreamPathTemplate("/api/products/")
.WithUpstreamPathTemplate("/")
.WithUpstreamHttpMethod("Get")
.WithUpstreamTemplatePattern("^/$")
.Build()
}))
.BDDfy();
} }
private void GivenTheConfigIsValid() private void GivenTheConfigIsValid()
@ -642,6 +563,25 @@ namespace Ocelot.UnitTests.Configuration
result.UpstreamHttpMethod.ShouldBe(expected.UpstreamHttpMethod); result.UpstreamHttpMethod.ShouldBe(expected.UpstreamHttpMethod);
result.UpstreamPathTemplate.Value.ShouldBe(expected.UpstreamPathTemplate.Value); result.UpstreamPathTemplate.Value.ShouldBe(expected.UpstreamPathTemplate.Value);
result.UpstreamTemplatePattern.ShouldBe(expected.UpstreamTemplatePattern); result.UpstreamTemplatePattern.ShouldBe(expected.UpstreamTemplatePattern);
result.ClaimsToClaims.Count.ShouldBe(expected.ClaimsToClaims.Count);
result.ClaimsToHeaders.Count.ShouldBe(expected.ClaimsToHeaders.Count);
result.ClaimsToQueries.Count.ShouldBe(expected.ClaimsToQueries.Count);
result.RequestIdKey.ShouldBe(expected.RequestIdKey);
}
}
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);
} }
} }
@ -699,5 +639,60 @@ namespace Ocelot.UnitTests.Configuration
_qosProviderHouse _qosProviderHouse
.Verify(x => x.Add(It.IsAny<string>(), _qosProvider.Object), Times.Once); .Verify(x => x.Add(It.IsAny<string>(), _qosProvider.Object), Times.Once);
} }
private void GivenTheClaimsToThingCreatorReturns(List<ClaimToThing> claimsToThing)
{
_claimsToThingCreator
.Setup(x => x.Create(_fileConfiguration.ReRoutes[0].AddHeadersToRequest))
.Returns(claimsToThing);
}
private void GivenTheAuthOptionsCreatorReturns(AuthenticationOptions authOptions)
{
_authOptionsCreator
.Setup(x => x.Create(It.IsAny<FileReRoute>()))
.Returns(authOptions);
}
private void ThenTheAuthOptionsCreatorIsCalledCorrectly()
{
_authOptionsCreator
.Verify(x => x.Create(_fileConfiguration.ReRoutes[0]), Times.Once);
}
private void GivenTheUpstreamTemplatePatternCreatorReturns(string pattern)
{
_upstreamTemplatePatternCreator
.Setup(x => x.Create(It.IsAny<FileReRoute>()))
.Returns(pattern);
}
private void ThenTheRequestIdKeyCreatorIsCalledCorrectly()
{
_requestIdKeyCreator
.Verify(x => x.Create(_fileConfiguration.ReRoutes[0], _fileConfiguration.GlobalConfiguration), Times.Once);
}
private void GivenTheRequestIdCreatorReturns(string requestId)
{
_requestIdKeyCreator
.Setup(x => x.Create(It.IsAny<FileReRoute>(), It.IsAny<FileGlobalConfiguration>()))
.Returns(requestId);
}
private void GivenTheQosOptionsCreatorReturns(QoSOptions qosOptions)
{
_qosOptionsCreator
.Setup(x => x.Create(_fileConfiguration.ReRoutes[0]))
.Returns(qosOptions);
}
private void ThenTheQosOptionsAre(QoSOptions qosOptions)
{
_config.Data.ReRoutes[0].QosOptions.DurationOfBreak.ShouldBe(qosOptions.DurationOfBreak);
_config.Data.ReRoutes[0].QosOptions.ExceptionsAllowedBeforeBreaking.ShouldBe(qosOptions.ExceptionsAllowedBeforeBreaking);
_config.Data.ReRoutes[0].QosOptions.TimeoutValue.ShouldBe(qosOptions.TimeoutValue);
}
} }
} }

View File

@ -0,0 +1,63 @@
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration
{
public class QoSOptionsCreatorTests
{
private QoSOptionsCreator _creator;
private FileReRoute _fileReRoute;
private QoSOptions _result;
public QoSOptionsCreatorTests()
{
_creator = new QoSOptionsCreator();
}
[Fact]
public void should_create_qos_options()
{
var reRoute = new FileReRoute
{
QoSOptions = new FileQoSOptions
{
ExceptionsAllowedBeforeBreaking = 1,
DurationOfBreak = 1,
TimeoutValue = 1
}
};
var expected = new QoSOptionsBuilder()
.WithDurationOfBreak(1)
.WithExceptionsAllowedBeforeBreaking(1)
.WithTimeoutValue(1)
.Build();
this.Given(x => x.GivenTheFollowingReRoute(reRoute))
.When(x => x.WhenICreate())
.Then(x => x.ThenTheFollowingIsReturned(expected))
.BDDfy();
}
private void GivenTheFollowingReRoute(FileReRoute fileReRoute)
{
_fileReRoute = fileReRoute;
}
private void WhenICreate()
{
_result = _creator.Create(_fileReRoute);
}
private void ThenTheFollowingIsReturned(QoSOptions expected)
{
_result.DurationOfBreak.ShouldBe(expected.DurationOfBreak);
_result.ExceptionsAllowedBeforeBreaking.ShouldBe(expected.ExceptionsAllowedBeforeBreaking);
_result.TimeoutValue.ShouldBe(expected.TimeoutValue);
}
}
}

View File

@ -0,0 +1,108 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration
{
public class RateLimitOptionsCreatorTests
{
private FileReRoute _fileReRoute;
private FileGlobalConfiguration _fileGlobalConfig;
private bool _enabled;
private RateLimitOptionsCreator _creator;
private RateLimitOptions _result;
public RateLimitOptionsCreatorTests()
{
_creator = new RateLimitOptionsCreator();
}
[Fact]
public void should_create_rate_limit_options()
{
var fileReRoute = new FileReRoute
{
RateLimitOptions = new FileRateLimitRule
{
ClientWhitelist = new List<string>(),
Period = "Period",
Limit = 1,
PeriodTimespan = 1,
EnableRateLimiting = true
}
};
var fileGlobalConfig = new FileGlobalConfiguration
{
RateLimitOptions = new FileRateLimitOptions
{
ClientIdHeader = "ClientIdHeader",
DisableRateLimitHeaders = true,
QuotaExceededMessage = "QuotaExceededMessage",
RateLimitCounterPrefix = "RateLimitCounterPrefix",
HttpStatusCode = 200
}
};
var expected = new RateLimitOptionsBuilder()
.WithClientIdHeader("ClientIdHeader")
.WithClientWhiteList(fileReRoute.RateLimitOptions.ClientWhitelist)
.WithDisableRateLimitHeaders(true)
.WithEnableRateLimiting(true)
.WithHttpStatusCode(200)
.WithQuotaExceededMessage("QuotaExceededMessage")
.WithRateLimitCounterPrefix("RateLimitCounterPrefix")
.WithRateLimitRule(new RateLimitRule(fileReRoute.RateLimitOptions.Period,
TimeSpan.FromSeconds(fileReRoute.RateLimitOptions.PeriodTimespan),
fileReRoute.RateLimitOptions.Limit))
.Build();
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.And(x => x.GivenTheFollowingFileGlobalConfig(fileGlobalConfig))
.And(x => x.GivenRateLimitingIsEnabled())
.When(x => x.WhenICreate())
.Then(x => x.ThenTheFollowingIsReturned(expected))
.BDDfy();
}
private void GivenTheFollowingFileReRoute(FileReRoute fileReRoute)
{
_fileReRoute = fileReRoute;
}
private void GivenTheFollowingFileGlobalConfig(FileGlobalConfiguration fileGlobalConfig)
{
_fileGlobalConfig = fileGlobalConfig;
}
private void GivenRateLimitingIsEnabled()
{
_enabled = true;
}
private void WhenICreate()
{
_result = _creator.Create(_fileReRoute, _fileGlobalConfig, _enabled);
}
private void ThenTheFollowingIsReturned(RateLimitOptions expected)
{
_result.ClientIdHeader.ShouldBe(expected.ClientIdHeader);
_result.ClientWhitelist.ShouldBe(expected.ClientWhitelist);
_result.DisableRateLimitHeaders.ShouldBe(expected.DisableRateLimitHeaders);
_result.EnableRateLimiting.ShouldBe(expected.EnableRateLimiting);
_result.HttpStatusCode.ShouldBe(expected.HttpStatusCode);
_result.QuotaExceededMessage.ShouldBe(expected.QuotaExceededMessage);
_result.RateLimitCounterPrefix.ShouldBe(expected.RateLimitCounterPrefix);
_result.RateLimitRule.Limit.ShouldBe(expected.RateLimitRule.Limit);
_result.RateLimitRule.Period.ShouldBe(expected.RateLimitRule.Period);
_result.RateLimitRule.PeriodTimespan.Ticks.ShouldBe(expected.RateLimitRule.PeriodTimespan.Ticks);
}
}
}

View File

@ -0,0 +1,84 @@
using System.Collections.Generic;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration
{
public class ReRouteOptionsCreatorTests
{
private ReRouteOptionsCreator _creator;
private FileReRoute _reRoute;
private ReRouteOptions _result;
public ReRouteOptionsCreatorTests()
{
_creator = new ReRouteOptionsCreator();
}
[Fact]
public void should_create_re_route_options()
{
var reRoute = new FileReRoute
{
RateLimitOptions = new FileRateLimitRule
{
EnableRateLimiting = true
},
QoSOptions = new FileQoSOptions
{
ExceptionsAllowedBeforeBreaking = 1,
TimeoutValue = 1
},
AuthenticationOptions = new FileAuthenticationOptions
{
Provider = "IdentityServer"
},
RouteClaimsRequirement = new Dictionary<string, string>()
{
{"",""}
},
FileCacheOptions = new FileCacheOptions
{
TtlSeconds = 1
}
};
var expected = new ReRouteOptionsBuilder()
.WithIsAuthenticated(true)
.WithIsAuthorised(true)
.WithIsCached(true)
.WithIsQos(true)
.WithRateLimiting(true)
.Build();
this.Given(x => x.GivenTheFollowing(reRoute))
.When(x => x.WhenICreate())
.Then(x => x.ThenTheFollowingIsReturned(expected))
.BDDfy();
}
private void GivenTheFollowing(FileReRoute reRoute)
{
_reRoute = reRoute;
}
private void WhenICreate()
{
_result = _creator.Create(_reRoute);
}
private void ThenTheFollowingIsReturned(ReRouteOptions expected)
{
_result.IsAuthenticated.ShouldBe(expected.IsAuthenticated);
_result.IsAuthorised.ShouldBe(expected.IsAuthorised);
_result.IsQos.ShouldBe(expected.IsQos);
_result.IsCached.ShouldBe(expected.IsCached);
_result.EnableRateLimiting.ShouldBe(expected.EnableRateLimiting);
}
}
}

View File

@ -0,0 +1,91 @@
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration
{
public class RequestIdKeyCreatorTests
{
private FileReRoute _fileReRoute;
private FileGlobalConfiguration _fileGlobalConfig;
private string _result;
private RequestIdKeyCreator _creator;
public RequestIdKeyCreatorTests()
{
_creator = new RequestIdKeyCreator();
}
[Fact]
public void should_use_global_configuration()
{
var reRoute = new FileReRoute();
var globalConfig = new FileGlobalConfiguration
{
RequestIdKey = "cheese"
};
this.Given(x => x.GivenTheFollowingReRoute(reRoute))
.And(x => x.GivenTheFollowingGlobalConfig(globalConfig))
.When(x => x.WhenICreate())
.Then(x => x.ThenTheFollowingIsReturned("cheese"))
.BDDfy();
}
[Fact]
public void should_use_re_route_specific()
{
var reRoute = new FileReRoute
{
RequestIdKey = "cheese"
};
var globalConfig = new FileGlobalConfiguration();
this.Given(x => x.GivenTheFollowingReRoute(reRoute))
.And(x => x.GivenTheFollowingGlobalConfig(globalConfig))
.When(x => x.WhenICreate())
.Then(x => x.ThenTheFollowingIsReturned("cheese"))
.BDDfy();
}
[Fact]
public void should_use_global_cofiguration_over_re_route_specific()
{
var reRoute = new FileReRoute
{
RequestIdKey = "cheese"
}; var globalConfig = new FileGlobalConfiguration
{
RequestIdKey = "cheese"
};
this.Given(x => x.GivenTheFollowingReRoute(reRoute))
.And(x => x.GivenTheFollowingGlobalConfig(globalConfig))
.When(x => x.WhenICreate())
.Then(x => x.ThenTheFollowingIsReturned("cheese"))
.BDDfy();
}
private void GivenTheFollowingReRoute(FileReRoute fileReRoute)
{
_fileReRoute = fileReRoute;
}
private void GivenTheFollowingGlobalConfig(FileGlobalConfiguration globalConfig)
{
_fileGlobalConfig = globalConfig;
}
private void WhenICreate()
{
_result = _creator.Create(_fileReRoute, _fileGlobalConfig);
}
private void ThenTheFollowingIsReturned(string expected)
{
_result.ShouldBe(expected);
}
}
}

View File

@ -0,0 +1,76 @@
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration
{
public class ServiceProviderCreatorTests
{
private ServiceProviderConfigurationCreator _creator;
private FileReRoute _reRoute;
private FileGlobalConfiguration _globalConfig;
private ServiceProviderConfiguration _result;
public ServiceProviderCreatorTests()
{
_creator = new ServiceProviderConfigurationCreator();
}
[Fact]
public void should_create_service_provider_config()
{
var reRoute = new FileReRoute();
var globalConfig = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{
Provider = "consul",
Host = "127.0.0.1",
Port = 1234
}
};
var expected = new ServiceProviderConfigurationBuilder()
.WithServiceDiscoveryProvider("consul")
.WithServiceDiscoveryProviderHost("127.0.0.1")
.WithServiceDiscoveryProviderPort(1234)
.Build();
this.Given(x => x.GivenTheFollowingReRoute(reRoute))
.And(x => x.GivenTheFollowingGlobalConfig(globalConfig))
.When(x => x.WhenICreate())
.Then(x => x.ThenTheConfigIs(expected))
.BDDfy();
}
private void GivenTheFollowingReRoute(FileReRoute fileReRoute)
{
_reRoute = fileReRoute;
}
private void GivenTheFollowingGlobalConfig(FileGlobalConfiguration fileGlobalConfig)
{
_globalConfig = fileGlobalConfig;
}
private void WhenICreate()
{
_result = _creator.Create(_reRoute, _globalConfig);
}
private void ThenTheConfigIs(ServiceProviderConfiguration expected)
{
_result.DownstreamHost.ShouldBe(expected.DownstreamHost);
_result.DownstreamPort.ShouldBe(expected.DownstreamPort);
_result.ServiceDiscoveryProvider.ShouldBe(expected.ServiceDiscoveryProvider);
_result.ServiceName.ShouldBe(expected.ServiceName);
_result.ServiceProviderHost.ShouldBe(expected.ServiceProviderHost);
_result.ServiceProviderPort.ShouldBe(expected.ServiceProviderPort);
}
}
}

View File

@ -0,0 +1,122 @@
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration
{
public class UpstreamTemplatePatternCreatorTests
{
private FileReRoute _fileReRoute;
private UpstreamTemplatePatternCreator _creator;
private string _result;
public UpstreamTemplatePatternCreatorTests()
{
_creator = new UpstreamTemplatePatternCreator();
}
[Fact]
public void should_set_upstream_template_pattern_to_ignore_case_sensitivity()
{
var fileReRoute = new FileReRoute
{
UpstreamPathTemplate = "/PRODUCTS/{productId}",
ReRouteIsCaseSensitive = false
};
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("(?i)/PRODUCTS/.*/$"))
.BDDfy();
}
[Fact]
public void should_set_upstream_template_pattern_to_respect_case_sensitivity()
{
var fileReRoute = new FileReRoute
{
UpstreamPathTemplate = "/PRODUCTS/{productId}",
ReRouteIsCaseSensitive = true
};
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("/PRODUCTS/.*/$"))
.BDDfy();
}
[Fact]
public void should_create_template_pattern_that_matches_anything_to_end_of_string()
{
var fileReRoute = new FileReRoute
{
UpstreamPathTemplate = "/api/products/{productId}",
ReRouteIsCaseSensitive = true
};
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("/api/products/.*/$"))
.BDDfy();
}
[Fact]
public void should_create_template_pattern_that_matches_more_than_one_placeholder()
{
var fileReRoute = new FileReRoute
{
UpstreamPathTemplate = "/api/products/{productId}/variants/{variantId}",
ReRouteIsCaseSensitive = true
};
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("/api/products/.*/variants/.*/$"))
.BDDfy();
}
[Fact]
public void should_create_template_pattern_that_matches_more_than_one_placeholder_with_trailing_slash()
{
var fileReRoute = new FileReRoute
{
UpstreamPathTemplate = "/api/products/{productId}/variants/{variantId}/",
ReRouteIsCaseSensitive = true
};
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("/api/products/.*/variants/.*/$"))
.BDDfy();
}
[Fact]
public void should_create_template_pattern_that_matches_to_end_of_string()
{
var fileReRoute = new FileReRoute
{
UpstreamPathTemplate = "/"
};
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^/$"))
.BDDfy();
}
private void GivenTheFollowingFileReRoute(FileReRoute fileReRoute)
{
_fileReRoute = fileReRoute;
}
private void WhenICreateTheTemplatePattern()
{
_result = _creator.Create(_fileReRoute);
}
private void ThenTheFollowingIsReturned(string expected)
{
_result.ShouldBe(expected);
}
}
}

View File

@ -1,5 +1,3 @@
using System;
using System.Net;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Moq; using Moq;
using Ocelot.Configuration.File; using Ocelot.Configuration.File;

View File

@ -28,7 +28,7 @@ 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 ServiceProviderConfiguraionBuilder().Build()) .WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder().Build())
.WithUpstreamHttpMethod("Get") .WithUpstreamHttpMethod("Get")
.Build(); .Build();
@ -45,7 +45,7 @@ namespace Ocelot.UnitTests.LoadBalancer
var reRoute = new ReRouteBuilder() var reRoute = new ReRouteBuilder()
.WithLoadBalancer("RoundRobin") .WithLoadBalancer("RoundRobin")
.WithUpstreamHttpMethod("Get") .WithUpstreamHttpMethod("Get")
.WithServiceProviderConfiguraion(new ServiceProviderConfiguraionBuilder().Build()) .WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder().Build())
.Build(); .Build();
this.Given(x => x.GivenAReRoute(reRoute)) this.Given(x => x.GivenAReRoute(reRoute))
@ -61,7 +61,7 @@ namespace Ocelot.UnitTests.LoadBalancer
var reRoute = new ReRouteBuilder() var reRoute = new ReRouteBuilder()
.WithLoadBalancer("LeastConnection") .WithLoadBalancer("LeastConnection")
.WithUpstreamHttpMethod("Get") .WithUpstreamHttpMethod("Get")
.WithServiceProviderConfiguraion(new ServiceProviderConfiguraionBuilder().Build()) .WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder().Build())
.Build(); .Build();
this.Given(x => x.GivenAReRoute(reRoute)) this.Given(x => x.GivenAReRoute(reRoute))
@ -77,7 +77,7 @@ namespace Ocelot.UnitTests.LoadBalancer
var reRoute = new ReRouteBuilder() var reRoute = new ReRouteBuilder()
.WithLoadBalancer("RoundRobin") .WithLoadBalancer("RoundRobin")
.WithUpstreamHttpMethod("Get") .WithUpstreamHttpMethod("Get")
.WithServiceProviderConfiguraion(new ServiceProviderConfiguraionBuilder().Build()) .WithServiceProviderConfiguraion(new ServiceProviderConfigurationBuilder().Build())
.Build(); .Build();
this.Given(x => x.GivenAReRoute(reRoute)) this.Given(x => x.GivenAReRoute(reRoute))
@ -90,14 +90,14 @@ namespace Ocelot.UnitTests.LoadBalancer
private void GivenTheServiceProviderFactoryReturns() private void GivenTheServiceProviderFactoryReturns()
{ {
_serviceProviderFactory _serviceProviderFactory
.Setup(x => x.Get(It.IsAny<ServiceProviderConfiguraion>())) .Setup(x => x.Get(It.IsAny<ServiceProviderConfiguration>()))
.Returns(_serviceProvider.Object); .Returns(_serviceProvider.Object);
} }
private void ThenTheServiceProviderIsCalledCorrectly() private void ThenTheServiceProviderIsCalledCorrectly()
{ {
_serviceProviderFactory _serviceProviderFactory
.Verify(x => x.Get(It.IsAny<ServiceProviderConfiguraion>()), Times.Once); .Verify(x => x.Get(It.IsAny<ServiceProviderConfiguration>()), Times.Once);
} }
private void GivenAReRoute(ReRoute reRoute) private void GivenAReRoute(ReRoute reRoute)

View File

@ -9,7 +9,7 @@ namespace Ocelot.UnitTests.ServiceDiscovery
{ {
public class ServiceProviderFactoryTests public class ServiceProviderFactoryTests
{ {
private ServiceProviderConfiguraion _serviceConfig; private ServiceProviderConfiguration _serviceConfig;
private IServiceDiscoveryProvider _result; private IServiceDiscoveryProvider _result;
private readonly ServiceDiscoveryProviderFactory _factory; private readonly ServiceDiscoveryProviderFactory _factory;
@ -21,7 +21,7 @@ namespace Ocelot.UnitTests.ServiceDiscovery
[Fact] [Fact]
public void should_return_no_service_provider() public void should_return_no_service_provider()
{ {
var serviceConfig = new ServiceProviderConfiguraionBuilder() var serviceConfig = new ServiceProviderConfigurationBuilder()
.WithDownstreamHost("127.0.0.1") .WithDownstreamHost("127.0.0.1")
.WithDownstreamPort(80) .WithDownstreamPort(80)
.WithUseServiceDiscovery(false) .WithUseServiceDiscovery(false)
@ -36,7 +36,7 @@ namespace Ocelot.UnitTests.ServiceDiscovery
[Fact] [Fact]
public void should_return_consul_service_provider() public void should_return_consul_service_provider()
{ {
var serviceConfig = new ServiceProviderConfiguraionBuilder() var serviceConfig = new ServiceProviderConfigurationBuilder()
.WithServiceName("product") .WithServiceName("product")
.WithUseServiceDiscovery(true) .WithUseServiceDiscovery(true)
.WithServiceDiscoveryProvider("Consul") .WithServiceDiscoveryProvider("Consul")
@ -48,7 +48,7 @@ namespace Ocelot.UnitTests.ServiceDiscovery
.BDDfy(); .BDDfy();
} }
private void GivenTheReRoute(ServiceProviderConfiguraion serviceConfig) private void GivenTheReRoute(ServiceProviderConfiguration serviceConfig)
{ {
_serviceConfig = serviceConfig; _serviceConfig = serviceConfig;
} }