mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 09:55:28 +08:00 
			
		
		
		
	refactoring ocelot config creation process
This commit is contained in:
		@@ -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();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										41
									
								
								src/Ocelot/Configuration/Creator/ClaimsToThingCreator.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/Ocelot/Configuration/Creator/ClaimsToThingCreator.cs
									
									
									
									
									
										Normal 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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -22,36 +22,38 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IOptions<FileConfiguration> _options;
 | 
			
		||||
        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 ILoadBalancerFactory _loadBalanceFactory;
 | 
			
		||||
        private readonly ILoadBalancerHouse _loadBalancerHouse;
 | 
			
		||||
        private readonly IQoSProviderFactory _qoSProviderFactory;
 | 
			
		||||
        private readonly IQosProviderHouse _qosProviderHouse;
 | 
			
		||||
        private readonly IClaimsToThingCreator _claimsToThingCreator;
 | 
			
		||||
        private readonly IAuthenticationOptionsCreator _authOptionsCreator;
 | 
			
		||||
        private IUpstreamTemplatePatternCreator _upstreamTemplatePatternCreator;
 | 
			
		||||
 | 
			
		||||
        public FileOcelotConfigurationCreator(
 | 
			
		||||
            IOptions<FileConfiguration> options, 
 | 
			
		||||
            IConfigurationValidator configurationValidator, 
 | 
			
		||||
            IClaimToThingConfigurationParser claimToThingConfigurationParser, 
 | 
			
		||||
            ILogger<FileOcelotConfigurationCreator> logger,
 | 
			
		||||
            ILoadBalancerFactory loadBalancerFactory,
 | 
			
		||||
            ILoadBalancerHouse loadBalancerHouse, 
 | 
			
		||||
            IQoSProviderFactory qoSProviderFactory, 
 | 
			
		||||
            IQosProviderHouse qosProviderHouse)
 | 
			
		||||
            IQosProviderHouse qosProviderHouse,
 | 
			
		||||
            IClaimsToThingCreator claimsToThingCreator,
 | 
			
		||||
            IAuthenticationOptionsCreator authOptionsCreator,
 | 
			
		||||
            IUpstreamTemplatePatternCreator upstreamTemplatePatternCreator)
 | 
			
		||||
        {
 | 
			
		||||
            _upstreamTemplatePatternCreator = upstreamTemplatePatternCreator;
 | 
			
		||||
            _authOptionsCreator = authOptionsCreator;
 | 
			
		||||
            _loadBalanceFactory = loadBalancerFactory;
 | 
			
		||||
            _loadBalancerHouse = loadBalancerHouse;
 | 
			
		||||
            _qoSProviderFactory = qoSProviderFactory;
 | 
			
		||||
            _qosProviderHouse = qosProviderHouse;
 | 
			
		||||
            _options = options;
 | 
			
		||||
            _configurationValidator = configurationValidator;
 | 
			
		||||
            _claimToThingConfigurationParser = claimToThingConfigurationParser;
 | 
			
		||||
            _logger = logger;
 | 
			
		||||
            _claimsToThingCreator = claimsToThingCreator;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<Response<IOcelotConfiguration>> Create()
 | 
			
		||||
@@ -107,19 +109,19 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
 | 
			
		||||
            var reRouteKey = BuildReRouteKey(fileReRoute);
 | 
			
		||||
 | 
			
		||||
            var upstreamTemplatePattern = BuildUpstreamTemplatePattern(fileReRoute);
 | 
			
		||||
            var upstreamTemplatePattern = _upstreamTemplatePatternCreator.Create(fileReRoute);
 | 
			
		||||
 | 
			
		||||
            var isQos = IsQoS(fileReRoute);
 | 
			
		||||
 | 
			
		||||
            var serviceProviderConfiguration = BuildServiceProviderConfiguration(fileReRoute, globalConfiguration);
 | 
			
		||||
 | 
			
		||||
            var authOptionsForRoute = BuildAuthenticationOptions(fileReRoute);
 | 
			
		||||
            var authOptionsForRoute = _authOptionsCreator.Create(fileReRoute);
 | 
			
		||||
 | 
			
		||||
            var claimsToHeaders = BuildAddThingsToRequest(fileReRoute.AddHeadersToRequest);
 | 
			
		||||
            var claimsToHeaders = _claimsToThingCreator.Create(fileReRoute.AddHeadersToRequest);
 | 
			
		||||
 | 
			
		||||
            var claimsToClaims = BuildAddThingsToRequest(fileReRoute.AddClaimsToRequest);
 | 
			
		||||
            var claimsToClaims = _claimsToThingCreator.Create(fileReRoute.AddClaimsToRequest);
 | 
			
		||||
 | 
			
		||||
            var claimsToQueries = BuildAddThingsToRequest(fileReRoute.AddQueriesToRequest);
 | 
			
		||||
            var claimsToQueries = _claimsToThingCreator.Create(fileReRoute.AddQueriesToRequest);
 | 
			
		||||
 | 
			
		||||
            var qosOptions = BuildQoSOptions(fileReRoute);
 | 
			
		||||
 | 
			
		||||
@@ -153,6 +155,7 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
                .WithEnableRateLimiting(enableRateLimiting)
 | 
			
		||||
                .WithRateLimitOptions(rateLimitOption)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            await SetupLoadBalancer(reRoute);
 | 
			
		||||
            SetupQosProvider(reRoute);
 | 
			
		||||
            return reRoute;
 | 
			
		||||
@@ -225,18 +228,6 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
            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)
 | 
			
		||||
        {
 | 
			
		||||
            var loadBalancer = await _loadBalanceFactory.Get(reRoute);
 | 
			
		||||
@@ -267,63 +258,6 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
                    .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] == '{';
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Creator
 | 
			
		||||
{
 | 
			
		||||
    public interface IAuthenticationOptionsCreator
 | 
			
		||||
    {
 | 
			
		||||
        AuthenticationOptions Create(FileReRoute fileReRoute);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Creator
 | 
			
		||||
{
 | 
			
		||||
    public interface IClaimsToThingCreator
 | 
			
		||||
    {
 | 
			
		||||
        List<ClaimToThing> Create(Dictionary<string,string> thingsBeingAdded);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Creator
 | 
			
		||||
{
 | 
			
		||||
    public interface IUpstreamTemplatePatternCreator
 | 
			
		||||
    {
 | 
			
		||||
        string Create(FileReRoute reRoute);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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] == '{';
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -60,6 +60,9 @@ namespace Ocelot.DependencyInjection
 | 
			
		||||
            services.AddSingleton<IOcelotConfigurationRepository, InMemoryOcelotConfigurationRepository>();
 | 
			
		||||
            services.AddSingleton<IConfigurationValidator, FileConfigurationValidator>();
 | 
			
		||||
            services.AddSingleton<IBaseUrlFinder, BaseUrlFinder>();
 | 
			
		||||
            services.AddSingleton<IClaimsToThingCreator, ClaimsToThingCreator>();
 | 
			
		||||
            services.AddSingleton<IAuthenticationOptionsCreator, AuthenticationOptionsCreator>();
 | 
			
		||||
            services.AddSingleton<IUpstreamTemplatePatternCreator, UpstreamTemplatePatternCreator>();
 | 
			
		||||
 | 
			
		||||
            var identityServerConfiguration = IdentityServerConfigurationCreator.GetIdentityServerConfiguration();
 | 
			
		||||
            
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										110
									
								
								test/Ocelot.UnitTests/Configuration/ClaimsToThingCreatorTests.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								test/Ocelot.UnitTests/Configuration/ClaimsToThingCreatorTests.cs
									
									
									
									
									
										Normal 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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -23,7 +23,6 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
        private readonly Mock<IConfigurationValidator> _validator;
 | 
			
		||||
        private Response<IOcelotConfiguration> _config;
 | 
			
		||||
        private FileConfiguration _fileConfiguration;
 | 
			
		||||
        private readonly Mock<IClaimToThingConfigurationParser> _configParser;
 | 
			
		||||
        private readonly Mock<ILogger<FileOcelotConfigurationCreator>> _logger;
 | 
			
		||||
        private readonly FileOcelotConfigurationCreator _ocelotConfigurationCreator;
 | 
			
		||||
        private readonly Mock<ILoadBalancerFactory> _loadBalancerFactory;
 | 
			
		||||
@@ -32,6 +31,9 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
        private readonly Mock<IQoSProviderFactory> _qosProviderFactory;
 | 
			
		||||
        private readonly Mock<IQosProviderHouse> _qosProviderHouse;
 | 
			
		||||
        private readonly Mock<IQoSProvider> _qosProvider;
 | 
			
		||||
        private Mock<IClaimsToThingCreator> _claimsToThingCreator;
 | 
			
		||||
        private Mock<IAuthenticationOptionsCreator> _authOptionsCreator;
 | 
			
		||||
        private Mock<IUpstreamTemplatePatternCreator> _upstreamTemplatePatternCreator;
 | 
			
		||||
 | 
			
		||||
        public FileConfigurationCreatorTests()
 | 
			
		||||
        {
 | 
			
		||||
@@ -39,16 +41,20 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
            _qosProviderHouse = new Mock<IQosProviderHouse>();
 | 
			
		||||
            _qosProvider = new Mock<IQoSProvider>();
 | 
			
		||||
            _logger = new Mock<ILogger<FileOcelotConfigurationCreator>>();
 | 
			
		||||
            _configParser = new Mock<IClaimToThingConfigurationParser>();
 | 
			
		||||
            _validator = new Mock<IConfigurationValidator>();
 | 
			
		||||
            _fileConfig = new Mock<IOptions<FileConfiguration>>();
 | 
			
		||||
            _loadBalancerFactory = new Mock<ILoadBalancerFactory>();
 | 
			
		||||
            _loadBalancerHouse = new Mock<ILoadBalancerHouse>();
 | 
			
		||||
            _loadBalancer = new Mock<ILoadBalancer>();
 | 
			
		||||
            _claimsToThingCreator = new Mock<IClaimsToThingCreator>();
 | 
			
		||||
            _authOptionsCreator = new Mock<IAuthenticationOptionsCreator>();
 | 
			
		||||
            _upstreamTemplatePatternCreator = new Mock<IUpstreamTemplatePatternCreator>();
 | 
			
		||||
 | 
			
		||||
            _ocelotConfigurationCreator = new FileOcelotConfigurationCreator( 
 | 
			
		||||
                _fileConfig.Object, _validator.Object, _configParser.Object, _logger.Object,
 | 
			
		||||
                _fileConfig.Object, _validator.Object, _logger.Object,
 | 
			
		||||
                _loadBalancerFactory.Object, _loadBalancerHouse.Object, 
 | 
			
		||||
                _qosProviderFactory.Object, _qosProviderHouse.Object);
 | 
			
		||||
                _qosProviderFactory.Object, _qosProviderHouse.Object, _claimsToThingCreator.Object,
 | 
			
		||||
                _authOptionsCreator.Object, _upstreamTemplatePatternCreator.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
@@ -130,7 +136,6 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                                        .WithDownstreamPathTemplate("/products/{productId}")
 | 
			
		||||
                                        .WithUpstreamPathTemplate("/api/products/{productId}")
 | 
			
		||||
                                        .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                                        .WithUpstreamTemplatePattern("(?i)/api/products/.*/$")
 | 
			
		||||
                                        .Build()
 | 
			
		||||
                                }))
 | 
			
		||||
                    .BDDfy();
 | 
			
		||||
@@ -161,7 +166,6 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                                                    .WithDownstreamPathTemplate("/products/{productId}")
 | 
			
		||||
                                                    .WithUpstreamPathTemplate("/api/products/{productId}")
 | 
			
		||||
                                                    .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                                                    .WithUpstreamTemplatePattern("(?i)/api/products/.*/$")
 | 
			
		||||
                                                    .Build()
 | 
			
		||||
                                            }))
 | 
			
		||||
                                .BDDfy();
 | 
			
		||||
