mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-04-22 06:42:50 +08:00
Merge pull request #51 from ThreeMammals/develop
Feature/adding some re route specific validation tests (#590)
This commit is contained in:
commit
e799f5792e
@ -62,7 +62,8 @@ The secret is the client secret that Ocelot's internal IdentityServer will use t
|
|||||||
}
|
}
|
||||||
|
|
||||||
In order for the administration API to work, Ocelot / IdentityServer must be able to call itself for validation. This means that you need to add the base url of Ocelot
|
In order for the administration API to work, Ocelot / IdentityServer must be able to call itself for validation. This means that you need to add the base url of Ocelot
|
||||||
to global configuration if it is not default (http://localhost:5000). This can be done as follows..
|
to global configuration if it is not default (http://localhost:5000). Please note if you are using something like docker to host Ocelot it might not be able to
|
||||||
|
call back to localhost etc and you need to know what you are doing with docker networking in this scenario. Anyway this can be done as follows..
|
||||||
|
|
||||||
If you want to run on a different host and port locally..
|
If you want to run on a different host and port locally..
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
using System.Collections.Generic;
|
namespace Ocelot.Configuration.Validator
|
||||||
|
{
|
||||||
|
using System.Collections.Generic;
|
||||||
using Ocelot.Errors;
|
using Ocelot.Errors;
|
||||||
|
|
||||||
namespace Ocelot.Configuration.Validator
|
|
||||||
{
|
|
||||||
public class ConfigurationValidationResult
|
public class ConfigurationValidationResult
|
||||||
{
|
{
|
||||||
public ConfigurationValidationResult(bool isError)
|
public ConfigurationValidationResult(bool isError)
|
||||||
@ -11,12 +11,6 @@ namespace Ocelot.Configuration.Validator
|
|||||||
Errors = new List<Error>();
|
Errors = new List<Error>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConfigurationValidationResult(bool isError, Error error)
|
|
||||||
{
|
|
||||||
IsError = isError;
|
|
||||||
Errors = new List<Error> { error };
|
|
||||||
}
|
|
||||||
|
|
||||||
public ConfigurationValidationResult(bool isError, List<Error> errors)
|
public ConfigurationValidationResult(bool isError, List<Error> errors)
|
||||||
{
|
{
|
||||||
IsError = isError;
|
IsError = isError;
|
||||||
|
@ -1,46 +1,42 @@
|
|||||||
using FluentValidation;
|
namespace Ocelot.Configuration.Validator
|
||||||
using Microsoft.AspNetCore.Authentication;
|
{
|
||||||
using Ocelot.Configuration.File;
|
using FluentValidation;
|
||||||
using Ocelot.Errors;
|
using File;
|
||||||
using Ocelot.Responses;
|
using Errors;
|
||||||
|
using Responses;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Ocelot.Configuration.Validator
|
|
||||||
{
|
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Ocelot.ServiceDiscovery;
|
using ServiceDiscovery;
|
||||||
using Requester;
|
|
||||||
|
|
||||||
public class FileConfigurationFluentValidator : AbstractValidator<FileConfiguration>, IConfigurationValidator
|
public class FileConfigurationFluentValidator : AbstractValidator<FileConfiguration>, IConfigurationValidator
|
||||||
{
|
{
|
||||||
private readonly QosDelegatingHandlerDelegate _qosDelegatingHandlerDelegate;
|
|
||||||
private readonly List<ServiceDiscoveryFinderDelegate> _serviceDiscoveryFinderDelegates;
|
private readonly List<ServiceDiscoveryFinderDelegate> _serviceDiscoveryFinderDelegates;
|
||||||
public FileConfigurationFluentValidator(IAuthenticationSchemeProvider authenticationSchemeProvider, IServiceProvider provider)
|
|
||||||
|
public FileConfigurationFluentValidator(IServiceProvider provider, ReRouteFluentValidator reRouteFluentValidator, FileGlobalConfigurationFluentValidator fileGlobalConfigurationFluentValidator)
|
||||||
{
|
{
|
||||||
_qosDelegatingHandlerDelegate = provider.GetService<QosDelegatingHandlerDelegate>();
|
|
||||||
_serviceDiscoveryFinderDelegates = provider
|
_serviceDiscoveryFinderDelegates = provider
|
||||||
.GetServices<ServiceDiscoveryFinderDelegate>()
|
.GetServices<ServiceDiscoveryFinderDelegate>()
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
RuleFor(configuration => configuration.ReRoutes)
|
RuleFor(configuration => configuration.ReRoutes)
|
||||||
.SetCollectionValidator(new ReRouteFluentValidator(authenticationSchemeProvider, _qosDelegatingHandlerDelegate));
|
.SetCollectionValidator(reRouteFluentValidator);
|
||||||
|
|
||||||
RuleFor(configuration => configuration.GlobalConfiguration)
|
RuleFor(configuration => configuration.GlobalConfiguration)
|
||||||
.SetValidator(new FileGlobalConfigurationFluentValidator(_qosDelegatingHandlerDelegate));
|
.SetValidator(fileGlobalConfigurationFluentValidator);
|
||||||
|
|
||||||
RuleForEach(configuration => configuration.ReRoutes)
|
RuleForEach(configuration => configuration.ReRoutes)
|
||||||
.Must((config, reRoute) => IsNotDuplicateIn(reRoute, config.ReRoutes))
|
.Must((config, reRoute) => IsNotDuplicateIn(reRoute, config.ReRoutes))
|
||||||
.WithMessage((config, reRoute) => $"{nameof(reRoute)} {reRoute.UpstreamPathTemplate} has duplicate");
|
.WithMessage((config, reRoute) => $"{nameof(reRoute)} {reRoute.UpstreamPathTemplate} has duplicate");
|
||||||
|
|
||||||
RuleForEach(configuration => configuration.ReRoutes)
|
RuleForEach(configuration => configuration.ReRoutes)
|
||||||
.Must((config, reRoute) => HaveServiceDiscoveryProviderRegitered(reRoute, config.GlobalConfiguration.ServiceDiscoveryProvider))
|
.Must((config, reRoute) => HaveServiceDiscoveryProviderRegistered(reRoute, config.GlobalConfiguration.ServiceDiscoveryProvider))
|
||||||
.WithMessage((config, reRoute) => $"Unable to start Ocelot, errors are: Unable to start Ocelot because either a ReRoute or GlobalConfiguration are using ServiceDiscoveryOptions but no ServiceDiscoveryFinderDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Consul and services.AddConsul() or Ocelot.Provider.Eureka and services.AddEureka()?");
|
.WithMessage((config, reRoute) => $"Unable to start Ocelot, errors are: Unable to start Ocelot because either a ReRoute or GlobalConfiguration are using ServiceDiscoveryOptions but no ServiceDiscoveryFinderDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Consul and services.AddConsul() or Ocelot.Provider.Eureka and services.AddEureka()?");
|
||||||
|
|
||||||
RuleFor(configuration => configuration.GlobalConfiguration.ServiceDiscoveryProvider)
|
RuleFor(configuration => configuration.GlobalConfiguration.ServiceDiscoveryProvider)
|
||||||
.Must((config) => HaveServiceDiscoveryProviderRegitered(config))
|
.Must(HaveServiceDiscoveryProviderRegistered)
|
||||||
.WithMessage((config, reRoute) => $"Unable to start Ocelot, errors are: Unable to start Ocelot because either a ReRoute or GlobalConfiguration are using ServiceDiscoveryOptions but no ServiceDiscoveryFinderDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Consul and services.AddConsul() or Ocelot.Provider.Eureka and services.AddEureka()?");
|
.WithMessage((config, reRoute) => $"Unable to start Ocelot, errors are: Unable to start Ocelot because either a ReRoute or GlobalConfiguration are using ServiceDiscoveryOptions but no ServiceDiscoveryFinderDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Consul and services.AddConsul() or Ocelot.Provider.Eureka and services.AddEureka()?");
|
||||||
|
|
||||||
RuleForEach(configuration => configuration.ReRoutes)
|
RuleForEach(configuration => configuration.ReRoutes)
|
||||||
@ -60,7 +56,7 @@ namespace Ocelot.Configuration.Validator
|
|||||||
.WithMessage((config, aggregateReRoute) => $"{nameof(aggregateReRoute)} {aggregateReRoute.UpstreamPathTemplate} contains ReRoute with specific RequestIdKey, this is not possible with Aggregates");
|
.WithMessage((config, aggregateReRoute) => $"{nameof(aggregateReRoute)} {aggregateReRoute.UpstreamPathTemplate} contains ReRoute with specific RequestIdKey, this is not possible with Aggregates");
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool HaveServiceDiscoveryProviderRegitered(FileReRoute reRoute, FileServiceDiscoveryProvider serviceDiscoveryProvider)
|
private bool HaveServiceDiscoveryProviderRegistered(FileReRoute reRoute, FileServiceDiscoveryProvider serviceDiscoveryProvider)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(reRoute.ServiceName))
|
if (string.IsNullOrEmpty(reRoute.ServiceName))
|
||||||
{
|
{
|
||||||
@ -75,7 +71,7 @@ namespace Ocelot.Configuration.Validator
|
|||||||
return _serviceDiscoveryFinderDelegates.Any();
|
return _serviceDiscoveryFinderDelegates.Any();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool HaveServiceDiscoveryProviderRegitered(FileServiceDiscoveryProvider serviceDiscoveryProvider)
|
private bool HaveServiceDiscoveryProviderRegistered(FileServiceDiscoveryProvider serviceDiscoveryProvider)
|
||||||
{
|
{
|
||||||
if(serviceDiscoveryProvider == null)
|
if(serviceDiscoveryProvider == null)
|
||||||
{
|
{
|
||||||
@ -87,12 +83,7 @@ namespace Ocelot.Configuration.Validator
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(string.IsNullOrEmpty(serviceDiscoveryProvider.Type))
|
return string.IsNullOrEmpty(serviceDiscoveryProvider.Type) || _serviceDiscoveryFinderDelegates.Any();
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _serviceDiscoveryFinderDelegates.Any();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Response<ConfigurationValidationResult>> IsValid(FileConfiguration configuration)
|
public async Task<Response<ConfigurationValidationResult>> IsValid(FileConfiguration configuration)
|
||||||
|
@ -1,21 +1,14 @@
|
|||||||
using FluentValidation;
|
|
||||||
using Ocelot.Configuration.File;
|
|
||||||
|
|
||||||
namespace Ocelot.Configuration.Validator
|
namespace Ocelot.Configuration.Validator
|
||||||
{
|
{
|
||||||
using Requester;
|
using FluentValidation;
|
||||||
|
using File;
|
||||||
|
|
||||||
public class FileGlobalConfigurationFluentValidator : AbstractValidator<FileGlobalConfiguration>
|
public class FileGlobalConfigurationFluentValidator : AbstractValidator<FileGlobalConfiguration>
|
||||||
{
|
{
|
||||||
private readonly QosDelegatingHandlerDelegate _qosDelegatingHandlerDelegate;
|
public FileGlobalConfigurationFluentValidator(FileQoSOptionsFluentValidator fileQoSOptionsFluentValidator)
|
||||||
|
|
||||||
public FileGlobalConfigurationFluentValidator(QosDelegatingHandlerDelegate qosDelegatingHandlerDelegate)
|
|
||||||
{
|
{
|
||||||
_qosDelegatingHandlerDelegate = qosDelegatingHandlerDelegate;
|
|
||||||
|
|
||||||
RuleFor(configuration => configuration.QoSOptions)
|
RuleFor(configuration => configuration.QoSOptions)
|
||||||
.SetValidator(new FileQoSOptionsFluentValidator(_qosDelegatingHandlerDelegate));
|
.SetValidator(fileQoSOptionsFluentValidator);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
using FluentValidation;
|
|
||||||
using Ocelot.Configuration.File;
|
|
||||||
|
|
||||||
namespace Ocelot.Configuration.Validator
|
namespace Ocelot.Configuration.Validator
|
||||||
{
|
{
|
||||||
|
using System;
|
||||||
|
using FluentValidation;
|
||||||
|
using File;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Requester;
|
using Requester;
|
||||||
|
|
||||||
public class FileQoSOptionsFluentValidator : AbstractValidator<FileQoSOptions>
|
public class FileQoSOptionsFluentValidator : AbstractValidator<FileQoSOptions>
|
||||||
{
|
{
|
||||||
private readonly QosDelegatingHandlerDelegate _qosDelegatingHandlerDelegate;
|
private readonly QosDelegatingHandlerDelegate _qosDelegatingHandlerDelegate;
|
||||||
|
|
||||||
public FileQoSOptionsFluentValidator(QosDelegatingHandlerDelegate qosDelegatingHandlerDelegate)
|
public FileQoSOptionsFluentValidator(IServiceProvider provider)
|
||||||
{
|
{
|
||||||
_qosDelegatingHandlerDelegate = qosDelegatingHandlerDelegate;
|
_qosDelegatingHandlerDelegate = provider.GetService<QosDelegatingHandlerDelegate>();
|
||||||
|
|
||||||
When(qosOptions => qosOptions.TimeoutValue > 0 && qosOptions.ExceptionsAllowedBeforeBreaking > 0, () => {
|
When(qosOptions => qosOptions.TimeoutValue > 0 && qosOptions.ExceptionsAllowedBeforeBreaking > 0, () => {
|
||||||
RuleFor(qosOptions => qosOptions)
|
RuleFor(qosOptions => qosOptions)
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
using System;
|
namespace Ocelot.Configuration.Validator
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using Ocelot.Errors;
|
|
||||||
|
|
||||||
namespace Ocelot.Configuration.Validator
|
|
||||||
{
|
{
|
||||||
|
using Errors;
|
||||||
|
|
||||||
public class FileValidationFailedError : Error
|
public class FileValidationFailedError : Error
|
||||||
{
|
{
|
||||||
public FileValidationFailedError(string message) : base(message, OcelotErrorCode.FileValidationFailedError)
|
public FileValidationFailedError(string message)
|
||||||
|
: base(message, OcelotErrorCode.FileValidationFailedError)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
|
namespace Ocelot.Configuration.Validator
|
||||||
|
{
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using Ocelot.Configuration.File;
|
using Ocelot.Configuration.File;
|
||||||
|
|
||||||
namespace Ocelot.Configuration.Validator
|
|
||||||
{
|
|
||||||
public class HostAndPortValidator : AbstractValidator<FileHostAndPort>
|
public class HostAndPortValidator : AbstractValidator<FileHostAndPort>
|
||||||
{
|
{
|
||||||
public HostAndPortValidator()
|
public HostAndPortValidator()
|
||||||
{
|
{
|
||||||
RuleFor(r => r.Host).NotEmpty().WithMessage("When not using service discovery Host must be set on DownstreamHostAndPorts if you are not using ReRoute.Host or Ocelot cannot find your service!");
|
RuleFor(r => r.Host)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage("When not using service discovery Host must be set on DownstreamHostAndPorts if you are not using ReRoute.Host or Ocelot cannot find your service!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
using System.Threading.Tasks;
|
namespace Ocelot.Configuration.Validator
|
||||||
|
{
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Ocelot.Configuration.File;
|
using Ocelot.Configuration.File;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
|
|
||||||
namespace Ocelot.Configuration.Validator
|
|
||||||
{
|
|
||||||
public interface IConfigurationValidator
|
public interface IConfigurationValidator
|
||||||
{
|
{
|
||||||
Task<Response<ConfigurationValidationResult>> IsValid(FileConfiguration configuration);
|
Task<Response<ConfigurationValidationResult>> IsValid(FileConfiguration configuration);
|
||||||
|
@ -1,37 +1,51 @@
|
|||||||
namespace Ocelot.Configuration.Validator
|
namespace Ocelot.Configuration.Validator
|
||||||
{
|
{
|
||||||
|
using System;
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Ocelot.Configuration.File;
|
using File;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Requester;
|
|
||||||
|
|
||||||
public class ReRouteFluentValidator : AbstractValidator<FileReRoute>
|
public class ReRouteFluentValidator : AbstractValidator<FileReRoute>
|
||||||
{
|
{
|
||||||
private readonly IAuthenticationSchemeProvider _authenticationSchemeProvider;
|
private readonly IAuthenticationSchemeProvider _authenticationSchemeProvider;
|
||||||
private readonly QosDelegatingHandlerDelegate _qosDelegatingHandlerDelegate;
|
|
||||||
|
|
||||||
public ReRouteFluentValidator(IAuthenticationSchemeProvider authenticationSchemeProvider, QosDelegatingHandlerDelegate qosDelegatingHandlerDelegate)
|
public ReRouteFluentValidator(IAuthenticationSchemeProvider authenticationSchemeProvider, HostAndPortValidator hostAndPortValidator, FileQoSOptionsFluentValidator fileQoSOptionsFluentValidator)
|
||||||
{
|
{
|
||||||
_authenticationSchemeProvider = authenticationSchemeProvider;
|
_authenticationSchemeProvider = authenticationSchemeProvider;
|
||||||
_qosDelegatingHandlerDelegate = qosDelegatingHandlerDelegate;
|
|
||||||
|
|
||||||
RuleFor(reRoute => reRoute.QoSOptions)
|
RuleFor(reRoute => reRoute.QoSOptions)
|
||||||
.SetValidator(new FileQoSOptionsFluentValidator(_qosDelegatingHandlerDelegate));
|
.SetValidator(fileQoSOptionsFluentValidator);
|
||||||
|
|
||||||
|
RuleFor(reRoute => reRoute.DownstreamPathTemplate)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage("{PropertyName} cannot be empty");
|
||||||
|
|
||||||
|
RuleFor(reRoute => reRoute.UpstreamPathTemplate)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage("{PropertyName} cannot be empty");
|
||||||
|
|
||||||
|
When(reRoute => !string.IsNullOrEmpty(reRoute.DownstreamPathTemplate), () =>
|
||||||
|
{
|
||||||
RuleFor(reRoute => reRoute.DownstreamPathTemplate)
|
RuleFor(reRoute => reRoute.DownstreamPathTemplate)
|
||||||
.Must(path => path.StartsWith("/"))
|
.Must(path => path.StartsWith("/"))
|
||||||
.WithMessage("{PropertyName} {PropertyValue} doesnt start with forward slash");
|
.WithMessage("{PropertyName} {PropertyValue} doesnt start with forward slash");
|
||||||
|
|
||||||
RuleFor(reRoute => reRoute.UpstreamPathTemplate)
|
RuleFor(reRoute => reRoute.DownstreamPathTemplate)
|
||||||
.Must(path => !path.Contains("//"))
|
.Must(path => !path.Contains("//"))
|
||||||
.WithMessage("{PropertyName} {PropertyValue} contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature.");
|
.WithMessage("{PropertyName} {PropertyValue} contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature.");
|
||||||
|
|
||||||
RuleFor(reRoute => reRoute.DownstreamPathTemplate)
|
RuleFor(reRoute => reRoute.DownstreamPathTemplate)
|
||||||
|
.Must(path => !path.Contains("https://") && !path.Contains("http://"))
|
||||||
|
.WithMessage("{PropertyName} {PropertyValue} contains scheme");
|
||||||
|
});
|
||||||
|
|
||||||
|
When(reRoute => !string.IsNullOrEmpty(reRoute.UpstreamPathTemplate), () =>
|
||||||
|
{
|
||||||
|
RuleFor(reRoute => reRoute.UpstreamPathTemplate)
|
||||||
.Must(path => !path.Contains("//"))
|
.Must(path => !path.Contains("//"))
|
||||||
.WithMessage("{PropertyName} {PropertyValue} contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature.");
|
.WithMessage("{PropertyName} {PropertyValue} contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature.");
|
||||||
|
|
||||||
@ -39,21 +53,25 @@
|
|||||||
.Must(path => path.StartsWith("/"))
|
.Must(path => path.StartsWith("/"))
|
||||||
.WithMessage("{PropertyName} {PropertyValue} doesnt start with forward slash");
|
.WithMessage("{PropertyName} {PropertyValue} doesnt start with forward slash");
|
||||||
|
|
||||||
RuleFor(reRoute => reRoute.DownstreamPathTemplate)
|
|
||||||
.Must(path => !path.Contains("https://") && !path.Contains("http://"))
|
|
||||||
.WithMessage("{PropertyName} {PropertyValue} contains scheme");
|
|
||||||
|
|
||||||
RuleFor(reRoute => reRoute.UpstreamPathTemplate)
|
RuleFor(reRoute => reRoute.UpstreamPathTemplate)
|
||||||
.Must(path => !path.Contains("https://") && !path.Contains("http://"))
|
.Must(path => !path.Contains("https://") && !path.Contains("http://"))
|
||||||
.WithMessage("{PropertyName} {PropertyValue} contains scheme");
|
.WithMessage("{PropertyName} {PropertyValue} contains scheme");
|
||||||
|
});
|
||||||
|
|
||||||
|
When(reRoute => reRoute.RateLimitOptions.EnableRateLimiting, () =>
|
||||||
|
{
|
||||||
|
RuleFor(reRoute => reRoute.RateLimitOptions.Period)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage("RateLimitOptions.Period is empty");
|
||||||
|
|
||||||
RuleFor(reRoute => reRoute.RateLimitOptions)
|
RuleFor(reRoute => reRoute.RateLimitOptions)
|
||||||
.Must(IsValidPeriod)
|
.Must(IsValidPeriod)
|
||||||
.WithMessage("RateLimitOptions.Period does not contains (s,m,h,d)");
|
.WithMessage("RateLimitOptions.Period does not contain integer then s (second), m (minute), h (hour), d (day) e.g. 1m for 1 minute period");
|
||||||
|
});
|
||||||
|
|
||||||
RuleFor(reRoute => reRoute.AuthenticationOptions)
|
RuleFor(reRoute => reRoute.AuthenticationOptions)
|
||||||
.MustAsync(IsSupportedAuthenticationProviders)
|
.MustAsync(IsSupportedAuthenticationProviders)
|
||||||
.WithMessage("{PropertyValue} is unsupported authentication provider");
|
.WithMessage("{PropertyName} {PropertyValue} is unsupported authentication provider");
|
||||||
|
|
||||||
When(reRoute => string.IsNullOrEmpty(reRoute.ServiceName), () => {
|
When(reRoute => string.IsNullOrEmpty(reRoute.ServiceName), () => {
|
||||||
RuleFor(r => r.DownstreamHostAndPorts).NotEmpty()
|
RuleFor(r => r.DownstreamHostAndPorts).NotEmpty()
|
||||||
@ -62,7 +80,7 @@
|
|||||||
|
|
||||||
When(reRoute => string.IsNullOrEmpty(reRoute.ServiceName), () => {
|
When(reRoute => string.IsNullOrEmpty(reRoute.ServiceName), () => {
|
||||||
RuleFor(reRoute => reRoute.DownstreamHostAndPorts)
|
RuleFor(reRoute => reRoute.DownstreamHostAndPorts)
|
||||||
.SetCollectionValidator(new HostAndPortValidator());
|
.SetCollectionValidator(hostAndPortValidator);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,9 +100,22 @@
|
|||||||
|
|
||||||
private static bool IsValidPeriod(FileRateLimitRule rateLimitOptions)
|
private static bool IsValidPeriod(FileRateLimitRule rateLimitOptions)
|
||||||
{
|
{
|
||||||
string period = rateLimitOptions.Period;
|
if (string.IsNullOrEmpty(rateLimitOptions.Period))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return !rateLimitOptions.EnableRateLimiting || period.Contains("s") || period.Contains("m") || period.Contains("h") || period.Contains("d");
|
var period = rateLimitOptions.Period;
|
||||||
|
|
||||||
|
var secondsRegEx = new Regex("^[0-9]+s");
|
||||||
|
var minutesRegEx = new Regex("^[0-9]+m");
|
||||||
|
var hoursRegEx = new Regex("^[0-9]+h");
|
||||||
|
var daysRegEx = new Regex("^[0-9]+d");
|
||||||
|
|
||||||
|
return secondsRegEx.Match(period).Success
|
||||||
|
|| minutesRegEx.Match(period).Success
|
||||||
|
|| hoursRegEx.Match(period).Success
|
||||||
|
|| daysRegEx.Match(period).Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,10 @@ namespace Ocelot.DependencyInjection
|
|||||||
Services.TryAddSingleton<IInternalConfigurationCreator, FileInternalConfigurationCreator>();
|
Services.TryAddSingleton<IInternalConfigurationCreator, FileInternalConfigurationCreator>();
|
||||||
Services.TryAddSingleton<IInternalConfigurationRepository, InMemoryInternalConfigurationRepository>();
|
Services.TryAddSingleton<IInternalConfigurationRepository, InMemoryInternalConfigurationRepository>();
|
||||||
Services.TryAddSingleton<IConfigurationValidator, FileConfigurationFluentValidator>();
|
Services.TryAddSingleton<IConfigurationValidator, FileConfigurationFluentValidator>();
|
||||||
|
Services.AddSingleton<HostAndPortValidator>();
|
||||||
|
Services.AddSingleton<ReRouteFluentValidator>();
|
||||||
|
Services.AddSingleton<FileGlobalConfigurationFluentValidator>();
|
||||||
|
Services.AddSingleton<FileQoSOptionsFluentValidator>();
|
||||||
Services.TryAddSingleton<IClaimsToThingCreator, ClaimsToThingCreator>();
|
Services.TryAddSingleton<IClaimsToThingCreator, ClaimsToThingCreator>();
|
||||||
Services.TryAddSingleton<IAuthenticationOptionsCreator, AuthenticationOptionsCreator>();
|
Services.TryAddSingleton<IAuthenticationOptionsCreator, AuthenticationOptionsCreator>();
|
||||||
Services.TryAddSingleton<IUpstreamTemplatePatternCreator, UpstreamTemplatePatternCreator>();
|
Services.TryAddSingleton<IUpstreamTemplatePatternCreator, UpstreamTemplatePatternCreator>();
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
namespace Ocelot.UnitTests.Configuration
|
namespace Ocelot.UnitTests.Configuration.Validation
|
||||||
{
|
{
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
@ -33,7 +33,8 @@
|
|||||||
_authProvider = new Mock<IAuthenticationSchemeProvider>();
|
_authProvider = new Mock<IAuthenticationSchemeProvider>();
|
||||||
var provider = new ServiceCollection()
|
var provider = new ServiceCollection()
|
||||||
.BuildServiceProvider();
|
.BuildServiceProvider();
|
||||||
_configurationValidator = new FileConfigurationFluentValidator(_authProvider.Object, provider);
|
// Todo - replace with mocks
|
||||||
|
_configurationValidator = new FileConfigurationFluentValidator(provider, new ReRouteFluentValidator(_authProvider.Object, new HostAndPortValidator(), new FileQoSOptionsFluentValidator(provider)), new FileGlobalConfigurationFluentValidator(new FileQoSOptionsFluentValidator(provider)));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -766,10 +767,11 @@
|
|||||||
.Then(x => x.ThenTheResultIsNotValid())
|
.Then(x => x.ThenTheResultIsNotValid())
|
||||||
.Then(x => x.ThenTheErrorIs<FileValidationFailedError>())
|
.Then(x => x.ThenTheErrorIs<FileValidationFailedError>())
|
||||||
.And(x => x.ThenTheErrorMessageAtPositionIs(0, "Downstream Path Template http://www.bbc.co.uk/api/products/{productId} doesnt start with forward slash"))
|
.And(x => x.ThenTheErrorMessageAtPositionIs(0, "Downstream Path Template http://www.bbc.co.uk/api/products/{productId} doesnt start with forward slash"))
|
||||||
.And(x => x.ThenTheErrorMessageAtPositionIs(1, "Upstream Path Template http://asdf.com contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature."))
|
.And(x => x.ThenTheErrorMessageAtPositionIs(1, "Downstream Path Template http://www.bbc.co.uk/api/products/{productId} contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature."))
|
||||||
.And(x => x.ThenTheErrorMessageAtPositionIs(2, "Downstream Path Template http://www.bbc.co.uk/api/products/{productId} contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature."))
|
.And(x => x.ThenTheErrorMessageAtPositionIs(2, "Downstream Path Template http://www.bbc.co.uk/api/products/{productId} contains scheme"))
|
||||||
.And(x => x.ThenTheErrorMessageAtPositionIs(3, "Upstream Path Template http://asdf.com doesnt start with forward slash"))
|
|
||||||
.And(x => x.ThenTheErrorMessageAtPositionIs(4, "Downstream Path Template http://www.bbc.co.uk/api/products/{productId} contains scheme"))
|
.And(x => x.ThenTheErrorMessageAtPositionIs(3, "Upstream Path Template http://asdf.com contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature."))
|
||||||
|
.And(x => x.ThenTheErrorMessageAtPositionIs(4, "Upstream Path Template http://asdf.com doesnt start with forward slash"))
|
||||||
.And(x => x.ThenTheErrorMessageAtPositionIs(5, "Upstream Path Template http://asdf.com contains scheme"))
|
.And(x => x.ThenTheErrorMessageAtPositionIs(5, "Upstream Path Template http://asdf.com contains scheme"))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
@ -947,7 +949,7 @@
|
|||||||
}))
|
}))
|
||||||
.When(x => x.WhenIValidateTheConfiguration())
|
.When(x => x.WhenIValidateTheConfiguration())
|
||||||
.Then(x => x.ThenTheResultIsNotValid())
|
.Then(x => x.ThenTheResultIsNotValid())
|
||||||
.And(x => x.ThenTheErrorMessageAtPositionIs(0, "AuthenticationProviderKey:Test,AllowedScopes:[] is unsupported authentication provider"))
|
.And(x => x.ThenTheErrorMessageAtPositionIs(0, "Authentication Options AuthenticationProviderKey:Test,AllowedScopes:[] is unsupported authentication provider"))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1140,7 +1142,7 @@
|
|||||||
}))
|
}))
|
||||||
.When(x => x.WhenIValidateTheConfiguration())
|
.When(x => x.WhenIValidateTheConfiguration())
|
||||||
.Then(x => x.ThenTheResultIsNotValid())
|
.Then(x => x.ThenTheResultIsNotValid())
|
||||||
.And(x => x.ThenTheErrorMessageAtPositionIs(0, "RateLimitOptions.Period does not contains (s,m,h,d)"))
|
.And(x => x.ThenTheErrorMessageAtPositionIs(0, "RateLimitOptions.Period does not contain integer then s (second), m (minute), h (hour), d (day) e.g. 1m for 1 minute period"))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1383,7 +1385,7 @@
|
|||||||
QosDelegatingHandlerDelegate del = (a,b) => new FakeDelegatingHandler();
|
QosDelegatingHandlerDelegate del = (a,b) => new FakeDelegatingHandler();
|
||||||
collection.AddSingleton<QosDelegatingHandlerDelegate>(del);
|
collection.AddSingleton<QosDelegatingHandlerDelegate>(del);
|
||||||
var provider = collection.BuildServiceProvider();
|
var provider = collection.BuildServiceProvider();
|
||||||
_configurationValidator = new FileConfigurationFluentValidator(_authProvider.Object, provider);
|
_configurationValidator = new FileConfigurationFluentValidator(provider, new ReRouteFluentValidator(_authProvider.Object, new HostAndPortValidator(), new FileQoSOptionsFluentValidator(provider)), new FileGlobalConfigurationFluentValidator(new FileQoSOptionsFluentValidator(provider)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenAServiceDiscoveryHandler()
|
private void GivenAServiceDiscoveryHandler()
|
||||||
@ -1392,7 +1394,7 @@
|
|||||||
ServiceDiscoveryFinderDelegate del = (a,b,c) => new FakeServiceDiscoveryProvider();
|
ServiceDiscoveryFinderDelegate del = (a,b,c) => new FakeServiceDiscoveryProvider();
|
||||||
collection.AddSingleton<ServiceDiscoveryFinderDelegate>(del);
|
collection.AddSingleton<ServiceDiscoveryFinderDelegate>(del);
|
||||||
var provider = collection.BuildServiceProvider();
|
var provider = collection.BuildServiceProvider();
|
||||||
_configurationValidator = new FileConfigurationFluentValidator(_authProvider.Object, provider);
|
_configurationValidator = new FileConfigurationFluentValidator(provider, new ReRouteFluentValidator(_authProvider.Object, new HostAndPortValidator(), new FileQoSOptionsFluentValidator(provider)), new FileGlobalConfigurationFluentValidator(new FileQoSOptionsFluentValidator(provider)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FakeServiceDiscoveryProvider : IServiceDiscoveryProvider
|
private class FakeServiceDiscoveryProvider : IServiceDiscoveryProvider
|
@ -0,0 +1,106 @@
|
|||||||
|
using System;
|
||||||
|
using FluentValidation.Results;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Moq;
|
||||||
|
using Ocelot.Configuration.File;
|
||||||
|
using Ocelot.Configuration.Validator;
|
||||||
|
using Ocelot.Requester;
|
||||||
|
using Shouldly;
|
||||||
|
using TestStack.BDDfy;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Ocelot.UnitTests.Configuration.Validation
|
||||||
|
{
|
||||||
|
public class FileQoSOptionsFluentValidatorTests
|
||||||
|
{
|
||||||
|
private FileQoSOptionsFluentValidator _validator;
|
||||||
|
private ServiceCollection _services;
|
||||||
|
private ValidationResult _result;
|
||||||
|
private FileQoSOptions _qosOptions;
|
||||||
|
|
||||||
|
public FileQoSOptionsFluentValidatorTests()
|
||||||
|
{
|
||||||
|
_services = new ServiceCollection();
|
||||||
|
var provider = _services.BuildServiceProvider();
|
||||||
|
_validator = new FileQoSOptionsFluentValidator(provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_be_valid_as_nothing_set()
|
||||||
|
{
|
||||||
|
this.Given(_ => GivenThe(new FileQoSOptions()))
|
||||||
|
.When(_ => WhenIValidate())
|
||||||
|
.Then(_ => ThenTheResultIsValid())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_be_valid_as_qos_delegate_set()
|
||||||
|
{
|
||||||
|
var qosOptions = new FileQoSOptions
|
||||||
|
{
|
||||||
|
TimeoutValue = 1,
|
||||||
|
ExceptionsAllowedBeforeBreaking = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Given(_ => GivenThe(qosOptions))
|
||||||
|
.And(_ => GivenAQosDelegate())
|
||||||
|
.When(_ => WhenIValidate())
|
||||||
|
.Then(_ => ThenTheResultIsValid())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_be_invalid_as_no_qos_delegate()
|
||||||
|
{
|
||||||
|
var qosOptions = new FileQoSOptions
|
||||||
|
{
|
||||||
|
TimeoutValue = 1,
|
||||||
|
ExceptionsAllowedBeforeBreaking = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Given(_ => GivenThe(qosOptions))
|
||||||
|
.When(_ => WhenIValidate())
|
||||||
|
.Then(_ => ThenTheResultIsInValid())
|
||||||
|
.And(_ => ThenTheErrorIs())
|
||||||
|
.BDDfy();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenTheErrorIs()
|
||||||
|
{
|
||||||
|
_result.Errors[0].ErrorMessage.ShouldBe("Unable to start Ocelot because either a ReRoute or GlobalConfiguration are using QoSOptions but no QosDelegatingHandlerDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Polly and services.AddPolly()?");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenTheResultIsInValid()
|
||||||
|
{
|
||||||
|
_result.IsValid.ShouldBeFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenAQosDelegate()
|
||||||
|
{
|
||||||
|
QosDelegatingHandlerDelegate fake = (a, b) =>
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
_services.AddSingleton<QosDelegatingHandlerDelegate>(fake);
|
||||||
|
var provider = _services.BuildServiceProvider();
|
||||||
|
_validator = new FileQoSOptionsFluentValidator(provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenThe(FileQoSOptions qosOptions)
|
||||||
|
{
|
||||||
|
_qosOptions = qosOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WhenIValidate()
|
||||||
|
{
|
||||||
|
_result = _validator.Validate(_qosOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenTheResultIsValid()
|
||||||
|
{
|
||||||
|
_result.IsValid.ShouldBeTrue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
using System;
|
||||||
|
using FluentValidation.Results;
|
||||||
|
using Ocelot.Configuration.File;
|
||||||
|
using Ocelot.Configuration.Validator;
|
||||||
|
using Shouldly;
|
||||||
|
using TestStack.BDDfy;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Ocelot.UnitTests.Configuration.Validation
|
||||||
|
{
|
||||||
|
public class HostAndPortValidatorTests
|
||||||
|
{
|
||||||
|
private HostAndPortValidator _validator;
|
||||||
|
private ValidationResult _result;
|
||||||
|
private FileHostAndPort _hostAndPort;
|
||||||
|
|
||||||
|
public HostAndPortValidatorTests()
|
||||||
|
{
|
||||||
|
_validator = new HostAndPortValidator();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(null)]
|
||||||
|
[InlineData("")]
|
||||||
|
public void should_be_invalid_because_host_empty(string host)
|
||||||
|
{
|
||||||
|
var fileHostAndPort = new FileHostAndPort
|
||||||
|
{
|
||||||
|
Host = host
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Given(_ => GivenThe(fileHostAndPort))
|
||||||
|
.When(_ => WhenIValidate())
|
||||||
|
.Then(_ => ThenTheResultIsInValid())
|
||||||
|
.And(_ => ThenTheErorrIs())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_be_valid_because_host_set()
|
||||||
|
{
|
||||||
|
var fileHostAndPort = new FileHostAndPort
|
||||||
|
{
|
||||||
|
Host = "test"
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Given(_ => GivenThe(fileHostAndPort))
|
||||||
|
.When(_ => WhenIValidate())
|
||||||
|
.Then(_ => ThenTheResultIsValid())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenThe(FileHostAndPort hostAndPort)
|
||||||
|
{
|
||||||
|
_hostAndPort = hostAndPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WhenIValidate()
|
||||||
|
{
|
||||||
|
_result = _validator.Validate(_hostAndPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenTheResultIsValid()
|
||||||
|
{
|
||||||
|
_result.IsValid.ShouldBeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenTheErorrIs()
|
||||||
|
{
|
||||||
|
_result.Errors[0].ErrorMessage.ShouldBe("When not using service discovery Host must be set on DownstreamHostAndPorts if you are not using ReRoute.Host or Ocelot cannot find your service!");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenTheResultIsInValid()
|
||||||
|
{
|
||||||
|
_result.IsValid.ShouldBeFalse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,368 @@
|
|||||||
|
namespace Ocelot.UnitTests.Configuration.Validation
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using FluentValidation.Results;
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Moq;
|
||||||
|
using Ocelot.Configuration.File;
|
||||||
|
using Ocelot.Configuration.Validator;
|
||||||
|
using Ocelot.Requester;
|
||||||
|
using Shouldly;
|
||||||
|
using TestStack.BDDfy;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
public class ReRouteFluentValidatorTests
|
||||||
|
{
|
||||||
|
private readonly ReRouteFluentValidator _validator;
|
||||||
|
private readonly Mock<IAuthenticationSchemeProvider> _authProvider;
|
||||||
|
private QosDelegatingHandlerDelegate _qosDelegatingHandler;
|
||||||
|
private Mock<IServiceProvider> _serviceProvider;
|
||||||
|
private FileReRoute _reRoute;
|
||||||
|
private ValidationResult _result;
|
||||||
|
|
||||||
|
public ReRouteFluentValidatorTests()
|
||||||
|
{
|
||||||
|
_authProvider = new Mock<IAuthenticationSchemeProvider>();
|
||||||
|
_serviceProvider = new Mock<IServiceProvider>();
|
||||||
|
// Todo - replace with mocks
|
||||||
|
_validator = new ReRouteFluentValidator(_authProvider.Object, new HostAndPortValidator(), new FileQoSOptionsFluentValidator(_serviceProvider.Object));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void downstream_path_template_should_not_be_empty()
|
||||||
|
{
|
||||||
|
var fileReRoute = new FileReRoute();
|
||||||
|
|
||||||
|
this.Given(_ => GivenThe(fileReRoute))
|
||||||
|
.When(_ => WhenIValidate())
|
||||||
|
.Then(_ => ThenTheResultIsInvalid())
|
||||||
|
.And(_ => ThenTheErrorsContains("Downstream Path Template cannot be empty"))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void upstream_path_template_should_not_be_empty()
|
||||||
|
{
|
||||||
|
var fileReRoute = new FileReRoute
|
||||||
|
{
|
||||||
|
DownstreamPathTemplate = "test"
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Given(_ => GivenThe(fileReRoute))
|
||||||
|
.When(_ => WhenIValidate())
|
||||||
|
.Then(_ => ThenTheResultIsInvalid())
|
||||||
|
.And(_ => ThenTheErrorsContains("Upstream Path Template cannot be empty"))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void downstream_path_template_should_start_with_forward_slash()
|
||||||
|
{
|
||||||
|
var fileReRoute = new FileReRoute
|
||||||
|
{
|
||||||
|
DownstreamPathTemplate = "test"
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Given(_ => GivenThe(fileReRoute))
|
||||||
|
.When(_ => WhenIValidate())
|
||||||
|
.Then(_ => ThenTheResultIsInvalid())
|
||||||
|
.And(_ => ThenTheErrorsContains("Downstream Path Template test doesnt start with forward slash"))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void downstream_path_template_should_not_contain_double_forward_slash()
|
||||||
|
{
|
||||||
|
var fileReRoute = new FileReRoute
|
||||||
|
{
|
||||||
|
DownstreamPathTemplate = "//test"
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Given(_ => GivenThe(fileReRoute))
|
||||||
|
.When(_ => WhenIValidate())
|
||||||
|
.Then(_ => ThenTheResultIsInvalid())
|
||||||
|
.And(_ => ThenTheErrorsContains("Downstream Path Template //test contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature."))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("https://test")]
|
||||||
|
[InlineData("http://test")]
|
||||||
|
[InlineData("/test/http://")]
|
||||||
|
[InlineData("/test/https://")]
|
||||||
|
public void downstream_path_template_should_not_contain_scheme(string downstreamPathTemplate)
|
||||||
|
{
|
||||||
|
var fileReRoute = new FileReRoute
|
||||||
|
{
|
||||||
|
DownstreamPathTemplate = downstreamPathTemplate
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Given(_ => GivenThe(fileReRoute))
|
||||||
|
.When(_ => WhenIValidate())
|
||||||
|
.Then(_ => ThenTheResultIsInvalid())
|
||||||
|
.And(_ => ThenTheErrorsContains($"Downstream Path Template {downstreamPathTemplate} contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature."))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void upstream_path_template_should_start_with_forward_slash()
|
||||||
|
{
|
||||||
|
var fileReRoute = new FileReRoute
|
||||||
|
{
|
||||||
|
DownstreamPathTemplate = "/test",
|
||||||
|
UpstreamPathTemplate = "test"
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Given(_ => GivenThe(fileReRoute))
|
||||||
|
.When(_ => WhenIValidate())
|
||||||
|
.Then(_ => ThenTheResultIsInvalid())
|
||||||
|
.And(_ => ThenTheErrorsContains("Upstream Path Template test doesnt start with forward slash"))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void upstream_path_template_should_not_contain_double_forward_slash()
|
||||||
|
{
|
||||||
|
var fileReRoute = new FileReRoute
|
||||||
|
{
|
||||||
|
DownstreamPathTemplate = "/test",
|
||||||
|
UpstreamPathTemplate = "//test"
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Given(_ => GivenThe(fileReRoute))
|
||||||
|
.When(_ => WhenIValidate())
|
||||||
|
.Then(_ => ThenTheResultIsInvalid())
|
||||||
|
.And(_ => ThenTheErrorsContains("Upstream Path Template //test contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature."))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("https://test")]
|
||||||
|
[InlineData("http://test")]
|
||||||
|
[InlineData("/test/http://")]
|
||||||
|
[InlineData("/test/https://")]
|
||||||
|
public void upstream_path_template_should_not_contain_scheme(string upstreamPathTemplate)
|
||||||
|
{
|
||||||
|
var fileReRoute = new FileReRoute
|
||||||
|
{
|
||||||
|
DownstreamPathTemplate = "/test",
|
||||||
|
UpstreamPathTemplate = upstreamPathTemplate
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Given(_ => GivenThe(fileReRoute))
|
||||||
|
.When(_ => WhenIValidate())
|
||||||
|
.Then(_ => ThenTheResultIsInvalid())
|
||||||
|
.And(_ => ThenTheErrorsContains($"Upstream Path Template {upstreamPathTemplate} contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature."))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_not_be_valid_if_enable_rate_limiting_true_and_period_is_empty()
|
||||||
|
{
|
||||||
|
var fileReRoute = new FileReRoute
|
||||||
|
{
|
||||||
|
DownstreamPathTemplate = "/test",
|
||||||
|
UpstreamPathTemplate = "/test",
|
||||||
|
RateLimitOptions = new FileRateLimitRule
|
||||||
|
{
|
||||||
|
EnableRateLimiting = true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Given(_ => GivenThe(fileReRoute))
|
||||||
|
.When(_ => WhenIValidate())
|
||||||
|
.Then(_ => ThenTheResultIsInvalid())
|
||||||
|
.And(_ => ThenTheErrorsContains("RateLimitOptions.Period is empty"))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_not_be_valid_if_enable_rate_limiting_true_and_period_has_value()
|
||||||
|
{
|
||||||
|
var fileReRoute = new FileReRoute
|
||||||
|
{
|
||||||
|
DownstreamPathTemplate = "/test",
|
||||||
|
UpstreamPathTemplate = "/test",
|
||||||
|
RateLimitOptions = new FileRateLimitRule
|
||||||
|
{
|
||||||
|
EnableRateLimiting = true,
|
||||||
|
Period = "test"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Given(_ => GivenThe(fileReRoute))
|
||||||
|
.When(_ => WhenIValidate())
|
||||||
|
.Then(_ => ThenTheResultIsInvalid())
|
||||||
|
.And(_ => ThenTheErrorsContains("RateLimitOptions.Period does not contain integer then s (second), m (minute), h (hour), d (day) e.g. 1m for 1 minute period"))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_not_be_valid_if_specified_authentication_provider_isnt_registered()
|
||||||
|
{
|
||||||
|
var fileReRoute = new FileReRoute
|
||||||
|
{
|
||||||
|
DownstreamPathTemplate = "/test",
|
||||||
|
UpstreamPathTemplate = "/test",
|
||||||
|
AuthenticationOptions = new FileAuthenticationOptions
|
||||||
|
{
|
||||||
|
AuthenticationProviderKey = "JwtLads"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Given(_ => GivenThe(fileReRoute))
|
||||||
|
.When(_ => WhenIValidate())
|
||||||
|
.Then(_ => ThenTheResultIsInvalid())
|
||||||
|
.And(_ => ThenTheErrorsContains($"Authentication Options AuthenticationProviderKey:JwtLads,AllowedScopes:[] is unsupported authentication provider"))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_not_be_valid_if_not_using_service_discovery_and_no_host_and_ports()
|
||||||
|
{
|
||||||
|
var fileReRoute = new FileReRoute
|
||||||
|
{
|
||||||
|
DownstreamPathTemplate = "/test",
|
||||||
|
UpstreamPathTemplate = "/test",
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Given(_ => GivenThe(fileReRoute))
|
||||||
|
.When(_ => WhenIValidate())
|
||||||
|
.Then(_ => ThenTheResultIsInvalid())
|
||||||
|
.And(_ => ThenTheErrorsContains("When not using service discovery DownstreamHostAndPorts must be set and not empty or Ocelot cannot find your service!"))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_be_valid_if_using_service_discovery_and_no_host_and_ports()
|
||||||
|
{
|
||||||
|
var fileReRoute = new FileReRoute
|
||||||
|
{
|
||||||
|
DownstreamPathTemplate = "/test",
|
||||||
|
UpstreamPathTemplate = "/test",
|
||||||
|
ServiceName = "Lads"
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Given(_ => GivenThe(fileReRoute))
|
||||||
|
.When(_ => WhenIValidate())
|
||||||
|
.Then(_ => ThenTheResultIsValid())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_be_valid_re_route_using_host_and_port_and_paths()
|
||||||
|
{
|
||||||
|
var fileReRoute = new FileReRoute
|
||||||
|
{
|
||||||
|
DownstreamPathTemplate = "/test",
|
||||||
|
UpstreamPathTemplate = "/test",
|
||||||
|
DownstreamHostAndPorts = new List<FileHostAndPort>
|
||||||
|
{
|
||||||
|
new FileHostAndPort
|
||||||
|
{
|
||||||
|
Host = "localhost",
|
||||||
|
Port = 5000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Given(_ => GivenThe(fileReRoute))
|
||||||
|
.When(_ => WhenIValidate())
|
||||||
|
.Then(_ => ThenTheResultIsValid())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_be_valid_if_specified_authentication_provider_is_registered()
|
||||||
|
{
|
||||||
|
const string key = "JwtLads";
|
||||||
|
|
||||||
|
var fileReRoute = new FileReRoute
|
||||||
|
{
|
||||||
|
DownstreamPathTemplate = "/test",
|
||||||
|
UpstreamPathTemplate = "/test",
|
||||||
|
AuthenticationOptions = new FileAuthenticationOptions
|
||||||
|
{
|
||||||
|
AuthenticationProviderKey = key
|
||||||
|
},
|
||||||
|
DownstreamHostAndPorts = new List<FileHostAndPort>
|
||||||
|
{
|
||||||
|
new FileHostAndPort
|
||||||
|
{
|
||||||
|
Host = "localhost",
|
||||||
|
Port = 5000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Given(_ => GivenThe(fileReRoute))
|
||||||
|
.And(_ => GivenAnAuthProvider(key))
|
||||||
|
.When(_ => WhenIValidate())
|
||||||
|
.Then(_ => ThenTheResultIsValid())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenAnAuthProvider(string key)
|
||||||
|
{
|
||||||
|
var schemes = new List<AuthenticationScheme>
|
||||||
|
{
|
||||||
|
new AuthenticationScheme(key, key, typeof(FakeAutheHandler))
|
||||||
|
};
|
||||||
|
|
||||||
|
_authProvider
|
||||||
|
.Setup(x => x.GetAllSchemesAsync())
|
||||||
|
.ReturnsAsync(schemes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenTheResultIsValid()
|
||||||
|
{
|
||||||
|
_result.IsValid.ShouldBeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenThe(FileReRoute reRoute)
|
||||||
|
{
|
||||||
|
_reRoute = reRoute;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WhenIValidate()
|
||||||
|
{
|
||||||
|
_result = _validator.Validate(_reRoute);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenTheResultIsInvalid()
|
||||||
|
{
|
||||||
|
_result.IsValid.ShouldBeFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenTheErrorsContains(string expected)
|
||||||
|
{
|
||||||
|
_result.Errors.ShouldContain(x => x.ErrorMessage == expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
class FakeAutheHandler : IAuthenticationHandler
|
||||||
|
{
|
||||||
|
public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<AuthenticateResult> AuthenticateAsync()
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task ChallengeAsync(AuthenticationProperties properties)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task ForbidAsync(AuthenticationProperties properties)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user