@@ -200,7 +204,6 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                                    .WithDownstreamPathTemplate("/products/{productId}")
 | 
			
		||||
                                    .WithUpstreamPathTemplate("/api/products/{productId}")
 | 
			
		||||
                                    .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                                    .WithUpstreamTemplatePattern("(?i)/api/products/.*/$")
 | 
			
		||||
                                    .WithServiceProviderConfiguraion(new ServiceProviderConfiguraionBuilder()
 | 
			
		||||
                                        .WithUseServiceDiscovery(true)
 | 
			
		||||
                                        .WithServiceDiscoveryProvider("consul")
 | 
			
		||||
@@ -236,7 +239,6 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                                    .WithDownstreamPathTemplate("/products/{productId}")
 | 
			
		||||
                                    .WithUpstreamPathTemplate("/api/products/{productId}")
 | 
			
		||||
                                    .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                                    .WithUpstreamTemplatePattern("(?i)/api/products/.*/$")
 | 
			
		||||
                                    .WithServiceProviderConfiguraion(new ServiceProviderConfiguraionBuilder()
 | 
			
		||||
                                        .WithUseServiceDiscovery(false)
 | 
			
		||||
                                        .Build())
 | 
			
		||||
@@ -246,7 +248,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_use_reroute_case_sensitivity_value()
 | 
			
		||||
        public void should_call_template_pattern_creator_correctly()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenTheConfigIs(new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
@@ -262,6 +264,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                }
 | 
			
		||||
            }))
 | 
			
		||||
                .And(x => x.GivenTheConfigIsValid())
 | 
			
		||||
                .And(x => x.GivenTheUpstreamTemplatePatternCreatorReturns("(?i)/api/products/.*/$"))
 | 
			
		||||
                .When(x => x.WhenICreateTheConfig())
 | 
			
		||||
                .Then(x => x.ThenTheReRoutesAre(new List<ReRoute>
 | 
			
		||||
                {
 | 
			
		||||
@@ -275,65 +278,6 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_set_upstream_template_pattern_to_ignore_case_sensitivity()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenTheConfigIs(new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                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()
 | 
			
		||||
        {
 | 
			
		||||
@@ -362,43 +306,12 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                        .WithDownstreamPathTemplate("/products/{productId}")
 | 
			
		||||
                        .WithUpstreamPathTemplate("/api/products/{productId}")
 | 
			
		||||
                        .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                        .WithUpstreamTemplatePattern("/api/products/.*/$")
 | 
			
		||||
                        .WithRequestIdKey("blahhhh")
 | 
			
		||||
                        .Build()
 | 
			
		||||
                }))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [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();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_create_with_headers_to_extract()
 | 
			
		||||
        {
 | 
			
		||||
@@ -417,7 +330,6 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                    .WithDownstreamPathTemplate("/products/{productId}")
 | 
			
		||||
                    .WithUpstreamPathTemplate("/api/products/{productId}")
 | 
			
		||||
                    .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                    .WithUpstreamTemplatePattern("/api/products/.*/$")
 | 
			
		||||
                    .WithAuthenticationOptions(authenticationOptions)
 | 
			
		||||
                    .WithClaimsToHeaders(new List<ClaimToThing>
 | 
			
		||||
                    {
 | 
			
		||||
@@ -453,20 +365,17 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                }
 | 
			
		||||
            }))
 | 
			
		||||
                .And(x => x.GivenTheConfigIsValid())
 | 
			
		||||
                .And(x => x.GivenTheConfigHeaderExtractorReturns(new ClaimToThing("CustomerId", "CustomerId", "", 0)))
 | 
			
		||||
                .And(x => x.GivenTheAuthOptionsCreatorReturns(authenticationOptions))
 | 
			
		||||
                .And(x => x.GivenTheClaimsToThingCreatorReturns(new List<ClaimToThing>{new ClaimToThing("CustomerId", "CustomerId", "", 0)}))
 | 
			
		||||
                .And(x => x.GivenTheLoadBalancerFactoryReturns())
 | 
			
		||||
                .When(x => x.WhenICreateTheConfig())
 | 
			
		||||
                .Then(x => x.ThenTheReRoutesAre(expected))
 | 
			
		||||
                .And(x => x.ThenTheAuthenticationOptionsAre(expected))
 | 
			
		||||
                .And(x => x.ThenTheAuthOptionsCreatorIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheConfigHeaderExtractorReturns(ClaimToThing expected)
 | 
			
		||||
        {
 | 
			
		||||
            _configParser
 | 
			
		||||
                .Setup(x => x.Extract(It.IsAny<string>(), It.IsAny<string>()))
 | 
			
		||||
                .Returns(new OkResponse<ClaimToThing>(expected));
 | 
			
		||||
        }
 | 
			
		||||
   
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_create_with_authentication_properties()
 | 
			
		||||
@@ -486,7 +395,6 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                    .WithDownstreamPathTemplate("/products/{productId}")
 | 
			
		||||
                    .WithUpstreamPathTemplate("/api/products/{productId}")
 | 
			
		||||
                    .WithUpstreamHttpMethod("Get")
 | 
			
		||||
                    .WithUpstreamTemplatePattern("/api/products/.*/$")
 | 
			
		||||
                    .WithAuthenticationOptions(authenticationOptions)
 | 
			
		||||
                    .Build()
 | 
			
		||||
            };
 | 
			
		||||
@@ -514,100 +422,12 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                }
 | 
			
		||||
            }))
 | 
			
		||||
                .And(x => x.GivenTheConfigIsValid())
 | 
			
		||||
                .And(x => x.GivenTheAuthOptionsCreatorReturns(authenticationOptions))
 | 
			
		||||
                .And(x => x.GivenTheLoadBalancerFactoryReturns())
 | 
			
		||||
                .When(x => x.WhenICreateTheConfig())
 | 
			
		||||
                .Then(x => x.ThenTheReRoutesAre(expected))
 | 
			
		||||
                .And(x => x.ThenTheAuthenticationOptionsAre(expected))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_create_template_pattern_that_matches_more_than_one_placeholder()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenTheConfigIs(new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                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_more_than_one_placeholder_with_trailing_slash()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenTheConfigIs(new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                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()
 | 
			
		||||
                }))
 | 
			
		||||
                .And(x => x.ThenTheAuthOptionsCreatorIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -642,6 +462,9 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                result.UpstreamHttpMethod.ShouldBe(expected.UpstreamHttpMethod);
 | 
			
		||||
                result.UpstreamPathTemplate.Value.ShouldBe(expected.UpstreamPathTemplate.Value);
 | 
			
		||||
                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);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -699,5 +522,32 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
            _qosProviderHouse
 | 
			
		||||
                .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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user