mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 16:10:50 +08:00 
			
		
		
		
	Remove Ocelot specific Middleware to make Ocelot more compatible with kestrel middleware and get ready for YARP
This commit is contained in:
		
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -189,7 +189,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                _services = services;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public async Task<Response<ServiceHostAndPort>> Lease(DownstreamContext downstreamContext)
 | 
			
		||||
            public async Task<Response<ServiceHostAndPort>> Lease(HttpContext httpContext)
 | 
			
		||||
            {
 | 
			
		||||
                var services = await _services();
 | 
			
		||||
                lock (_lock)
 | 
			
		||||
@@ -205,7 +205,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public void Release(ServiceHostAndPort hostAndPort)
 | 
			
		||||
        public void Release(ServiceHostAndPort hostAndPort)
 | 
			
		||||
            {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
    using Ocelot.Infrastructure;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Ocelot.Middleware.Multiplexer;
 | 
			
		||||
    using Ocelot.Multiplexer;
 | 
			
		||||
    using Ocelot.Provider.Consul;
 | 
			
		||||
    using Ocelot.Provider.Eureka;
 | 
			
		||||
    using Ocelot.Provider.Polly;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,31 +1,30 @@
 | 
			
		||||
using BenchmarkDotNet.Attributes;
 | 
			
		||||
using BenchmarkDotNet.Columns;
 | 
			
		||||
using BenchmarkDotNet.Configs;
 | 
			
		||||
using BenchmarkDotNet.Diagnosers;
 | 
			
		||||
using BenchmarkDotNet.Validators;
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Microsoft.Extensions.Configuration;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.DependencyInjection;
 | 
			
		||||
using Ocelot.DownstreamRouteFinder.Finder;
 | 
			
		||||
using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Ocelot.Middleware.Multiplexer;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Benchmarks
 | 
			
		||||
{
 | 
			
		||||
    using BenchmarkDotNet.Attributes;
 | 
			
		||||
    using BenchmarkDotNet.Columns;
 | 
			
		||||
    using BenchmarkDotNet.Configs;
 | 
			
		||||
    using BenchmarkDotNet.Diagnosers;
 | 
			
		||||
    using BenchmarkDotNet.Validators;
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Microsoft.Extensions.Configuration;
 | 
			
		||||
    using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.DependencyInjection;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.Finder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
    [SimpleJob(launchCount: 1, warmupCount: 2, targetCount: 5)]
 | 
			
		||||
    [Config(typeof(DownstreamRouteFinderMiddlewareBenchmarks))]
 | 
			
		||||
    public class DownstreamRouteFinderMiddlewareBenchmarks : ManualConfig
 | 
			
		||||
    {
 | 
			
		||||
        private DownstreamRouteFinderMiddleware _middleware;
 | 
			
		||||
        private DownstreamContext _downstreamContext;
 | 
			
		||||
        private OcelotRequestDelegate _next;
 | 
			
		||||
        private RequestDelegate _next;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
 | 
			
		||||
        public DownstreamRouteFinderMiddlewareBenchmarks()
 | 
			
		||||
        {
 | 
			
		||||
@@ -43,7 +42,6 @@ namespace Ocelot.Benchmarks
 | 
			
		||||
            var services = serviceCollection.BuildServiceProvider();
 | 
			
		||||
            var loggerFactory = services.GetService<IOcelotLoggerFactory>();
 | 
			
		||||
            var drpf = services.GetService<IDownstreamRouteProviderFactory>();
 | 
			
		||||
            var multiplexer = services.GetService<IMultiplexer>();
 | 
			
		||||
 | 
			
		||||
            _next = async context =>
 | 
			
		||||
            {
 | 
			
		||||
@@ -51,22 +49,21 @@ namespace Ocelot.Benchmarks
 | 
			
		||||
                throw new Exception("BOOM");
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            _middleware = new DownstreamRouteFinderMiddleware(_next, loggerFactory, drpf, multiplexer);
 | 
			
		||||
            _middleware = new DownstreamRouteFinderMiddleware(_next, loggerFactory, drpf);
 | 
			
		||||
 | 
			
		||||
            var httpContext = new DefaultHttpContext();
 | 
			
		||||
            httpContext.Request.Path = new PathString("/test");
 | 
			
		||||
            httpContext.Request.QueryString = new QueryString("?a=b");
 | 
			
		||||
            httpContext.Request.Headers.Add("Host", "most");
 | 
			
		||||
            httpContext.Items.SetIInternalConfiguration(new InternalConfiguration(new List<ReRoute>(), null, null, null, null, null, null, null, null));
 | 
			
		||||
 | 
			
		||||
            _downstreamContext = new DownstreamContext(httpContext)
 | 
			
		||||
            {
 | 
			
		||||
                Configuration = new InternalConfiguration(new List<ReRoute>(), null, null, null, null, null, null, null, null)
 | 
			
		||||
            };
 | 
			
		||||
            _httpContext = httpContext;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Benchmark(Baseline = true)]
 | 
			
		||||
        public async Task Baseline()
 | 
			
		||||
        {
 | 
			
		||||
            await _middleware.Invoke(_downstreamContext);
 | 
			
		||||
            await _middleware.Invoke(_httpContext);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,61 +1,60 @@
 | 
			
		||||
using BenchmarkDotNet.Attributes;
 | 
			
		||||
using BenchmarkDotNet.Columns;
 | 
			
		||||
using BenchmarkDotNet.Configs;
 | 
			
		||||
using BenchmarkDotNet.Diagnosers;
 | 
			
		||||
using BenchmarkDotNet.Validators;
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Microsoft.Extensions.Configuration;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using Ocelot.Configuration.Repository;
 | 
			
		||||
using Ocelot.DependencyInjection;
 | 
			
		||||
using Ocelot.Errors.Middleware;
 | 
			
		||||
using Ocelot.Infrastructure.RequestData;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Benchmarks
 | 
			
		||||
{
 | 
			
		||||
    [SimpleJob(launchCount: 1, warmupCount: 2, targetCount: 5)]
 | 
			
		||||
    [Config(typeof(ExceptionHandlerMiddlewareBenchmarks))]
 | 
			
		||||
    public class ExceptionHandlerMiddlewareBenchmarks : ManualConfig
 | 
			
		||||
    {
 | 
			
		||||
        private ExceptionHandlerMiddleware _middleware;
 | 
			
		||||
        private DownstreamContext _downstreamContext;
 | 
			
		||||
        private OcelotRequestDelegate _next;
 | 
			
		||||
 | 
			
		||||
        public ExceptionHandlerMiddlewareBenchmarks()
 | 
			
		||||
        {
 | 
			
		||||
            Add(StatisticColumn.AllStatistics);
 | 
			
		||||
            Add(MemoryDiagnoser.Default);
 | 
			
		||||
            Add(BaselineValidator.FailOnError);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [GlobalSetup]
 | 
			
		||||
        public void SetUp()
 | 
			
		||||
        {
 | 
			
		||||
            var serviceCollection = new ServiceCollection();
 | 
			
		||||
            var config = new ConfigurationRoot(new List<IConfigurationProvider>());
 | 
			
		||||
            var builder = new OcelotBuilder(serviceCollection, config);
 | 
			
		||||
            var services = serviceCollection.BuildServiceProvider();
 | 
			
		||||
            var loggerFactory = services.GetService<IOcelotLoggerFactory>();
 | 
			
		||||
            var configRepo = services.GetService<IInternalConfigurationRepository>();
 | 
			
		||||
            var repo = services.GetService<IRequestScopedDataRepository>();
 | 
			
		||||
namespace Ocelot.Benchmarks
 | 
			
		||||
{
 | 
			
		||||
    using BenchmarkDotNet.Attributes;
 | 
			
		||||
    using BenchmarkDotNet.Columns;
 | 
			
		||||
    using BenchmarkDotNet.Configs;
 | 
			
		||||
    using BenchmarkDotNet.Diagnosers;
 | 
			
		||||
    using BenchmarkDotNet.Validators;
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Microsoft.Extensions.Configuration;
 | 
			
		||||
    using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
    using Ocelot.DependencyInjection;
 | 
			
		||||
    using Ocelot.Errors.Middleware;
 | 
			
		||||
    using Ocelot.Infrastructure.RequestData;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
    [SimpleJob(launchCount: 1, warmupCount: 2, targetCount: 5)]
 | 
			
		||||
    [Config(typeof(ExceptionHandlerMiddlewareBenchmarks))]
 | 
			
		||||
    public class ExceptionHandlerMiddlewareBenchmarks : ManualConfig
 | 
			
		||||
    {
 | 
			
		||||
        private ExceptionHandlerMiddleware _middleware;
 | 
			
		||||
        private RequestDelegate _next;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
 | 
			
		||||
        public ExceptionHandlerMiddlewareBenchmarks()
 | 
			
		||||
        {
 | 
			
		||||
            Add(StatisticColumn.AllStatistics);
 | 
			
		||||
            Add(MemoryDiagnoser.Default);
 | 
			
		||||
            Add(BaselineValidator.FailOnError);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [GlobalSetup]
 | 
			
		||||
        public void SetUp()
 | 
			
		||||
        {
 | 
			
		||||
            var serviceCollection = new ServiceCollection();
 | 
			
		||||
            var config = new ConfigurationRoot(new List<IConfigurationProvider>());
 | 
			
		||||
            var builder = new OcelotBuilder(serviceCollection, config);
 | 
			
		||||
            var services = serviceCollection.BuildServiceProvider();
 | 
			
		||||
            var loggerFactory = services.GetService<IOcelotLoggerFactory>();
 | 
			
		||||
            var repo = services.GetService<IRequestScopedDataRepository>();
 | 
			
		||||
 | 
			
		||||
            _next = async context =>
 | 
			
		||||
            {
 | 
			
		||||
                await Task.CompletedTask;
 | 
			
		||||
                throw new Exception("BOOM");
 | 
			
		||||
            };
 | 
			
		||||
            _middleware = new ExceptionHandlerMiddleware(_next, loggerFactory, configRepo, repo);
 | 
			
		||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Benchmark(Baseline = true)]
 | 
			
		||||
        public async Task Baseline()
 | 
			
		||||
        {
 | 
			
		||||
            await _middleware.Invoke(_downstreamContext);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
            {
 | 
			
		||||
                await Task.CompletedTask;
 | 
			
		||||
                throw new Exception("BOOM");
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            _middleware = new ExceptionHandlerMiddleware(_next, loggerFactory, repo);
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Benchmark(Baseline = true)]
 | 
			
		||||
        public async Task Baseline()
 | 
			
		||||
        {
 | 
			
		||||
            await _middleware.Invoke(_httpContext);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,115 +1,119 @@
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
[assembly: CollectionBehavior(DisableTestParallelization = true)]
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Authentication
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Authentication.Middleware;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.IO;
 | 
			
		||||
    using System.Text;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
[assembly: CollectionBehavior(DisableTestParallelization = true)]
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Authentication
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Authentication.Middleware;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.IO;
 | 
			
		||||
    using System.Text;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using Ocelot.Infrastructure.RequestData;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
 | 
			
		||||
    public class AuthenticationMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private AuthenticationMiddleware _middleware;
 | 
			
		||||
        private readonly Mock<IOcelotLoggerFactory> _factory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private OcelotRequestDelegate _next;
 | 
			
		||||
        private readonly DownstreamContext _downstreamContext;
 | 
			
		||||
 | 
			
		||||
        public AuthenticationMiddlewareTests()
 | 
			
		||||
    public class AuthenticationMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private AuthenticationMiddleware _middleware;
 | 
			
		||||
        private readonly Mock<IOcelotLoggerFactory> _factory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private RequestDelegate _next;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
        private Mock<IRequestScopedDataRepository> _repo;
 | 
			
		||||
 | 
			
		||||
        public AuthenticationMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _repo = new Mock<IRequestScopedDataRepository>();
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
            _factory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _factory.Setup(x => x.CreateLogger<AuthenticationMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_next_middleware_if_route_is_not_authenticated()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => GivenTheDownStreamRouteIs(
 | 
			
		||||
                    new DownstreamReRouteBuilder().WithUpstreamHttpMethod(new List<string> { "Get" }).Build()))
 | 
			
		||||
                .And(x => GivenTheTestServerPipelineIsConfigured())
 | 
			
		||||
                .When(x => WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => ThenTheUserIsAuthenticated())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_next_middleware_if_route_is_using_options_method()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => GivenTheDownStreamRouteIs(
 | 
			
		||||
                    new DownstreamReRouteBuilder()
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Options" })
 | 
			
		||||
                        .WithIsAuthenticated(true)
 | 
			
		||||
                        .Build()))
 | 
			
		||||
                .And(x => GivenTheRequestIsUsingOptionsMethod())
 | 
			
		||||
                .When(x => WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => ThenTheUserIsAuthenticated())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _next = (context) =>
 | 
			
		||||
            {
 | 
			
		||||
                byte[] byteArray = Encoding.ASCII.GetBytes("The user is authenticated");
 | 
			
		||||
                var stream = new MemoryStream(byteArray);
 | 
			
		||||
                _httpContext.Response.Body = stream;
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            };
 | 
			
		||||
            _middleware = new AuthenticationMiddleware(_next, _factory.Object);
 | 
			
		||||
            _middleware.Invoke(_httpContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheTestServerPipelineIsConfigured()
 | 
			
		||||
        {
 | 
			
		||||
            _next = (context) =>
 | 
			
		||||
            {
 | 
			
		||||
                byte[] byteArray = Encoding.ASCII.GetBytes("The user is authenticated");
 | 
			
		||||
                var stream = new MemoryStream(byteArray);
 | 
			
		||||
                _httpContext.Response.Body = stream;
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheRequestIsUsingOptionsMethod()
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext.Request.Method = "OPTIONS";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheUserIsAuthenticated()
 | 
			
		||||
        {
 | 
			
		||||
            var content = _httpContext.Response.Body.AsString();
 | 
			
		||||
            content.ShouldBe("The user is authenticated");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownStreamRouteIs(DownstreamReRoute downstreamRoute)
 | 
			
		||||
        {
 | 
			
		||||
            _factory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _factory.Setup(x => x.CreateLogger<AuthenticationMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_next_middleware_if_route_is_not_authenticated()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => GivenTheDownStreamRouteIs(
 | 
			
		||||
                    new DownstreamReRouteBuilder().WithUpstreamHttpMethod(new List<string> { "Get" }).Build()))
 | 
			
		||||
                .And(x => GivenTheTestServerPipelineIsConfigured())
 | 
			
		||||
                .When(x => WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => ThenTheUserIsAuthenticated())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_next_middleware_if_route_is_using_options_method()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => GivenTheDownStreamRouteIs(
 | 
			
		||||
                    new DownstreamReRouteBuilder()
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Options" })
 | 
			
		||||
                        .WithIsAuthenticated(true)
 | 
			
		||||
                        .Build()))
 | 
			
		||||
                .And(x => GivenTheRequestIsUsingOptionsMethod())
 | 
			
		||||
                .When(x => WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => ThenTheUserIsAuthenticated())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _next = (context) =>
 | 
			
		||||
            {
 | 
			
		||||
                byte[] byteArray = Encoding.ASCII.GetBytes("The user is authenticated");
 | 
			
		||||
                var stream = new MemoryStream(byteArray);
 | 
			
		||||
                context.HttpContext.Response.Body = stream;
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            };
 | 
			
		||||
            _middleware = new AuthenticationMiddleware(_next, _factory.Object);
 | 
			
		||||
            _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheTestServerPipelineIsConfigured()
 | 
			
		||||
        {
 | 
			
		||||
            _next = (context) =>
 | 
			
		||||
            {
 | 
			
		||||
                byte[] byteArray = Encoding.ASCII.GetBytes("The user is authenticated");
 | 
			
		||||
                var stream = new MemoryStream(byteArray);
 | 
			
		||||
                context.HttpContext.Response.Body = stream;
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheRequestIsUsingOptionsMethod()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.HttpContext.Request.Method = "OPTIONS";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheUserIsAuthenticated()
 | 
			
		||||
        {
 | 
			
		||||
            var content = _downstreamContext.HttpContext.Response.Body.AsString();
 | 
			
		||||
            content.ShouldBe("The user is authenticated");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownStreamRouteIs(DownstreamReRoute downstreamRoute)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.DownstreamReRoute = downstreamRoute;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class StreamExtensions
 | 
			
		||||
    {
 | 
			
		||||
        public static string AsString(this Stream stream)
 | 
			
		||||
        {
 | 
			
		||||
            using (var reader = new StreamReader(stream))
 | 
			
		||||
            {
 | 
			
		||||
                string text = reader.ReadToEnd();
 | 
			
		||||
                return text;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamReRoute(downstreamRoute);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class StreamExtensions
 | 
			
		||||
    {
 | 
			
		||||
        public static string AsString(this Stream stream)
 | 
			
		||||
        {
 | 
			
		||||
            using (var reader = new StreamReader(stream))
 | 
			
		||||
            {
 | 
			
		||||
                string text = reader.ReadToEnd();
 | 
			
		||||
                return text;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,88 +1,89 @@
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Authorization
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Authorisation;
 | 
			
		||||
    using Ocelot.Authorisation.Middleware;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Responses;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Security.Claims;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class AuthorisationMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Mock<IClaimsAuthoriser> _authService;
 | 
			
		||||
        private readonly Mock<IScopesAuthoriser> _authScopesService;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private readonly AuthorisationMiddleware _middleware;
 | 
			
		||||
        private readonly DownstreamContext _downstreamContext;
 | 
			
		||||
        private OcelotRequestDelegate _next;
 | 
			
		||||
 | 
			
		||||
        public AuthorisationMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _authService = new Mock<IClaimsAuthoriser>();
 | 
			
		||||
            _authScopesService = new Mock<IScopesAuthoriser>();
 | 
			
		||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<AuthorisationMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _next = context => Task.CompletedTask;
 | 
			
		||||
            _middleware = new AuthorisationMiddleware(_next, _authService.Object, _authScopesService.Object, _loggerFactory.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_authorisation_service()
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Authorization
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Authorisation;
 | 
			
		||||
    using Ocelot.Authorisation.Middleware;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Ocelot.Responses;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Security.Claims;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class AuthorisationMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Mock<IClaimsAuthoriser> _authService;
 | 
			
		||||
        private readonly Mock<IScopesAuthoriser> _authScopesService;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private readonly AuthorisationMiddleware _middleware;
 | 
			
		||||
        private RequestDelegate _next;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
 | 
			
		||||
        public AuthorisationMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
            _authService = new Mock<IClaimsAuthoriser>();
 | 
			
		||||
            _authScopesService = new Mock<IScopesAuthoriser>();
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<AuthorisationMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _next = context => Task.CompletedTask;
 | 
			
		||||
            _middleware = new AuthorisationMiddleware(_next, _authService.Object, _authScopesService.Object, _loggerFactory.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_authorisation_service()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new DownstreamReRouteBuilder()
 | 
			
		||||
                    .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().Build())
 | 
			
		||||
                    .WithIsAuthorised(true)
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                    .Build()))
 | 
			
		||||
                .And(x => x.GivenTheAuthServiceReturns(new OkResponse<bool>(true)))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheAuthServiceIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownStreamRouteIs(List<PlaceholderNameAndValue> templatePlaceholderNameAndValues, DownstreamReRoute downstreamReRoute)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.TemplatePlaceholderNameAndValues = templatePlaceholderNameAndValues;
 | 
			
		||||
            _downstreamContext.DownstreamReRoute = downstreamReRoute;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheAuthServiceReturns(Response<bool> expected)
 | 
			
		||||
        {
 | 
			
		||||
            _authService
 | 
			
		||||
                new DownstreamReRouteBuilder()
 | 
			
		||||
                    .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().Build())
 | 
			
		||||
                    .WithIsAuthorised(true)
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                    .Build()))
 | 
			
		||||
                .And(x => x.GivenTheAuthServiceReturns(new OkResponse<bool>(true)))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheAuthServiceIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_httpContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownStreamRouteIs(List<PlaceholderNameAndValue> templatePlaceholderNameAndValues, DownstreamReRoute downstreamReRoute)
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext.Items.UpsertTemplatePlaceholderNameAndValues(templatePlaceholderNameAndValues);
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamReRoute(downstreamReRoute);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheAuthServiceReturns(Response<bool> expected)
 | 
			
		||||
        {
 | 
			
		||||
            _authService
 | 
			
		||||
                .Setup(x => x.Authorise(
 | 
			
		||||
                           It.IsAny<ClaimsPrincipal>(),
 | 
			
		||||
                           It.IsAny<Dictionary<string, string>>(),
 | 
			
		||||
                           It.IsAny<List<PlaceholderNameAndValue>>()))
 | 
			
		||||
                .Returns(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheAuthServiceIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _authService
 | 
			
		||||
                .Verify(x => x.Authorise(
 | 
			
		||||
                    It.IsAny<ClaimsPrincipal>(),
 | 
			
		||||
                    It.IsAny<Dictionary<string, string>>(),
 | 
			
		||||
                           It.IsAny<List<PlaceholderNameAndValue>>()))
 | 
			
		||||
                .Returns(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheAuthServiceIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _authService
 | 
			
		||||
                .Verify(x => x.Authorise(
 | 
			
		||||
                    It.IsAny<ClaimsPrincipal>(),
 | 
			
		||||
                    It.IsAny<Dictionary<string, string>>(),
 | 
			
		||||
                    It.IsAny<List<PlaceholderNameAndValue>>())
 | 
			
		||||
                        , Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
                        , Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,38 +1,34 @@
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Ocelot.Cache;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Cache
 | 
			
		||||
namespace Ocelot.UnitTests.Cache
 | 
			
		||||
{
 | 
			
		||||
    using Ocelot.Cache;
 | 
			
		||||
    using Ocelot.Request.Middleware;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class CacheKeyGeneratorTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly ICacheKeyGenerator _cacheKeyGenerator;
 | 
			
		||||
        private readonly DownstreamContext _downstreamContext;
 | 
			
		||||
        private readonly DownstreamRequest _downstreamRequest;
 | 
			
		||||
 | 
			
		||||
        public CacheKeyGeneratorTests()
 | 
			
		||||
        {
 | 
			
		||||
            _cacheKeyGenerator = new CacheKeyGenerator();
 | 
			
		||||
            _cacheKeyGenerator = new CacheKeyGenerator();
 | 
			
		||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext())
 | 
			
		||||
            {
 | 
			
		||||
                DownstreamRequest = new Ocelot.Request.Middleware.DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "https://some.url/blah?abcd=123"))
 | 
			
		||||
            };
 | 
			
		||||
            _downstreamRequest = new DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "https://some.url/blah?abcd=123"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_generate_cache_key_from_context()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenCacheKeyFromContext(_downstreamContext))
 | 
			
		||||
            this.Given(x => x.GivenCacheKeyFromContext(_downstreamRequest))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenCacheKeyFromContext(DownstreamContext context)
 | 
			
		||||
        private void GivenCacheKeyFromContext(DownstreamRequest downstreamRequest)
 | 
			
		||||
        {
 | 
			
		||||
            string generatedCacheKey = _cacheKeyGenerator.GenerateRequestCacheKey(context);
 | 
			
		||||
            string generatedCacheKey = _cacheKeyGenerator.GenerateRequestCacheKey(downstreamRequest);
 | 
			
		||||
            string cachekey = MD5Helper.GenerateMd5("GET-https://some.url/blah?abcd=123");
 | 
			
		||||
            generatedCacheKey.ShouldBe(cachekey);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,140 +1,144 @@
 | 
			
		||||
namespace Ocelot.UnitTests.Cache
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Cache;
 | 
			
		||||
    using Ocelot.Cache.Middleware;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Net;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
namespace Ocelot.UnitTests.Cache
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Cache;
 | 
			
		||||
    using Ocelot.Cache.Middleware;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Net;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using Ocelot.Infrastructure.RequestData;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
 | 
			
		||||
    public class OutputCacheMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Mock<IOcelotCache<CachedResponse>> _cache;
 | 
			
		||||
        private readonly Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private OutputCacheMiddleware _middleware;
 | 
			
		||||
        private readonly DownstreamContext _downstreamContext;
 | 
			
		||||
        private readonly OcelotRequestDelegate _next;
 | 
			
		||||
        private readonly ICacheKeyGenerator _cacheKeyGenerator;
 | 
			
		||||
        private CachedResponse _response;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public OutputCacheMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _cache = new Mock<IOcelotCache<CachedResponse>>();
 | 
			
		||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _cacheKeyGenerator = new CacheKeyGenerator();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<OutputCacheMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
    public class OutputCacheMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Mock<IOcelotCache<CachedResponse>> _cache;
 | 
			
		||||
        private readonly Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private OutputCacheMiddleware _middleware;
 | 
			
		||||
        private readonly RequestDelegate _next;
 | 
			
		||||
        private readonly ICacheKeyGenerator _cacheKeyGenerator;
 | 
			
		||||
        private CachedResponse _response;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
        private Mock<IRequestScopedDataRepository> _repo;
 | 
			
		||||
 | 
			
		||||
        public OutputCacheMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _repo = new Mock<IRequestScopedDataRepository>();
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
            _cache = new Mock<IOcelotCache<CachedResponse>>();
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _cacheKeyGenerator = new CacheKeyGenerator();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<OutputCacheMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _next = context => Task.CompletedTask;
 | 
			
		||||
            _downstreamContext.DownstreamRequest = new Ocelot.Request.Middleware.DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "https://some.url/blah?abcd=123"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_returned_cached_item_when_it_is_in_cache()
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamRequest(new Ocelot.Request.Middleware.DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "https://some.url/blah?abcd=123")));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_returned_cached_item_when_it_is_in_cache()
 | 
			
		||||
        {
 | 
			
		||||
            var headers = new Dictionary<string, IEnumerable<string>>
 | 
			
		||||
            {
 | 
			
		||||
                { "test", new List<string> { "test" } }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var contentHeaders = new Dictionary<string, IEnumerable<string>>
 | 
			
		||||
            {
 | 
			
		||||
                { "content-type", new List<string> { "application/json" } }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var cachedResponse = new CachedResponse(HttpStatusCode.OK, headers, "", contentHeaders, "some reason");
 | 
			
		||||
            this.Given(x => x.GivenThereIsACachedResponse(cachedResponse))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRouteIs())
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheCacheGetIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_returned_cached_item_when_it_is_in_cache_expires_header()
 | 
			
		||||
        {
 | 
			
		||||
            var contentHeaders = new Dictionary<string, IEnumerable<string>>
 | 
			
		||||
            {
 | 
			
		||||
                { "Expires", new List<string> { "-1" } }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var cachedResponse = new CachedResponse(HttpStatusCode.OK, new Dictionary<string, IEnumerable<string>>(), "", contentHeaders, "some reason");
 | 
			
		||||
            this.Given(x => x.GivenThereIsACachedResponse(cachedResponse))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRouteIs())
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheCacheGetIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_continue_with_pipeline_and_cache_response()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenResponseIsNotCached(new HttpResponseMessage()))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRouteIs())
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheCacheAddIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware = new OutputCacheMiddleware(_next, _loggerFactory.Object, _cache.Object, _cacheKeyGenerator);
 | 
			
		||||
            _middleware.Invoke(_httpContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsACachedResponse(CachedResponse response)
 | 
			
		||||
        {
 | 
			
		||||
            _response = response;
 | 
			
		||||
            _cache
 | 
			
		||||
              .Setup(x => x.Get(It.IsAny<string>(), It.IsAny<string>()))
 | 
			
		||||
              .Returns(_response);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenResponseIsNotCached(HttpResponseMessage responseMessage)
 | 
			
		||||
        {
 | 
			
		||||
            var headers = new Dictionary<string, IEnumerable<string>>
 | 
			
		||||
            {
 | 
			
		||||
                { "test", new List<string> { "test" } }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var contentHeaders = new Dictionary<string, IEnumerable<string>>
 | 
			
		||||
            {
 | 
			
		||||
                { "content-type", new List<string> { "application/json" } }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var cachedResponse = new CachedResponse(HttpStatusCode.OK, headers, "", contentHeaders, "some reason");
 | 
			
		||||
            this.Given(x => x.GivenThereIsACachedResponse(cachedResponse))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRouteIs())
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheCacheGetIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_returned_cached_item_when_it_is_in_cache_expires_header()
 | 
			
		||||
        {
 | 
			
		||||
            var contentHeaders = new Dictionary<string, IEnumerable<string>>
 | 
			
		||||
            {
 | 
			
		||||
                { "Expires", new List<string> { "-1" } }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var cachedResponse = new CachedResponse(HttpStatusCode.OK, new Dictionary<string, IEnumerable<string>>(), "", contentHeaders, "some reason");
 | 
			
		||||
            this.Given(x => x.GivenThereIsACachedResponse(cachedResponse))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRouteIs())
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheCacheGetIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_continue_with_pipeline_and_cache_response()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenResponseIsNotCached(new HttpResponseMessage()))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRouteIs())
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheCacheAddIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware = new OutputCacheMiddleware(_next, _loggerFactory.Object, _cache.Object, _cacheKeyGenerator);
 | 
			
		||||
            _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsACachedResponse(CachedResponse response)
 | 
			
		||||
        {
 | 
			
		||||
            _response = response;
 | 
			
		||||
            _cache
 | 
			
		||||
              .Setup(x => x.Get(It.IsAny<string>(), It.IsAny<string>()))
 | 
			
		||||
              .Returns(_response);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenResponseIsNotCached(HttpResponseMessage responseMessage)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.DownstreamResponse = new DownstreamResponse(responseMessage);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownstreamRouteIs()
 | 
			
		||||
        {
 | 
			
		||||
            var reRoute = new ReRouteBuilder()
 | 
			
		||||
                .WithDownstreamReRoute(new DownstreamReRouteBuilder()
 | 
			
		||||
                    .WithIsCached(true)
 | 
			
		||||
                    .WithCacheOptions(new CacheOptions(100, "kanken"))
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                    .Build())
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamResponse(new DownstreamResponse(responseMessage));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownstreamRouteIs()
 | 
			
		||||
        {
 | 
			
		||||
            var reRoute = new ReRouteBuilder()
 | 
			
		||||
                .WithDownstreamReRoute(new DownstreamReRouteBuilder()
 | 
			
		||||
                    .WithIsCached(true)
 | 
			
		||||
                    .WithCacheOptions(new CacheOptions(100, "kanken"))
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                    .Build())
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<PlaceholderNameAndValue>(), reRoute);
 | 
			
		||||
 | 
			
		||||
            _downstreamContext.TemplatePlaceholderNameAndValues = downstreamRoute.TemplatePlaceholderNameAndValues;
 | 
			
		||||
            _downstreamContext.DownstreamReRoute = downstreamRoute.ReRoute.DownstreamReRoute[0];
 | 
			
		||||
        }
 | 
			
		||||
            _httpContext.Items.UpsertTemplatePlaceholderNameAndValues(downstreamRoute.TemplatePlaceholderNameAndValues);
 | 
			
		||||
 | 
			
		||||
        private void ThenTheCacheGetIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _cache
 | 
			
		||||
                .Verify(x => x.Get(It.IsAny<string>(), It.IsAny<string>()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheCacheAddIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _cache
 | 
			
		||||
                .Verify(x => x.Add(It.IsAny<string>(), It.IsAny<CachedResponse>(), It.IsAny<TimeSpan>(), It.IsAny<string>()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamReRoute(downstreamRoute.ReRoute.DownstreamReRoute[0]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheCacheGetIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _cache
 | 
			
		||||
                .Verify(x => x.Get(It.IsAny<string>(), It.IsAny<string>()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheCacheAddIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _cache
 | 
			
		||||
                .Verify(x => x.Add(It.IsAny<string>(), It.IsAny<CachedResponse>(), It.IsAny<TimeSpan>(), It.IsAny<string>()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,96 +1,97 @@
 | 
			
		||||
namespace Ocelot.UnitTests.CacheManager
 | 
			
		||||
{
 | 
			
		||||
    using global::CacheManager.Core;
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Cache;
 | 
			
		||||
    using Ocelot.Cache.CacheManager;
 | 
			
		||||
    using Ocelot.Cache.Middleware;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
namespace Ocelot.UnitTests.CacheManager
 | 
			
		||||
{
 | 
			
		||||
    using global::CacheManager.Core;
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Cache;
 | 
			
		||||
    using Ocelot.Cache.CacheManager;
 | 
			
		||||
    using Ocelot.Cache.Middleware;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Linq;
 | 
			
		||||
    using System.Net;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Net.Http.Headers;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class OutputCacheMiddlewareRealCacheTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IOcelotCache<CachedResponse> _cacheManager;
 | 
			
		||||
        private readonly ICacheKeyGenerator _cacheKeyGenerator;
 | 
			
		||||
        private readonly OutputCacheMiddleware _middleware;
 | 
			
		||||
        private readonly DownstreamContext _downstreamContext;
 | 
			
		||||
        private OcelotRequestDelegate _next;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
 | 
			
		||||
        public OutputCacheMiddlewareRealCacheTests()
 | 
			
		||||
        {
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();            
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<OutputCacheMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            var cacheManagerOutputCache = CacheFactory.Build<CachedResponse>("OcelotOutputCache", x =>
 | 
			
		||||
            {
 | 
			
		||||
                x.WithDictionaryHandle();
 | 
			
		||||
            });
 | 
			
		||||
            _cacheManager = new OcelotCacheManagerCache<CachedResponse>(cacheManagerOutputCache);
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Linq;
 | 
			
		||||
    using System.Net;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Net.Http.Headers;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class OutputCacheMiddlewareRealCacheTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IOcelotCache<CachedResponse> _cacheManager;
 | 
			
		||||
        private readonly ICacheKeyGenerator _cacheKeyGenerator;
 | 
			
		||||
        private readonly OutputCacheMiddleware _middleware;
 | 
			
		||||
        private RequestDelegate _next;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
 | 
			
		||||
        public OutputCacheMiddlewareRealCacheTests()
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();            
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<OutputCacheMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            var cacheManagerOutputCache = CacheFactory.Build<CachedResponse>("OcelotOutputCache", x =>
 | 
			
		||||
            {
 | 
			
		||||
                x.WithDictionaryHandle();
 | 
			
		||||
            });
 | 
			
		||||
            _cacheManager = new OcelotCacheManagerCache<CachedResponse>(cacheManagerOutputCache);
 | 
			
		||||
            _cacheKeyGenerator = new CacheKeyGenerator();
 | 
			
		||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
            _downstreamContext.DownstreamRequest = new Ocelot.Request.Middleware.DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "https://some.url/blah?abcd=123"));
 | 
			
		||||
            _next = context => Task.CompletedTask;
 | 
			
		||||
            _middleware = new OutputCacheMiddleware(_next, _loggerFactory.Object, _cacheManager, _cacheKeyGenerator);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_cache_content_headers()
 | 
			
		||||
        {
 | 
			
		||||
            var content = new StringContent("{\"Test\": 1}")
 | 
			
		||||
            {
 | 
			
		||||
                Headers = { ContentType = new MediaTypeHeaderValue("application/json") }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var response = new DownstreamResponse(content, HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "fooreason");
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenResponseIsNotCached(response))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRouteIs())
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheContentTypeHeaderIsCached())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheContentTypeHeaderIsCached()
 | 
			
		||||
        {
 | 
			
		||||
            string cacheKey = MD5Helper.GenerateMd5("GET-https://some.url/blah?abcd=123");
 | 
			
		||||
            var result = _cacheManager.Get(cacheKey, "kanken");
 | 
			
		||||
            var header = result.ContentHeaders["Content-Type"];
 | 
			
		||||
            header.First().ShouldBe("application/json");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenResponseIsNotCached(DownstreamResponse response)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.DownstreamResponse = response;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownstreamRouteIs()
 | 
			
		||||
        {
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithIsCached(true)
 | 
			
		||||
                .WithCacheOptions(new CacheOptions(100, "kanken"))
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamRequest(new Ocelot.Request.Middleware.DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "https://some.url/blah?abcd=123")));
 | 
			
		||||
            _next = context => Task.CompletedTask;
 | 
			
		||||
            _middleware = new OutputCacheMiddleware(_next, _loggerFactory.Object, _cacheManager, _cacheKeyGenerator);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_cache_content_headers()
 | 
			
		||||
        {
 | 
			
		||||
            var content = new StringContent("{\"Test\": 1}")
 | 
			
		||||
            {
 | 
			
		||||
                Headers = { ContentType = new MediaTypeHeaderValue("application/json") }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var response = new DownstreamResponse(content, HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "fooreason");
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenResponseIsNotCached(response))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRouteIs())
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheContentTypeHeaderIsCached())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_httpContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheContentTypeHeaderIsCached()
 | 
			
		||||
        {
 | 
			
		||||
            string cacheKey = MD5Helper.GenerateMd5("GET-https://some.url/blah?abcd=123");
 | 
			
		||||
            var result = _cacheManager.Get(cacheKey, "kanken");
 | 
			
		||||
            var header = result.ContentHeaders["Content-Type"];
 | 
			
		||||
            header.First().ShouldBe("application/json");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenResponseIsNotCached(DownstreamResponse response)
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamResponse(response);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownstreamRouteIs()
 | 
			
		||||
        {
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithIsCached(true)
 | 
			
		||||
                .WithCacheOptions(new CacheOptions(100, "kanken"))
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            _downstreamContext.DownstreamReRoute = reRoute;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamReRoute(reRoute);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,142 +1,142 @@
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Claims;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Errors;
 | 
			
		||||
using Ocelot.Infrastructure.Claims.Parser;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Security.Claims;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Claims
 | 
			
		||||
{
 | 
			
		||||
    public class AddClaimsToRequestTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly AddClaimsToRequest _addClaimsToRequest;
 | 
			
		||||
        private readonly Mock<IClaimsParser> _parser;
 | 
			
		||||
        private List<ClaimToThing> _claimsToThings;
 | 
			
		||||
        private HttpContext _context;
 | 
			
		||||
        private Response _result;
 | 
			
		||||
        private Response<string> _claimValue;
 | 
			
		||||
 | 
			
		||||
        public AddClaimsToRequestTests()
 | 
			
		||||
        {
 | 
			
		||||
            _parser = new Mock<IClaimsParser>();
 | 
			
		||||
            _addClaimsToRequest = new AddClaimsToRequest(_parser.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_claims_to_context()
 | 
			
		||||
        {
 | 
			
		||||
            var context = new DefaultHttpContext
 | 
			
		||||
            {
 | 
			
		||||
                User = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
 | 
			
		||||
                {
 | 
			
		||||
                    new Claim("test", "data")
 | 
			
		||||
                }))
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(
 | 
			
		||||
                x => x.GivenClaimsToThings(new List<ClaimToThing>
 | 
			
		||||
                {
 | 
			
		||||
                    new ClaimToThing("claim-key", "", "", 0)
 | 
			
		||||
                }))
 | 
			
		||||
                .Given(x => x.GivenHttpContext(context))
 | 
			
		||||
                .And(x => x.GivenTheClaimParserReturns(new OkResponse<string>("value")))
 | 
			
		||||
                .When(x => x.WhenIAddClaimsToTheRequest())
 | 
			
		||||
                .Then(x => x.ThenTheResultIsSuccess())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void if_claims_exists_should_replace_it()
 | 
			
		||||
        {
 | 
			
		||||
            var context = new DefaultHttpContext
 | 
			
		||||
            {
 | 
			
		||||
                User = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
 | 
			
		||||
                {
 | 
			
		||||
                    new Claim("existing-key", "data"),
 | 
			
		||||
                    new Claim("new-key", "data")
 | 
			
		||||
                })),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(
 | 
			
		||||
                x => x.GivenClaimsToThings(new List<ClaimToThing>
 | 
			
		||||
                {
 | 
			
		||||
                    new ClaimToThing("existing-key", "new-key", "", 0)
 | 
			
		||||
                }))
 | 
			
		||||
                .Given(x => x.GivenHttpContext(context))
 | 
			
		||||
                .And(x => x.GivenTheClaimParserReturns(new OkResponse<string>("value")))
 | 
			
		||||
                .When(x => x.WhenIAddClaimsToTheRequest())
 | 
			
		||||
                .Then(x => x.ThenTheResultIsSuccess())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_error()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(
 | 
			
		||||
               x => x.GivenClaimsToThings(new List<ClaimToThing>
 | 
			
		||||
               {
 | 
			
		||||
                    new ClaimToThing("", "", "", 0)
 | 
			
		||||
               }))
 | 
			
		||||
               .Given(x => x.GivenHttpContext(new DefaultHttpContext()))
 | 
			
		||||
               .And(x => x.GivenTheClaimParserReturns(new ErrorResponse<string>(new List<Error>
 | 
			
		||||
               {
 | 
			
		||||
                   new AnyError()
 | 
			
		||||
               })))
 | 
			
		||||
               .When(x => x.WhenIAddClaimsToTheRequest())
 | 
			
		||||
               .Then(x => x.ThenTheResultIsError())
 | 
			
		||||
               .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenClaimsToThings(List<ClaimToThing> configuration)
 | 
			
		||||
        {
 | 
			
		||||
            _claimsToThings = configuration;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenHttpContext(HttpContext context)
 | 
			
		||||
        {
 | 
			
		||||
            _context = context;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheClaimParserReturns(Response<string> claimValue)
 | 
			
		||||
        {
 | 
			
		||||
            _claimValue = claimValue;
 | 
			
		||||
            _parser
 | 
			
		||||
                .Setup(
 | 
			
		||||
                    x =>
 | 
			
		||||
                        x.GetValue(It.IsAny<IEnumerable<Claim>>(),
 | 
			
		||||
                        It.IsAny<string>(),
 | 
			
		||||
                        It.IsAny<string>(),
 | 
			
		||||
                        It.IsAny<int>()))
 | 
			
		||||
                .Returns(_claimValue);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIAddClaimsToTheRequest()
 | 
			
		||||
        {
 | 
			
		||||
            _result = _addClaimsToRequest.SetClaimsOnContext(_claimsToThings, _context);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheResultIsSuccess()
 | 
			
		||||
        {
 | 
			
		||||
            _result.IsError.ShouldBe(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheResultIsError()
 | 
			
		||||
        {
 | 
			
		||||
            _result.IsError.ShouldBe(true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private class AnyError : Error
 | 
			
		||||
        {
 | 
			
		||||
            public AnyError()
 | 
			
		||||
                : base("blahh", OcelotErrorCode.UnknownError)
 | 
			
		||||
            {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Claims;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Errors;
 | 
			
		||||
using Ocelot.Infrastructure.Claims.Parser;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Security.Claims;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Claims
 | 
			
		||||
{
 | 
			
		||||
    public class AddClaimsToRequestTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly AddClaimsToRequest _addClaimsToRequest;
 | 
			
		||||
        private readonly Mock<IClaimsParser> _parser;
 | 
			
		||||
        private List<ClaimToThing> _claimsToThings;
 | 
			
		||||
        private HttpContext _context;
 | 
			
		||||
        private Response _result;
 | 
			
		||||
        private Response<string> _claimValue;
 | 
			
		||||
 | 
			
		||||
        public AddClaimsToRequestTests()
 | 
			
		||||
        {
 | 
			
		||||
            _parser = new Mock<IClaimsParser>();
 | 
			
		||||
            _addClaimsToRequest = new AddClaimsToRequest(_parser.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_claims_to_context()
 | 
			
		||||
        {
 | 
			
		||||
            var context = new DefaultHttpContext
 | 
			
		||||
            {
 | 
			
		||||
                User = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
 | 
			
		||||
                {
 | 
			
		||||
                    new Claim("test", "data")
 | 
			
		||||
                }))
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(
 | 
			
		||||
                x => x.GivenClaimsToThings(new List<ClaimToThing>
 | 
			
		||||
                {
 | 
			
		||||
                    new ClaimToThing("claim-key", "", "", 0)
 | 
			
		||||
                }))
 | 
			
		||||
                .Given(x => x.GivenHttpContext(context))
 | 
			
		||||
                .And(x => x.GivenTheClaimParserReturns(new OkResponse<string>("value")))
 | 
			
		||||
                .When(x => x.WhenIAddClaimsToTheRequest())
 | 
			
		||||
                .Then(x => x.ThenTheResultIsSuccess())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void if_claims_exists_should_replace_it()
 | 
			
		||||
        {
 | 
			
		||||
            var context = new DefaultHttpContext
 | 
			
		||||
            {
 | 
			
		||||
                User = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
 | 
			
		||||
                {
 | 
			
		||||
                    new Claim("existing-key", "data"),
 | 
			
		||||
                    new Claim("new-key", "data")
 | 
			
		||||
                })),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(
 | 
			
		||||
                x => x.GivenClaimsToThings(new List<ClaimToThing>
 | 
			
		||||
                {
 | 
			
		||||
                    new ClaimToThing("existing-key", "new-key", "", 0)
 | 
			
		||||
                }))
 | 
			
		||||
                .Given(x => x.GivenHttpContext(context))
 | 
			
		||||
                .And(x => x.GivenTheClaimParserReturns(new OkResponse<string>("value")))
 | 
			
		||||
                .When(x => x.WhenIAddClaimsToTheRequest())
 | 
			
		||||
                .Then(x => x.ThenTheResultIsSuccess())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_error()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(
 | 
			
		||||
               x => x.GivenClaimsToThings(new List<ClaimToThing>
 | 
			
		||||
               {
 | 
			
		||||
                    new ClaimToThing("", "", "", 0)
 | 
			
		||||
               }))
 | 
			
		||||
               .Given(x => x.GivenHttpContext(new DefaultHttpContext()))
 | 
			
		||||
               .And(x => x.GivenTheClaimParserReturns(new ErrorResponse<string>(new List<Error>
 | 
			
		||||
               {
 | 
			
		||||
                   new AnyError()
 | 
			
		||||
               })))
 | 
			
		||||
               .When(x => x.WhenIAddClaimsToTheRequest())
 | 
			
		||||
               .Then(x => x.ThenTheResultIsError())
 | 
			
		||||
               .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenClaimsToThings(List<ClaimToThing> configuration)
 | 
			
		||||
        {
 | 
			
		||||
            _claimsToThings = configuration;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenHttpContext(HttpContext context)
 | 
			
		||||
        {
 | 
			
		||||
            _context = context;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheClaimParserReturns(Response<string> claimValue)
 | 
			
		||||
        {
 | 
			
		||||
            _claimValue = claimValue;
 | 
			
		||||
            _parser
 | 
			
		||||
                .Setup(
 | 
			
		||||
                    x =>
 | 
			
		||||
                        x.GetValue(It.IsAny<IEnumerable<Claim>>(),
 | 
			
		||||
                        It.IsAny<string>(),
 | 
			
		||||
                        It.IsAny<string>(),
 | 
			
		||||
                        It.IsAny<int>()))
 | 
			
		||||
                .Returns(_claimValue);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIAddClaimsToTheRequest()
 | 
			
		||||
        {
 | 
			
		||||
            _result = _addClaimsToRequest.SetClaimsOnContext(_claimsToThings, _context);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheResultIsSuccess()
 | 
			
		||||
        {
 | 
			
		||||
            _result.IsError.ShouldBe(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheResultIsError()
 | 
			
		||||
        {
 | 
			
		||||
            _result.IsError.ShouldBe(true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private class AnyError : Error
 | 
			
		||||
        {
 | 
			
		||||
            public AnyError()
 | 
			
		||||
                : base("blahh", OcelotErrorCode.UnknownError, 404)
 | 
			
		||||
            {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,89 +1,91 @@
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Claims
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Claims;
 | 
			
		||||
    using Ocelot.Claims.Middleware;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Claims
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Claims;
 | 
			
		||||
    using Ocelot.Claims.Middleware;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Responses;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class ClaimsToClaimsMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Mock<IAddClaimsToRequest> _addHeaders;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private readonly ClaimsToClaimsMiddleware _middleware;
 | 
			
		||||
        private readonly DownstreamContext _downstreamContext;
 | 
			
		||||
        private OcelotRequestDelegate _next;
 | 
			
		||||
 | 
			
		||||
        public ClaimsToClaimsMiddlewareTests()
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Responses;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class ClaimsToClaimsMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Mock<IAddClaimsToRequest> _addHeaders;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private readonly ClaimsToClaimsMiddleware _middleware;
 | 
			
		||||
        private RequestDelegate _next;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
 | 
			
		||||
        public ClaimsToClaimsMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
            _addHeaders = new Mock<IAddClaimsToRequest>();
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<ClaimsToClaimsMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _next = context => Task.CompletedTask;
 | 
			
		||||
            _middleware = new ClaimsToClaimsMiddleware(_next, _loggerFactory.Object, _addHeaders.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_claims_to_request_correctly()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamReRoute(new DownstreamReRouteBuilder()
 | 
			
		||||
                        .WithDownstreamPathTemplate("any old string")
 | 
			
		||||
                        .WithClaimsToClaims(new List<ClaimToThing>
 | 
			
		||||
                        {
 | 
			
		||||
                            new ClaimToThing("sub", "UserType", "|", 0)
 | 
			
		||||
                        })
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .Build())
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
                .And(x => x.GivenTheAddClaimsToRequestReturns())
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheClaimsToRequestIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_httpContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute)
 | 
			
		||||
        {
 | 
			
		||||
            _addHeaders = new Mock<IAddClaimsToRequest>();
 | 
			
		||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<ClaimsToClaimsMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _next = context => Task.CompletedTask;
 | 
			
		||||
            _middleware = new ClaimsToClaimsMiddleware(_next, _loggerFactory.Object, _addHeaders.Object);
 | 
			
		||||
        }
 | 
			
		||||
            _httpContext.Items.UpsertTemplatePlaceholderNameAndValues(downstreamRoute.TemplatePlaceholderNameAndValues);
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_claims_to_request_correctly()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamReRoute(new DownstreamReRouteBuilder()
 | 
			
		||||
                        .WithDownstreamPathTemplate("any old string")
 | 
			
		||||
                        .WithClaimsToClaims(new List<ClaimToThing>
 | 
			
		||||
                        {
 | 
			
		||||
                            new ClaimToThing("sub", "UserType", "|", 0)
 | 
			
		||||
                        })
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .Build())
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
                .And(x => x.GivenTheAddClaimsToRequestReturns())
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheClaimsToRequestIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.TemplatePlaceholderNameAndValues = downstreamRoute.TemplatePlaceholderNameAndValues;
 | 
			
		||||
            _downstreamContext.DownstreamReRoute = downstreamRoute.ReRoute.DownstreamReRoute[0];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheAddClaimsToRequestReturns()
 | 
			
		||||
        {
 | 
			
		||||
            _addHeaders
 | 
			
		||||
                .Setup(x => x.SetClaimsOnContext(It.IsAny<List<ClaimToThing>>(),
 | 
			
		||||
                It.IsAny<HttpContext>()))
 | 
			
		||||
                .Returns(new OkResponse());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheClaimsToRequestIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _addHeaders
 | 
			
		||||
                .Verify(x => x.SetClaimsOnContext(It.IsAny<List<ClaimToThing>>(),
 | 
			
		||||
                It.IsAny<HttpContext>()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamReRoute(downstreamRoute.ReRoute.DownstreamReRoute[0]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheAddClaimsToRequestReturns()
 | 
			
		||||
        {
 | 
			
		||||
            _addHeaders
 | 
			
		||||
                .Setup(x => x.SetClaimsOnContext(It.IsAny<List<ClaimToThing>>(),
 | 
			
		||||
                It.IsAny<HttpContext>()))
 | 
			
		||||
                .Returns(new OkResponse());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheClaimsToRequestIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _addHeaders
 | 
			
		||||
                .Verify(x => x.SetClaimsOnContext(It.IsAny<List<ClaimToThing>>(),
 | 
			
		||||
                It.IsAny<HttpContext>()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,135 +1,135 @@
 | 
			
		||||
using Microsoft.AspNetCore.Mvc;
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using Ocelot.Configuration.Setter;
 | 
			
		||||
using Ocelot.Errors;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using System;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Controllers
 | 
			
		||||
{
 | 
			
		||||
    using Ocelot.Configuration.Repository;
 | 
			
		||||
 | 
			
		||||
    public class FileConfigurationControllerTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly FileConfigurationController _controller;
 | 
			
		||||
        private readonly Mock<IFileConfigurationRepository> _repo;
 | 
			
		||||
        private readonly Mock<IFileConfigurationSetter> _setter;
 | 
			
		||||
        private IActionResult _result;
 | 
			
		||||
        private FileConfiguration _fileConfiguration;
 | 
			
		||||
        private readonly Mock<IServiceProvider> _provider;
 | 
			
		||||
 | 
			
		||||
        public FileConfigurationControllerTests()
 | 
			
		||||
        {
 | 
			
		||||
            _provider = new Mock<IServiceProvider>();
 | 
			
		||||
            _repo = new Mock<IFileConfigurationRepository>();
 | 
			
		||||
            _setter = new Mock<IFileConfigurationSetter>();
 | 
			
		||||
            _controller = new FileConfigurationController(_repo.Object, _setter.Object, _provider.Object);
 | 
			
		||||
using Microsoft.AspNetCore.Mvc;
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using Ocelot.Configuration.Setter;
 | 
			
		||||
using Ocelot.Errors;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using System;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Controllers
 | 
			
		||||
{
 | 
			
		||||
    using Ocelot.Configuration.Repository;
 | 
			
		||||
 | 
			
		||||
    public class FileConfigurationControllerTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly FileConfigurationController _controller;
 | 
			
		||||
        private readonly Mock<IFileConfigurationRepository> _repo;
 | 
			
		||||
        private readonly Mock<IFileConfigurationSetter> _setter;
 | 
			
		||||
        private IActionResult _result;
 | 
			
		||||
        private FileConfiguration _fileConfiguration;
 | 
			
		||||
        private readonly Mock<IServiceProvider> _provider;
 | 
			
		||||
 | 
			
		||||
        public FileConfigurationControllerTests()
 | 
			
		||||
        {
 | 
			
		||||
            _provider = new Mock<IServiceProvider>();
 | 
			
		||||
            _repo = new Mock<IFileConfigurationRepository>();
 | 
			
		||||
            _setter = new Mock<IFileConfigurationSetter>();
 | 
			
		||||
            _controller = new FileConfigurationController(_repo.Object, _setter.Object, _provider.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_get_file_configuration()
 | 
			
		||||
        {
 | 
			
		||||
            var expected = new Responses.OkResponse<FileConfiguration>(new FileConfiguration());
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheGetConfigurationReturns(expected))
 | 
			
		||||
                .When(x => x.WhenIGetTheFileConfiguration())
 | 
			
		||||
                .Then(x => x.TheTheGetFileConfigurationIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_error_when_cannot_get_config()
 | 
			
		||||
        {
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_get_file_configuration()
 | 
			
		||||
        {
 | 
			
		||||
            var expected = new Responses.OkResponse<FileConfiguration>(new FileConfiguration());
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheGetConfigurationReturns(expected))
 | 
			
		||||
                .When(x => x.WhenIGetTheFileConfiguration())
 | 
			
		||||
                .Then(x => x.TheTheGetFileConfigurationIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_error_when_cannot_get_config()
 | 
			
		||||
        {
 | 
			
		||||
            var expected = new Responses.ErrorResponse<FileConfiguration>(It.IsAny<Error>());
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheGetConfigurationReturns(expected))
 | 
			
		||||
               .When(x => x.WhenIGetTheFileConfiguration())
 | 
			
		||||
               .Then(x => x.TheTheGetFileConfigurationIsCalledCorrectly())
 | 
			
		||||
               .And(x => x.ThenTheResponseIs<BadRequestObjectResult>())
 | 
			
		||||
               .BDDfy();
 | 
			
		||||
               .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_post_file_configuration()
 | 
			
		||||
        {
 | 
			
		||||
            var expected = new FileConfiguration();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFileConfiguration(expected))
 | 
			
		||||
                .And(x => GivenTheConfigSetterReturns(new OkResponse()))
 | 
			
		||||
                .When(x => WhenIPostTheFileConfiguration())
 | 
			
		||||
                .Then(x => x.ThenTheConfigrationSetterIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_error_when_cannot_set_config()
 | 
			
		||||
        {
 | 
			
		||||
            var expected = new FileConfiguration();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFileConfiguration(expected))
 | 
			
		||||
                .And(x => GivenTheConfigSetterReturns(new ErrorResponse(new FakeError())))
 | 
			
		||||
                .When(x => WhenIPostTheFileConfiguration())
 | 
			
		||||
                .Then(x => x.ThenTheConfigrationSetterIsCalledCorrectly())
 | 
			
		||||
                .And(x => ThenTheResponseIs<BadRequestObjectResult>())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheConfigSetterReturns(Response response)
 | 
			
		||||
        {
 | 
			
		||||
            _setter
 | 
			
		||||
                .Setup(x => x.Set(It.IsAny<FileConfiguration>()))
 | 
			
		||||
                .ReturnsAsync(response);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheConfigrationSetterIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _setter
 | 
			
		||||
                .Verify(x => x.Set(_fileConfiguration), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIPostTheFileConfiguration()
 | 
			
		||||
        {
 | 
			
		||||
            _result = _controller.Post(_fileConfiguration).Result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFileConfiguration(FileConfiguration fileConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            _fileConfiguration = fileConfiguration;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheResponseIs<T>()
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_post_file_configuration()
 | 
			
		||||
        {
 | 
			
		||||
            _result.ShouldBeOfType<T>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheGetConfigurationReturns(Ocelot.Responses.Response<FileConfiguration> fileConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            _repo
 | 
			
		||||
                .Setup(x => x.Get())
 | 
			
		||||
                .ReturnsAsync(fileConfiguration);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIGetTheFileConfiguration()
 | 
			
		||||
        {
 | 
			
		||||
            _result = _controller.Get().Result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void TheTheGetFileConfigurationIsCalledCorrectly()
 | 
			
		||||
            var expected = new FileConfiguration();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFileConfiguration(expected))
 | 
			
		||||
                .And(x => GivenTheConfigSetterReturns(new OkResponse()))
 | 
			
		||||
                .When(x => WhenIPostTheFileConfiguration())
 | 
			
		||||
                .Then(x => x.ThenTheConfigrationSetterIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_error_when_cannot_set_config()
 | 
			
		||||
        {
 | 
			
		||||
            var expected = new FileConfiguration();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFileConfiguration(expected))
 | 
			
		||||
                .And(x => GivenTheConfigSetterReturns(new ErrorResponse(new FakeError())))
 | 
			
		||||
                .When(x => WhenIPostTheFileConfiguration())
 | 
			
		||||
                .Then(x => x.ThenTheConfigrationSetterIsCalledCorrectly())
 | 
			
		||||
                .And(x => ThenTheResponseIs<BadRequestObjectResult>())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheConfigSetterReturns(Response response)
 | 
			
		||||
        {
 | 
			
		||||
            _setter
 | 
			
		||||
                .Setup(x => x.Set(It.IsAny<FileConfiguration>()))
 | 
			
		||||
                .ReturnsAsync(response);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheConfigrationSetterIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _setter
 | 
			
		||||
                .Verify(x => x.Set(_fileConfiguration), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIPostTheFileConfiguration()
 | 
			
		||||
        {
 | 
			
		||||
            _result = _controller.Post(_fileConfiguration).Result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFileConfiguration(FileConfiguration fileConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            _fileConfiguration = fileConfiguration;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheResponseIs<T>()
 | 
			
		||||
        {
 | 
			
		||||
            _result.ShouldBeOfType<T>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheGetConfigurationReturns(Ocelot.Responses.Response<FileConfiguration> fileConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            _repo
 | 
			
		||||
             .Verify(x => x.Get(), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private class FakeError : Error
 | 
			
		||||
        {
 | 
			
		||||
            public FakeError() : base(string.Empty, OcelotErrorCode.CannotAddDataError)
 | 
			
		||||
            {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
                .Setup(x => x.Get())
 | 
			
		||||
                .ReturnsAsync(fileConfiguration);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIGetTheFileConfiguration()
 | 
			
		||||
        {
 | 
			
		||||
            _result = _controller.Get().Result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void TheTheGetFileConfigurationIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _repo
 | 
			
		||||
             .Verify(x => x.Get(), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private class FakeError : Error
 | 
			
		||||
        {
 | 
			
		||||
            public FakeError() : base(string.Empty, OcelotErrorCode.CannotAddDataError, 404)
 | 
			
		||||
            {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,404 +1,403 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Ocelot.LoadBalancer.LoadBalancers;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Ocelot.Values;
 | 
			
		||||
namespace Ocelot.UnitTests.DependencyInjection
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Hosting;
 | 
			
		||||
    using Microsoft.Extensions.Configuration;
 | 
			
		||||
    using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Configuration.Setter;
 | 
			
		||||
    using Ocelot.DependencyInjection;
 | 
			
		||||
    using Ocelot.Infrastructure;
 | 
			
		||||
    using Ocelot.Multiplexer;
 | 
			
		||||
    using Ocelot.Requester;
 | 
			
		||||
    using Ocelot.UnitTests.Requester;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Linq;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Reflection;
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using Ocelot.LoadBalancer.LoadBalancers;
 | 
			
		||||
    using Ocelot.Responses;
 | 
			
		||||
    using Ocelot.Values;
 | 
			
		||||
    using static Ocelot.UnitTests.Multiplexing.UserDefinedResponseAggregatorTests;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.DependencyInjection
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Hosting;
 | 
			
		||||
    using Microsoft.Extensions.Configuration;
 | 
			
		||||
    using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Configuration.Setter;
 | 
			
		||||
    using Ocelot.DependencyInjection;
 | 
			
		||||
    using Ocelot.Infrastructure;
 | 
			
		||||
    using Ocelot.Middleware.Multiplexer;
 | 
			
		||||
    using Ocelot.Requester;
 | 
			
		||||
    using Ocelot.UnitTests.Requester;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Linq;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Reflection;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
    using static Ocelot.UnitTests.Middleware.UserDefinedResponseAggregatorTests;
 | 
			
		||||
 | 
			
		||||
    public class OcelotBuilderTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IServiceCollection _services;
 | 
			
		||||
        private IServiceProvider _serviceProvider;
 | 
			
		||||
        private readonly IConfiguration _configRoot;
 | 
			
		||||
        private IOcelotBuilder _ocelotBuilder;
 | 
			
		||||
        private readonly int _maxRetries;
 | 
			
		||||
        private Exception _ex;
 | 
			
		||||
 | 
			
		||||
        public OcelotBuilderTests()
 | 
			
		||||
        {
 | 
			
		||||
            _configRoot = new ConfigurationRoot(new List<IConfigurationProvider>());
 | 
			
		||||
            _services = new ServiceCollection();
 | 
			
		||||
            _services.AddSingleton<IWebHostEnvironment>(GetHostingEnvironment());
 | 
			
		||||
            _services.AddSingleton(_configRoot);
 | 
			
		||||
            _maxRetries = 100;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private IWebHostEnvironment GetHostingEnvironment()
 | 
			
		||||
        {
 | 
			
		||||
            var environment = new Mock<IWebHostEnvironment>();
 | 
			
		||||
            environment
 | 
			
		||||
                .Setup(e => e.ApplicationName)
 | 
			
		||||
                .Returns(typeof(OcelotBuilderTests).GetTypeInfo().Assembly.GetName().Name);
 | 
			
		||||
 | 
			
		||||
            return environment.Object;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_specific_delegating_handlers_transient()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => AddSpecificTransientDelegatingHandler<FakeDelegatingHandler>())
 | 
			
		||||
                .And(x => AddSpecificTransientDelegatingHandler<FakeDelegatingHandlerTwo>())
 | 
			
		||||
                .Then(x => ThenTheProviderIsRegisteredAndReturnsSpecificHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
 | 
			
		||||
                .And(x => ThenTheSpecificHandlersAreTransient())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_type_specific_delegating_handlers_transient()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => AddTypeSpecificTransientDelegatingHandler(typeof(FakeDelegatingHandler)))
 | 
			
		||||
                .And(x => AddTypeSpecificTransientDelegatingHandler(typeof(FakeDelegatingHandlerTwo)))
 | 
			
		||||
                .Then(x => ThenTheProviderIsRegisteredAndReturnsSpecificHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
 | 
			
		||||
                .And(x => ThenTheSpecificHandlersAreTransient())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_global_delegating_handlers_transient()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => AddTransientGlobalDelegatingHandler<FakeDelegatingHandler>())
 | 
			
		||||
                .And(x => AddTransientGlobalDelegatingHandler<FakeDelegatingHandlerTwo>())
 | 
			
		||||
                .Then(x => ThenTheProviderIsRegisteredAndReturnsHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
 | 
			
		||||
                .And(x => ThenTheGlobalHandlersAreTransient())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_global_type_delegating_handlers_transient()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => AddTransientGlobalDelegatingHandler<FakeDelegatingHandler>())
 | 
			
		||||
                .And(x => AddTransientGlobalDelegatingHandler<FakeDelegatingHandlerTwo>())
 | 
			
		||||
                .Then(x => ThenTheProviderIsRegisteredAndReturnsHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
 | 
			
		||||
                .And(x => ThenTheGlobalHandlersAreTransient())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_set_up_services()
 | 
			
		||||
        {
 | 
			
		||||
            this.When(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .Then(x => ThenAnExceptionIsntThrown())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_ocelot_builder()
 | 
			
		||||
        {
 | 
			
		||||
            this.When(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .Then(x => ThenAnOcelotBuilderIsReturned())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_use_logger_factory()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => WhenIValidateScopes())
 | 
			
		||||
                .When(x => WhenIAccessLoggerFactory())
 | 
			
		||||
                .Then(x => ThenAnExceptionIsntThrown())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_set_up_without_passing_in_config()
 | 
			
		||||
        {
 | 
			
		||||
            this.When(x => WhenISetUpOcelotServicesWithoutConfig())
 | 
			
		||||
                .Then(x => ThenAnExceptionIsntThrown())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_singleton_defined_aggregators()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => AddSingletonDefinedAggregator<TestDefinedAggregator>())
 | 
			
		||||
                .When(x => AddSingletonDefinedAggregator<TestDefinedAggregator>())
 | 
			
		||||
                .Then(x => ThenTheProviderIsRegisteredAndReturnsSpecificAggregators<TestDefinedAggregator, TestDefinedAggregator>())
 | 
			
		||||
                .And(x => ThenTheAggregatorsAreSingleton<TestDefinedAggregator, TestDefinedAggregator>())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_transient_defined_aggregators()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => AddTransientDefinedAggregator<TestDefinedAggregator>())
 | 
			
		||||
                .When(x => AddTransientDefinedAggregator<TestDefinedAggregator>())
 | 
			
		||||
                .Then(x => ThenTheProviderIsRegisteredAndReturnsSpecificAggregators<TestDefinedAggregator, TestDefinedAggregator>())
 | 
			
		||||
                .And(x => ThenTheAggregatorsAreTransient<TestDefinedAggregator, TestDefinedAggregator>())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_custom_load_balancer_creators_by_default_ctor()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => _ocelotBuilder.AddCustomLoadBalancer<FakeCustomLoadBalancer>())
 | 
			
		||||
                .Then(x => ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_custom_load_balancer_creators_by_factory_method()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => _ocelotBuilder.AddCustomLoadBalancer(() => new FakeCustomLoadBalancer()))
 | 
			
		||||
                .Then(x => ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_custom_load_balancer_creators_by_di_factory_method()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => _ocelotBuilder.AddCustomLoadBalancer(provider => new FakeCustomLoadBalancer()))
 | 
			
		||||
                .Then(x => ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_custom_load_balancer_creators_by_factory_method_with_arguments()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => _ocelotBuilder.AddCustomLoadBalancer((reroute, discoveryProvider) => new FakeCustomLoadBalancer()))
 | 
			
		||||
                .Then(x => ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_replace_iplaceholder()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => AddConfigPlaceholders())
 | 
			
		||||
                .Then(x => ThenAnExceptionIsntThrown())
 | 
			
		||||
                .And(x => ThenTheIPlaceholderInstanceIsReplaced())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_custom_load_balancer_creators()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => _ocelotBuilder.AddCustomLoadBalancer((provider, reroute, discoveryProvider) => new FakeCustomLoadBalancer()))
 | 
			
		||||
                .Then(x => ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void AddSingletonDefinedAggregator<T>()
 | 
			
		||||
            where T : class, IDefinedAggregator
 | 
			
		||||
        {
 | 
			
		||||
            _ocelotBuilder.AddSingletonDefinedAggregator<T>();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        private void AddTransientDefinedAggregator<T>()
 | 
			
		||||
            where T : class, IDefinedAggregator
 | 
			
		||||
        {
 | 
			
		||||
            _ocelotBuilder.AddTransientDefinedAggregator<T>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void AddConfigPlaceholders()
 | 
			
		||||
        {
 | 
			
		||||
            _ocelotBuilder.AddConfigPlaceholders();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheSpecificHandlersAreTransient()
 | 
			
		||||
        {
 | 
			
		||||
            var handlers = _serviceProvider.GetServices<DelegatingHandler>().ToList();
 | 
			
		||||
            var first = handlers[0];
 | 
			
		||||
            handlers = _serviceProvider.GetServices<DelegatingHandler>().ToList();
 | 
			
		||||
            var second = handlers[0];
 | 
			
		||||
            first.ShouldNotBe(second);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheGlobalHandlersAreTransient()
 | 
			
		||||
        {
 | 
			
		||||
            var handlers = _serviceProvider.GetServices<GlobalDelegatingHandler>().ToList();
 | 
			
		||||
            var first = handlers[0].DelegatingHandler;
 | 
			
		||||
            handlers = _serviceProvider.GetServices<GlobalDelegatingHandler>().ToList();
 | 
			
		||||
            var second = handlers[0].DelegatingHandler;
 | 
			
		||||
            first.ShouldNotBe(second);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void AddTransientGlobalDelegatingHandler<T>()
 | 
			
		||||
            where T : DelegatingHandler
 | 
			
		||||
        {
 | 
			
		||||
            _ocelotBuilder.AddDelegatingHandler<T>(true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void AddSpecificTransientDelegatingHandler<T>()
 | 
			
		||||
            where T : DelegatingHandler
 | 
			
		||||
        {
 | 
			
		||||
            _ocelotBuilder.AddDelegatingHandler<T>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void AddTypeTransientGlobalDelegatingHandler(Type type)
 | 
			
		||||
        {
 | 
			
		||||
            _ocelotBuilder.AddDelegatingHandler(type, true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void AddTypeSpecificTransientDelegatingHandler(Type type)
 | 
			
		||||
        {
 | 
			
		||||
            _ocelotBuilder.AddDelegatingHandler(type);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheProviderIsRegisteredAndReturnsHandlers<TOne, TWo>()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceProvider = _services.BuildServiceProvider();
 | 
			
		||||
            var handlers = _serviceProvider.GetServices<GlobalDelegatingHandler>().ToList();
 | 
			
		||||
            handlers[0].DelegatingHandler.ShouldBeOfType<TOne>();
 | 
			
		||||
            handlers[1].DelegatingHandler.ShouldBeOfType<TWo>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheProviderIsRegisteredAndReturnsSpecificHandlers<TOne, TWo>()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceProvider = _services.BuildServiceProvider();
 | 
			
		||||
            var handlers = _serviceProvider.GetServices<DelegatingHandler>().ToList();
 | 
			
		||||
            handlers[0].ShouldBeOfType<TOne>();
 | 
			
		||||
            handlers[1].ShouldBeOfType<TWo>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheProviderIsRegisteredAndReturnsSpecificAggregators<TOne, TWo>()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceProvider = _services.BuildServiceProvider();
 | 
			
		||||
            var handlers = _serviceProvider.GetServices<IDefinedAggregator>().ToList();
 | 
			
		||||
            handlers[0].ShouldBeOfType<TOne>();
 | 
			
		||||
            handlers[1].ShouldBeOfType<TWo>();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        private void ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceProvider = _services.BuildServiceProvider();
 | 
			
		||||
            var creators = _serviceProvider.GetServices<ILoadBalancerCreator>().ToList();
 | 
			
		||||
            creators.Count(c => c.GetType() == typeof(NoLoadBalancerCreator)).ShouldBe(1);
 | 
			
		||||
            creators.Count(c => c.GetType() == typeof(RoundRobinCreator)).ShouldBe(1);
 | 
			
		||||
            creators.Count(c => c.GetType() == typeof(CookieStickySessionsCreator)).ShouldBe(1);
 | 
			
		||||
            creators.Count(c => c.GetType() == typeof(LeastConnectionCreator)).ShouldBe(1);
 | 
			
		||||
            creators.Count(c => c.GetType() == typeof(DelegateInvokingLoadBalancerCreator<FakeCustomLoadBalancer>)).ShouldBe(1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheAggregatorsAreTransient<TOne, TWo>()
 | 
			
		||||
        {
 | 
			
		||||
            var aggregators = _serviceProvider.GetServices<IDefinedAggregator>().ToList();
 | 
			
		||||
            var first = aggregators[0];
 | 
			
		||||
            aggregators = _serviceProvider.GetServices<IDefinedAggregator>().ToList();
 | 
			
		||||
            var second = aggregators[0];
 | 
			
		||||
            first.ShouldNotBe(second);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheAggregatorsAreSingleton<TOne, TWo>()
 | 
			
		||||
        {
 | 
			
		||||
            var aggregators = _serviceProvider.GetServices<IDefinedAggregator>().ToList();
 | 
			
		||||
            var first = aggregators[0];
 | 
			
		||||
            aggregators = _serviceProvider.GetServices<IDefinedAggregator>().ToList();
 | 
			
		||||
            var second = aggregators[0];
 | 
			
		||||
            first.ShouldBe(second);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenAnOcelotBuilderIsReturned()
 | 
			
		||||
        {
 | 
			
		||||
            _ocelotBuilder.ShouldBeOfType<OcelotBuilder>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheIPlaceholderInstanceIsReplaced()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceProvider = _services.BuildServiceProvider();
 | 
			
		||||
            var placeholders = _serviceProvider.GetService<IPlaceholders>();
 | 
			
		||||
            placeholders.ShouldBeOfType<ConfigAwarePlaceholders>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenISetUpOcelotServices()
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                _ocelotBuilder = _services.AddOcelot(_configRoot);
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception e)
 | 
			
		||||
            {
 | 
			
		||||
                _ex = e;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenISetUpOcelotServicesWithoutConfig()
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                _ocelotBuilder = _services.AddOcelot();
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception e)
 | 
			
		||||
            {
 | 
			
		||||
                _ex = e;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIAccessLoggerFactory()
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                _serviceProvider = _services.BuildServiceProvider();
 | 
			
		||||
                var logger = _serviceProvider.GetService<IFileConfigurationSetter>();
 | 
			
		||||
                logger.ShouldNotBeNull();
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception e)
 | 
			
		||||
            {
 | 
			
		||||
                _ex = e;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIValidateScopes()
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                _serviceProvider = _services.BuildServiceProvider(new ServiceProviderOptions { ValidateScopes = true });
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception e)
 | 
			
		||||
            {
 | 
			
		||||
                _ex = e;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenAnExceptionIsntThrown()
 | 
			
		||||
        {
 | 
			
		||||
            _ex.ShouldBeNull();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private class FakeCustomLoadBalancer : ILoadBalancer
 | 
			
		||||
        {
 | 
			
		||||
            public Task<Response<ServiceHostAndPort>> Lease(DownstreamContext context)
 | 
			
		||||
            {
 | 
			
		||||
                // Not relevant for these tests
 | 
			
		||||
                throw new NotImplementedException();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public void Release(ServiceHostAndPort hostAndPort)
 | 
			
		||||
            {
 | 
			
		||||
                // Not relevant for these tests
 | 
			
		||||
                throw new NotImplementedException();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
    public class OcelotBuilderTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IServiceCollection _services;
 | 
			
		||||
        private IServiceProvider _serviceProvider;
 | 
			
		||||
        private readonly IConfiguration _configRoot;
 | 
			
		||||
        private IOcelotBuilder _ocelotBuilder;
 | 
			
		||||
        private readonly int _maxRetries;
 | 
			
		||||
        private Exception _ex;
 | 
			
		||||
 | 
			
		||||
        public OcelotBuilderTests()
 | 
			
		||||
        {
 | 
			
		||||
            _configRoot = new ConfigurationRoot(new List<IConfigurationProvider>());
 | 
			
		||||
            _services = new ServiceCollection();
 | 
			
		||||
            _services.AddSingleton<IWebHostEnvironment>(GetHostingEnvironment());
 | 
			
		||||
            _services.AddSingleton(_configRoot);
 | 
			
		||||
            _maxRetries = 100;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private IWebHostEnvironment GetHostingEnvironment()
 | 
			
		||||
        {
 | 
			
		||||
            var environment = new Mock<IWebHostEnvironment>();
 | 
			
		||||
            environment
 | 
			
		||||
                .Setup(e => e.ApplicationName)
 | 
			
		||||
                .Returns(typeof(OcelotBuilderTests).GetTypeInfo().Assembly.GetName().Name);
 | 
			
		||||
 | 
			
		||||
            return environment.Object;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_specific_delegating_handlers_transient()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => AddSpecificTransientDelegatingHandler<FakeDelegatingHandler>())
 | 
			
		||||
                .And(x => AddSpecificTransientDelegatingHandler<FakeDelegatingHandlerTwo>())
 | 
			
		||||
                .Then(x => ThenTheProviderIsRegisteredAndReturnsSpecificHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
 | 
			
		||||
                .And(x => ThenTheSpecificHandlersAreTransient())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_type_specific_delegating_handlers_transient()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => AddTypeSpecificTransientDelegatingHandler(typeof(FakeDelegatingHandler)))
 | 
			
		||||
                .And(x => AddTypeSpecificTransientDelegatingHandler(typeof(FakeDelegatingHandlerTwo)))
 | 
			
		||||
                .Then(x => ThenTheProviderIsRegisteredAndReturnsSpecificHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
 | 
			
		||||
                .And(x => ThenTheSpecificHandlersAreTransient())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_global_delegating_handlers_transient()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => AddTransientGlobalDelegatingHandler<FakeDelegatingHandler>())
 | 
			
		||||
                .And(x => AddTransientGlobalDelegatingHandler<FakeDelegatingHandlerTwo>())
 | 
			
		||||
                .Then(x => ThenTheProviderIsRegisteredAndReturnsHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
 | 
			
		||||
                .And(x => ThenTheGlobalHandlersAreTransient())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_global_type_delegating_handlers_transient()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => AddTransientGlobalDelegatingHandler<FakeDelegatingHandler>())
 | 
			
		||||
                .And(x => AddTransientGlobalDelegatingHandler<FakeDelegatingHandlerTwo>())
 | 
			
		||||
                .Then(x => ThenTheProviderIsRegisteredAndReturnsHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
 | 
			
		||||
                .And(x => ThenTheGlobalHandlersAreTransient())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_set_up_services()
 | 
			
		||||
        {
 | 
			
		||||
            this.When(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .Then(x => ThenAnExceptionIsntThrown())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_ocelot_builder()
 | 
			
		||||
        {
 | 
			
		||||
            this.When(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .Then(x => ThenAnOcelotBuilderIsReturned())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_use_logger_factory()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => WhenIValidateScopes())
 | 
			
		||||
                .When(x => WhenIAccessLoggerFactory())
 | 
			
		||||
                .Then(x => ThenAnExceptionIsntThrown())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_set_up_without_passing_in_config()
 | 
			
		||||
        {
 | 
			
		||||
            this.When(x => WhenISetUpOcelotServicesWithoutConfig())
 | 
			
		||||
                .Then(x => ThenAnExceptionIsntThrown())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_singleton_defined_aggregators()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => AddSingletonDefinedAggregator<TestDefinedAggregator>())
 | 
			
		||||
                .When(x => AddSingletonDefinedAggregator<TestDefinedAggregator>())
 | 
			
		||||
                .Then(x => ThenTheProviderIsRegisteredAndReturnsSpecificAggregators<TestDefinedAggregator, TestDefinedAggregator>())
 | 
			
		||||
                .And(x => ThenTheAggregatorsAreSingleton<TestDefinedAggregator, TestDefinedAggregator>())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_transient_defined_aggregators()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => AddTransientDefinedAggregator<TestDefinedAggregator>())
 | 
			
		||||
                .When(x => AddTransientDefinedAggregator<TestDefinedAggregator>())
 | 
			
		||||
                .Then(x => ThenTheProviderIsRegisteredAndReturnsSpecificAggregators<TestDefinedAggregator, TestDefinedAggregator>())
 | 
			
		||||
                .And(x => ThenTheAggregatorsAreTransient<TestDefinedAggregator, TestDefinedAggregator>())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_custom_load_balancer_creators_by_default_ctor()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => _ocelotBuilder.AddCustomLoadBalancer<FakeCustomLoadBalancer>())
 | 
			
		||||
                .Then(x => ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_custom_load_balancer_creators_by_factory_method()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => _ocelotBuilder.AddCustomLoadBalancer(() => new FakeCustomLoadBalancer()))
 | 
			
		||||
                .Then(x => ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_custom_load_balancer_creators_by_di_factory_method()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => _ocelotBuilder.AddCustomLoadBalancer(provider => new FakeCustomLoadBalancer()))
 | 
			
		||||
                .Then(x => ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_custom_load_balancer_creators_by_factory_method_with_arguments()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => _ocelotBuilder.AddCustomLoadBalancer((reroute, discoveryProvider) => new FakeCustomLoadBalancer()))
 | 
			
		||||
                .Then(x => ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_replace_iplaceholder()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => AddConfigPlaceholders())
 | 
			
		||||
                .Then(x => ThenAnExceptionIsntThrown())
 | 
			
		||||
                .And(x => ThenTheIPlaceholderInstanceIsReplaced())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_custom_load_balancer_creators()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => _ocelotBuilder.AddCustomLoadBalancer((provider, reroute, discoveryProvider) => new FakeCustomLoadBalancer()))
 | 
			
		||||
                .Then(x => ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void AddSingletonDefinedAggregator<T>()
 | 
			
		||||
            where T : class, IDefinedAggregator
 | 
			
		||||
        {
 | 
			
		||||
            _ocelotBuilder.AddSingletonDefinedAggregator<T>();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        private void AddTransientDefinedAggregator<T>()
 | 
			
		||||
            where T : class, IDefinedAggregator
 | 
			
		||||
        {
 | 
			
		||||
            _ocelotBuilder.AddTransientDefinedAggregator<T>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void AddConfigPlaceholders()
 | 
			
		||||
        {
 | 
			
		||||
            _ocelotBuilder.AddConfigPlaceholders();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheSpecificHandlersAreTransient()
 | 
			
		||||
        {
 | 
			
		||||
            var handlers = _serviceProvider.GetServices<DelegatingHandler>().ToList();
 | 
			
		||||
            var first = handlers[0];
 | 
			
		||||
            handlers = _serviceProvider.GetServices<DelegatingHandler>().ToList();
 | 
			
		||||
            var second = handlers[0];
 | 
			
		||||
            first.ShouldNotBe(second);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheGlobalHandlersAreTransient()
 | 
			
		||||
        {
 | 
			
		||||
            var handlers = _serviceProvider.GetServices<GlobalDelegatingHandler>().ToList();
 | 
			
		||||
            var first = handlers[0].DelegatingHandler;
 | 
			
		||||
            handlers = _serviceProvider.GetServices<GlobalDelegatingHandler>().ToList();
 | 
			
		||||
            var second = handlers[0].DelegatingHandler;
 | 
			
		||||
            first.ShouldNotBe(second);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void AddTransientGlobalDelegatingHandler<T>()
 | 
			
		||||
            where T : DelegatingHandler
 | 
			
		||||
        {
 | 
			
		||||
            _ocelotBuilder.AddDelegatingHandler<T>(true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void AddSpecificTransientDelegatingHandler<T>()
 | 
			
		||||
            where T : DelegatingHandler
 | 
			
		||||
        {
 | 
			
		||||
            _ocelotBuilder.AddDelegatingHandler<T>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void AddTypeTransientGlobalDelegatingHandler(Type type)
 | 
			
		||||
        {
 | 
			
		||||
            _ocelotBuilder.AddDelegatingHandler(type, true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void AddTypeSpecificTransientDelegatingHandler(Type type)
 | 
			
		||||
        {
 | 
			
		||||
            _ocelotBuilder.AddDelegatingHandler(type);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheProviderIsRegisteredAndReturnsHandlers<TOne, TWo>()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceProvider = _services.BuildServiceProvider();
 | 
			
		||||
            var handlers = _serviceProvider.GetServices<GlobalDelegatingHandler>().ToList();
 | 
			
		||||
            handlers[0].DelegatingHandler.ShouldBeOfType<TOne>();
 | 
			
		||||
            handlers[1].DelegatingHandler.ShouldBeOfType<TWo>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheProviderIsRegisteredAndReturnsSpecificHandlers<TOne, TWo>()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceProvider = _services.BuildServiceProvider();
 | 
			
		||||
            var handlers = _serviceProvider.GetServices<DelegatingHandler>().ToList();
 | 
			
		||||
            handlers[0].ShouldBeOfType<TOne>();
 | 
			
		||||
            handlers[1].ShouldBeOfType<TWo>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheProviderIsRegisteredAndReturnsSpecificAggregators<TOne, TWo>()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceProvider = _services.BuildServiceProvider();
 | 
			
		||||
            var handlers = _serviceProvider.GetServices<IDefinedAggregator>().ToList();
 | 
			
		||||
            handlers[0].ShouldBeOfType<TOne>();
 | 
			
		||||
            handlers[1].ShouldBeOfType<TWo>();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        private void ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceProvider = _services.BuildServiceProvider();
 | 
			
		||||
            var creators = _serviceProvider.GetServices<ILoadBalancerCreator>().ToList();
 | 
			
		||||
            creators.Count(c => c.GetType() == typeof(NoLoadBalancerCreator)).ShouldBe(1);
 | 
			
		||||
            creators.Count(c => c.GetType() == typeof(RoundRobinCreator)).ShouldBe(1);
 | 
			
		||||
            creators.Count(c => c.GetType() == typeof(CookieStickySessionsCreator)).ShouldBe(1);
 | 
			
		||||
            creators.Count(c => c.GetType() == typeof(LeastConnectionCreator)).ShouldBe(1);
 | 
			
		||||
            creators.Count(c => c.GetType() == typeof(DelegateInvokingLoadBalancerCreator<FakeCustomLoadBalancer>)).ShouldBe(1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheAggregatorsAreTransient<TOne, TWo>()
 | 
			
		||||
        {
 | 
			
		||||
            var aggregators = _serviceProvider.GetServices<IDefinedAggregator>().ToList();
 | 
			
		||||
            var first = aggregators[0];
 | 
			
		||||
            aggregators = _serviceProvider.GetServices<IDefinedAggregator>().ToList();
 | 
			
		||||
            var second = aggregators[0];
 | 
			
		||||
            first.ShouldNotBe(second);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheAggregatorsAreSingleton<TOne, TWo>()
 | 
			
		||||
        {
 | 
			
		||||
            var aggregators = _serviceProvider.GetServices<IDefinedAggregator>().ToList();
 | 
			
		||||
            var first = aggregators[0];
 | 
			
		||||
            aggregators = _serviceProvider.GetServices<IDefinedAggregator>().ToList();
 | 
			
		||||
            var second = aggregators[0];
 | 
			
		||||
            first.ShouldBe(second);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenAnOcelotBuilderIsReturned()
 | 
			
		||||
        {
 | 
			
		||||
            _ocelotBuilder.ShouldBeOfType<OcelotBuilder>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheIPlaceholderInstanceIsReplaced()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceProvider = _services.BuildServiceProvider();
 | 
			
		||||
            var placeholders = _serviceProvider.GetService<IPlaceholders>();
 | 
			
		||||
            placeholders.ShouldBeOfType<ConfigAwarePlaceholders>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenISetUpOcelotServices()
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                _ocelotBuilder = _services.AddOcelot(_configRoot);
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception e)
 | 
			
		||||
            {
 | 
			
		||||
                _ex = e;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenISetUpOcelotServicesWithoutConfig()
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                _ocelotBuilder = _services.AddOcelot();
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception e)
 | 
			
		||||
            {
 | 
			
		||||
                _ex = e;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIAccessLoggerFactory()
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                _serviceProvider = _services.BuildServiceProvider();
 | 
			
		||||
                var logger = _serviceProvider.GetService<IFileConfigurationSetter>();
 | 
			
		||||
                logger.ShouldNotBeNull();
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception e)
 | 
			
		||||
            {
 | 
			
		||||
                _ex = e;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIValidateScopes()
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                _serviceProvider = _services.BuildServiceProvider(new ServiceProviderOptions { ValidateScopes = true });
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception e)
 | 
			
		||||
            {
 | 
			
		||||
                _ex = e;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenAnExceptionIsntThrown()
 | 
			
		||||
        {
 | 
			
		||||
            _ex.ShouldBeNull();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private class FakeCustomLoadBalancer : ILoadBalancer
 | 
			
		||||
        {
 | 
			
		||||
            public Task<Response<ServiceHostAndPort>> Lease(HttpContext httpContext)
 | 
			
		||||
            {
 | 
			
		||||
                // Not relevant for these tests
 | 
			
		||||
                throw new NotImplementedException();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public void Release(ServiceHostAndPort hostAndPort)
 | 
			
		||||
            {
 | 
			
		||||
                // Not relevant for these tests
 | 
			
		||||
                throw new NotImplementedException();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,101 +1,104 @@
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Configuration.Builder;
 | 
			
		||||
using Ocelot.DownstreamRouteFinder;
 | 
			
		||||
using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Ocelot.PathManipulation;
 | 
			
		||||
using Ocelot.PathManipulation.Middleware;
 | 
			
		||||
using Ocelot.Request.Middleware;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Ocelot.Values;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Security.Claims;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
namespace Ocelot.UnitTests.DownstreamPathManipulation
 | 
			
		||||
{
 | 
			
		||||
    using Ocelot.DownstreamPathManipulation.Middleware;
 | 
			
		||||
    using Ocelot.Infrastructure.RequestData;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Ocelot.PathManipulation;
 | 
			
		||||
    using Ocelot.Request.Middleware;
 | 
			
		||||
    using Ocelot.Responses;
 | 
			
		||||
    using Ocelot.Values;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Security.Claims;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.DownstreamPathManipulation
 | 
			
		||||
{
 | 
			
		||||
    public class ClaimsToDownstreamPathMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Mock<IChangeDownstreamPathTemplate> _changePath;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private ClaimsToDownstreamPathMiddleware _middleware;
 | 
			
		||||
        private DownstreamContext _downstreamContext;
 | 
			
		||||
        private OcelotRequestDelegate _next;
 | 
			
		||||
 | 
			
		||||
        public ClaimsToDownstreamPathMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<ClaimsToDownstreamPathMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _next = context => Task.CompletedTask;
 | 
			
		||||
    public class ClaimsToDownstreamPathMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Mock<IChangeDownstreamPathTemplate> _changePath;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private ClaimsToDownstreamPathMiddleware _middleware;
 | 
			
		||||
        private RequestDelegate _next;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
 | 
			
		||||
        public ClaimsToDownstreamPathMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<ClaimsToDownstreamPathMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _next = context => Task.CompletedTask;
 | 
			
		||||
            _changePath = new Mock<IChangeDownstreamPathTemplate>();
 | 
			
		||||
            _downstreamContext.DownstreamRequest = new DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "http://test.com"));
 | 
			
		||||
            _middleware = new ClaimsToDownstreamPathMiddleware(_next, _loggerFactory.Object, _changePath.Object);
 | 
			
		||||
        }
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamRequest(new DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "http://test.com")));
 | 
			
		||||
            _middleware = new ClaimsToDownstreamPathMiddleware(_next, _loggerFactory.Object, _changePath.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_add_queries_correctly()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamReRoute(new DownstreamReRouteBuilder()
 | 
			
		||||
                        .WithDownstreamPathTemplate("any old string")
 | 
			
		||||
                        .WithClaimsToDownstreamPath(new List<ClaimToThing>
 | 
			
		||||
                        {
 | 
			
		||||
                            new ClaimToThing("UserId", "Subject", "", 0),
 | 
			
		||||
                        })
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .Build())
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
               .And(x => x.GivenTheChangeDownstreamPathReturnsOk())
 | 
			
		||||
               .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
               .Then(x => x.ThenChangeDownstreamPathIsCalledCorrectly())
 | 
			
		||||
               .BDDfy();
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_httpContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheChangeDownstreamPathReturnsOk()
 | 
			
		||||
        {
 | 
			
		||||
            _changePath
 | 
			
		||||
                .Setup(x => x.ChangeDownstreamPath(
 | 
			
		||||
                    It.IsAny<List<ClaimToThing>>(),
 | 
			
		||||
                    It.IsAny<IEnumerable<Claim>>(),
 | 
			
		||||
                    It.IsAny<DownstreamPathTemplate>(),
 | 
			
		||||
                    It.IsAny<List<PlaceholderNameAndValue>>()))
 | 
			
		||||
                .Returns(new OkResponse());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenChangeDownstreamPathIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _changePath
 | 
			
		||||
                .Verify(x => x.ChangeDownstreamPath(
 | 
			
		||||
                    It.IsAny<List<ClaimToThing>>(),
 | 
			
		||||
                    It.IsAny<IEnumerable<Claim>>(),
 | 
			
		||||
                    _httpContext.Items.DownstreamReRoute().DownstreamPathTemplate,
 | 
			
		||||
                    _httpContext.Items.TemplatePlaceholderNameAndValues()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute)
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext.Items.UpsertTemplatePlaceholderNameAndValues(downstreamRoute.TemplatePlaceholderNameAndValues);
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_add_queries_correctly()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamReRoute(new DownstreamReRouteBuilder()
 | 
			
		||||
                        .WithDownstreamPathTemplate("any old string")
 | 
			
		||||
                        .WithClaimsToDownstreamPath(new List<ClaimToThing>
 | 
			
		||||
                        {
 | 
			
		||||
                            new ClaimToThing("UserId", "Subject", "", 0),
 | 
			
		||||
                        })
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .Build())
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
               .And(x => x.GivenTheChangeDownstreamPathReturnsOk())
 | 
			
		||||
               .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
               .Then(x => x.ThenChangeDownstreamPathIsCalledCorrectly())
 | 
			
		||||
               .BDDfy();
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheChangeDownstreamPathReturnsOk()
 | 
			
		||||
        {
 | 
			
		||||
            _changePath
 | 
			
		||||
                .Setup(x => x.ChangeDownstreamPath(
 | 
			
		||||
                    It.IsAny<List<ClaimToThing>>(),
 | 
			
		||||
                    It.IsAny<IEnumerable<Claim>>(),
 | 
			
		||||
                    It.IsAny<DownstreamPathTemplate>(),
 | 
			
		||||
                    It.IsAny<List<PlaceholderNameAndValue>>()))
 | 
			
		||||
                .Returns(new OkResponse());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenChangeDownstreamPathIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _changePath
 | 
			
		||||
                .Verify(x => x.ChangeDownstreamPath(
 | 
			
		||||
                    It.IsAny<List<ClaimToThing>>(),
 | 
			
		||||
                    It.IsAny<IEnumerable<Claim>>(),
 | 
			
		||||
                    _downstreamContext.DownstreamReRoute.DownstreamPathTemplate,
 | 
			
		||||
                    _downstreamContext.TemplatePlaceholderNameAndValues), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.TemplatePlaceholderNameAndValues = downstreamRoute.TemplatePlaceholderNameAndValues;
 | 
			
		||||
            _downstreamContext.DownstreamReRoute = downstreamRoute.ReRoute.DownstreamReRoute[0];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamReRoute(downstreamRoute.ReRoute.DownstreamReRoute[0]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -11,11 +11,12 @@
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Ocelot.Middleware.Multiplexer;
 | 
			
		||||
    using Ocelot.Multiplexer;
 | 
			
		||||
    using Ocelot.Responses;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using Ocelot.Infrastructure.RequestData;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
@@ -28,22 +29,20 @@
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private readonly DownstreamRouteFinderMiddleware _middleware;
 | 
			
		||||
        private readonly DownstreamContext _downstreamContext;
 | 
			
		||||
        private OcelotRequestDelegate _next;
 | 
			
		||||
        private readonly Mock<IMultiplexer> _multiplexer;
 | 
			
		||||
        private RequestDelegate _next;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
 | 
			
		||||
        public DownstreamRouteFinderMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
            _finder = new Mock<IDownstreamRouteProvider>();
 | 
			
		||||
            _factory = new Mock<IDownstreamRouteProviderFactory>();
 | 
			
		||||
            _factory.Setup(x => x.Get(It.IsAny<IInternalConfiguration>())).Returns(_finder.Object);
 | 
			
		||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<DownstreamRouteFinderMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _next = context => Task.CompletedTask;
 | 
			
		||||
            _multiplexer = new Mock<IMultiplexer>();
 | 
			
		||||
            _middleware = new DownstreamRouteFinderMiddleware(_next, _loggerFactory.Object, _factory.Object, _multiplexer.Object);
 | 
			
		||||
            _middleware = new DownstreamRouteFinderMiddleware(_next, _loggerFactory.Object, _factory.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
@@ -71,13 +70,13 @@
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_downstreamContext).GetAwaiter().GetType();
 | 
			
		||||
            _middleware.Invoke(_httpContext).GetAwaiter().GetType();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFollowingConfig(IInternalConfiguration config)
 | 
			
		||||
        {
 | 
			
		||||
            _config = config;
 | 
			
		||||
            _downstreamContext.Configuration = config;
 | 
			
		||||
            _httpContext.Items.SetIInternalConfiguration(config);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownStreamRouteFinderReturns(DownstreamRoute downstreamRoute)
 | 
			
		||||
@@ -90,8 +89,8 @@
 | 
			
		||||
 | 
			
		||||
        private void ThenTheScopedDataRepositoryIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.TemplatePlaceholderNameAndValues.ShouldBe(_downstreamRoute.Data.TemplatePlaceholderNameAndValues);
 | 
			
		||||
            _downstreamContext.Configuration.ServiceProviderConfiguration.ShouldBe(_config.ServiceProviderConfiguration);
 | 
			
		||||
            _httpContext.Items.TemplatePlaceholderNameAndValues().ShouldBe(_downstreamRoute.Data.TemplatePlaceholderNameAndValues);
 | 
			
		||||
            _httpContext.Items.IInternalConfiguration().ServiceProviderConfiguration.ShouldBe(_config.ServiceProviderConfiguration);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,436 +1,440 @@
 | 
			
		||||
namespace Ocelot.UnitTests.DownstreamUrlCreator
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
			
		||||
    using Ocelot.DownstreamUrlCreator.Middleware;
 | 
			
		||||
    using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Ocelot.Request.Middleware;
 | 
			
		||||
    using Ocelot.Responses;
 | 
			
		||||
    using Ocelot.Values;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
namespace Ocelot.UnitTests.DownstreamUrlCreator
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
			
		||||
    using Ocelot.DownstreamUrlCreator.Middleware;
 | 
			
		||||
    using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Ocelot.Request.Middleware;
 | 
			
		||||
    using Ocelot.Responses;
 | 
			
		||||
    using Ocelot.Values;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using Ocelot.Infrastructure.RequestData;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
 | 
			
		||||
    public class DownstreamUrlCreatorMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Mock<IDownstreamPathPlaceholderReplacer> _downstreamUrlTemplateVariableReplacer;
 | 
			
		||||
        private OkResponse<DownstreamPath> _downstreamPath;
 | 
			
		||||
        private readonly Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private DownstreamUrlCreatorMiddleware _middleware;
 | 
			
		||||
        private readonly DownstreamContext _downstreamContext;
 | 
			
		||||
        private readonly OcelotRequestDelegate _next;
 | 
			
		||||
        private readonly HttpRequestMessage _request;
 | 
			
		||||
 | 
			
		||||
        public DownstreamUrlCreatorMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<DownstreamUrlCreatorMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _downstreamUrlTemplateVariableReplacer = new Mock<IDownstreamPathPlaceholderReplacer>();
 | 
			
		||||
    public class DownstreamUrlCreatorMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Mock<IDownstreamPathPlaceholderReplacer> _downstreamUrlTemplateVariableReplacer;
 | 
			
		||||
        private OkResponse<DownstreamPath> _downstreamPath;
 | 
			
		||||
        private readonly Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private DownstreamUrlCreatorMiddleware _middleware;
 | 
			
		||||
        private readonly RequestDelegate _next;
 | 
			
		||||
        private readonly HttpRequestMessage _request;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
        private Mock<IRequestScopedDataRepository> _repo;
 | 
			
		||||
 | 
			
		||||
        public DownstreamUrlCreatorMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _repo = new Mock<IRequestScopedDataRepository>();
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<DownstreamUrlCreatorMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _downstreamUrlTemplateVariableReplacer = new Mock<IDownstreamPathPlaceholderReplacer>();
 | 
			
		||||
            _request = new HttpRequestMessage(HttpMethod.Get, "https://my.url/abc/?q=123");
 | 
			
		||||
            _downstreamContext.DownstreamRequest = new DownstreamRequest(_request);
 | 
			
		||||
            _next = context => Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_replace_scheme_and_path()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamReRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithDownstreamPathTemplate("any old string")
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                .WithDownstreamScheme("https")
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var config = new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(
 | 
			
		||||
                    new DownstreamRoute(
 | 
			
		||||
                    new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                    new ReRouteBuilder()
 | 
			
		||||
                        .WithDownstreamReRoute(downstreamReRoute)
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .Build())))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRequestUriIs("http://my.url/abc?q=123"))
 | 
			
		||||
                .And(x => GivenTheServiceProviderConfigIs(config))
 | 
			
		||||
                .And(x => x.GivenTheUrlReplacerWillReturn("/api/products/1"))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheDownstreamRequestUriIs("https://my.url:80/api/products/1?q=123"))
 | 
			
		||||
                .And(x => ThenTheQueryStringIs("?q=123"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_replace_query_string()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamReRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithDownstreamPathTemplate("/api/units/{subscriptionId}/{unitId}/updates")
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                .WithDownstreamScheme("https")
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var config = new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(
 | 
			
		||||
                    new DownstreamRoute(
 | 
			
		||||
                        new List<PlaceholderNameAndValue>
 | 
			
		||||
                        {
 | 
			
		||||
                            new PlaceholderNameAndValue("{subscriptionId}", "1"),
 | 
			
		||||
                            new PlaceholderNameAndValue("{unitId}", "2")
 | 
			
		||||
                        },
 | 
			
		||||
                        new ReRouteBuilder()
 | 
			
		||||
                            .WithDownstreamReRoute(downstreamReRoute)
 | 
			
		||||
                            .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                            .Build())))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:5000/api/subscriptions/1/updates?unitId=2"))
 | 
			
		||||
                .And(x => GivenTheServiceProviderConfigIs(config))
 | 
			
		||||
                .And(x => x.GivenTheUrlReplacerWillReturn("api/units/1/2/updates"))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheDownstreamRequestUriIs("https://localhost:5000/api/units/1/2/updates"))
 | 
			
		||||
                .And(x => ThenTheQueryStringIs(""))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_replace_query_string_but_leave_non_placeholder_queries()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamReRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithDownstreamPathTemplate("/api/units/{subscriptionId}/{unitId}/updates")
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                .WithDownstreamScheme("https")
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var config = new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(
 | 
			
		||||
                    new DownstreamRoute(
 | 
			
		||||
                        new List<PlaceholderNameAndValue>
 | 
			
		||||
                        {
 | 
			
		||||
                            new PlaceholderNameAndValue("{subscriptionId}", "1"),
 | 
			
		||||
                            new PlaceholderNameAndValue("{unitId}", "2")
 | 
			
		||||
                        },
 | 
			
		||||
                        new ReRouteBuilder()
 | 
			
		||||
                            .WithDownstreamReRoute(downstreamReRoute)
 | 
			
		||||
                            .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                            .Build())))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:5000/api/subscriptions/1/updates?unitId=2&productId=2"))
 | 
			
		||||
                .And(x => GivenTheServiceProviderConfigIs(config))
 | 
			
		||||
                .And(x => x.GivenTheUrlReplacerWillReturn("api/units/1/2/updates"))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheDownstreamRequestUriIs("https://localhost:5000/api/units/1/2/updates?productId=2"))
 | 
			
		||||
                .And(x => ThenTheQueryStringIs("?productId=2"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_replace_query_string_exact_match()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamReRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithDownstreamPathTemplate("/api/units/{subscriptionId}/{unitId}/updates/{unitIdIty}")
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                .WithDownstreamScheme("https")
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var config = new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(
 | 
			
		||||
                    new DownstreamRoute(
 | 
			
		||||
                        new List<PlaceholderNameAndValue>
 | 
			
		||||
                        {
 | 
			
		||||
                            new PlaceholderNameAndValue("{subscriptionId}", "1"),
 | 
			
		||||
                            new PlaceholderNameAndValue("{unitId}", "2"),
 | 
			
		||||
                            new PlaceholderNameAndValue("{unitIdIty}", "3")
 | 
			
		||||
                        },
 | 
			
		||||
                        new ReRouteBuilder()
 | 
			
		||||
                            .WithDownstreamReRoute(downstreamReRoute)
 | 
			
		||||
                            .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                            .Build())))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:5000/api/subscriptions/1/updates?unitId=2?unitIdIty=3"))
 | 
			
		||||
                .And(x => GivenTheServiceProviderConfigIs(config))
 | 
			
		||||
                .And(x => x.GivenTheUrlReplacerWillReturn("api/units/1/2/updates/3"))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheDownstreamRequestUriIs("https://localhost:5000/api/units/1/2/updates/3"))
 | 
			
		||||
                .And(x => ThenTheQueryStringIs(""))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_create_service_fabric_url()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamReRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithDownstreamPathTemplate("any old string")
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                .WithDownstreamScheme("https")
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var config = new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                .WithType("ServiceFabric")
 | 
			
		||||
                .WithHost("localhost")
 | 
			
		||||
                .WithPort(19081)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(
 | 
			
		||||
                    new DownstreamRoute(
 | 
			
		||||
                        new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                        new ReRouteBuilder()
 | 
			
		||||
                            .WithDownstreamReRoute(downstreamReRoute)
 | 
			
		||||
                            .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                            .Build())))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRequestUriIs("http://my.url/abc?q=123"))
 | 
			
		||||
                .And(x => GivenTheServiceProviderConfigIs(config))
 | 
			
		||||
                .And(x => x.GivenTheUrlReplacerWillReturn("/api/products/1"))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheDownstreamRequestUriIs("https://my.url:80/api/products/1?q=123"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_create_service_fabric_url()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamReRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithDownstreamScheme("http")
 | 
			
		||||
                .WithServiceName("Ocelot/OcelotApp")
 | 
			
		||||
                .WithUseServiceDiscovery(true)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(
 | 
			
		||||
                new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamReRoute(downstreamReRoute)
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            var config = new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                .WithType("ServiceFabric")
 | 
			
		||||
                .WithHost("localhost")
 | 
			
		||||
                .WithPort(19081)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
                .And(x => GivenTheServiceProviderConfigIs(config))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:19081"))
 | 
			
		||||
                .And(x => x.GivenTheUrlReplacerWillReturnSequence("/api/products/1", "Ocelot/OcelotApp"))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheDownstreamRequestUriIs("http://localhost:19081/Ocelot/OcelotApp/api/products/1"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_create_service_fabric_url_with_query_string_for_stateless_service()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamReRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithDownstreamScheme("http")
 | 
			
		||||
                .WithServiceName("Ocelot/OcelotApp")
 | 
			
		||||
                .WithUseServiceDiscovery(true)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(
 | 
			
		||||
                new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamReRoute(downstreamReRoute)
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            var config = new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                .WithType("ServiceFabric")
 | 
			
		||||
                .WithHost("localhost")
 | 
			
		||||
                .WithPort(19081)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
                .And(x => GivenTheServiceProviderConfigIs(config))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:19081?Tom=test&laura=1"))
 | 
			
		||||
                .And(x => x.GivenTheUrlReplacerWillReturnSequence("/api/products/1", "Ocelot/OcelotApp"))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheDownstreamRequestUriIs("http://localhost:19081/Ocelot/OcelotApp/api/products/1?Tom=test&laura=1"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_create_service_fabric_url_with_query_string_for_stateful_service()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamReRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithDownstreamScheme("http")
 | 
			
		||||
                .WithServiceName("Ocelot/OcelotApp")
 | 
			
		||||
                .WithUseServiceDiscovery(true)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(
 | 
			
		||||
                new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamReRoute(downstreamReRoute)
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            var config = new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                .WithType("ServiceFabric")
 | 
			
		||||
                .WithHost("localhost")
 | 
			
		||||
                .WithPort(19081)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
                .And(x => GivenTheServiceProviderConfigIs(config))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:19081?PartitionKind=test&PartitionKey=1"))
 | 
			
		||||
                .And(x => x.GivenTheUrlReplacerWillReturnSequence("/api/products/1", "Ocelot/OcelotApp"))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheDownstreamRequestUriIs("http://localhost:19081/Ocelot/OcelotApp/api/products/1?PartitionKind=test&PartitionKey=1"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_create_service_fabric_url_with_version_from_upstream_path_template()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(
 | 
			
		||||
                new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder().WithDownstreamReRoute(
 | 
			
		||||
                        new DownstreamReRouteBuilder()
 | 
			
		||||
                            .WithDownstreamScheme("http")
 | 
			
		||||
                            .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("/products").Build())
 | 
			
		||||
                            .WithUseServiceDiscovery(true)
 | 
			
		||||
                            .Build()
 | 
			
		||||
                    ).Build());
 | 
			
		||||
 | 
			
		||||
            var config = new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                .WithType("ServiceFabric")
 | 
			
		||||
                .WithHost("localhost")
 | 
			
		||||
                .WithPort(19081)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
                .And(x => GivenTheServiceProviderConfigIs(config))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:19081?PartitionKind=test&PartitionKey=1"))
 | 
			
		||||
                .And(x => x.GivenTheUrlReplacerWillReturnSequence("/products", "Service_1.0/Api"))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheDownstreamRequestUriIs("http://localhost:19081/Service_1.0/Api/products?PartitionKind=test&PartitionKey=1"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void issue_473_should_not_remove_additional_query_string()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamReRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithDownstreamPathTemplate("/Authorized/{action}?server={server}")
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Post", "Get" })
 | 
			
		||||
                .WithDownstreamScheme("http")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("/uc/Authorized/{server}/{action}").Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var config = new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(
 | 
			
		||||
                    new DownstreamRoute(
 | 
			
		||||
                        new List<PlaceholderNameAndValue>
 | 
			
		||||
                        {
 | 
			
		||||
                            new PlaceholderNameAndValue("{action}", "1"),
 | 
			
		||||
                            new PlaceholderNameAndValue("{server}", "2")
 | 
			
		||||
                        },
 | 
			
		||||
                        new ReRouteBuilder()
 | 
			
		||||
                            .WithDownstreamReRoute(downstreamReRoute)
 | 
			
		||||
                            .WithUpstreamHttpMethod(new List<string> { "Post", "Get" })
 | 
			
		||||
                            .Build())))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:5000/uc/Authorized/2/1/refresh?refreshToken=2288356cfb1338fdc5ff4ca558ec785118dfe1ff2864340937da8226863ff66d"))
 | 
			
		||||
                .And(x => GivenTheServiceProviderConfigIs(config))
 | 
			
		||||
                .And(x => x.GivenTheUrlReplacerWillReturn("/Authorized/1?server=2"))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheDownstreamRequestUriIs("http://localhost:5000/Authorized/1?refreshToken=2288356cfb1338fdc5ff4ca558ec785118dfe1ff2864340937da8226863ff66d&server=2"))
 | 
			
		||||
                .And(x => ThenTheQueryStringIs("?refreshToken=2288356cfb1338fdc5ff4ca558ec785118dfe1ff2864340937da8226863ff66d&server=2"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_replace_by_empty_scheme()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamReRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithDownstreamScheme("")
 | 
			
		||||
                .WithServiceName("Ocelot/OcelotApp")
 | 
			
		||||
                .WithUseServiceDiscovery(true)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(
 | 
			
		||||
                new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamReRoute(downstreamReRoute)
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            var config = new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                .WithType("ServiceFabric")
 | 
			
		||||
                .WithHost("localhost")
 | 
			
		||||
                .WithPort(19081)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
                .And(x => GivenTheServiceProviderConfigIs(config))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRequestUriIs("https://localhost:19081?PartitionKind=test&PartitionKey=1"))
 | 
			
		||||
                .And(x => x.GivenTheUrlReplacerWillReturnSequence("/api/products/1", "Ocelot/OcelotApp"))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheDownstreamRequestUriIs("https://localhost:19081/Ocelot/OcelotApp/api/products/1?PartitionKind=test&PartitionKey=1"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheServiceProviderConfigIs(ServiceProviderConfiguration config)
 | 
			
		||||
        {
 | 
			
		||||
            _next = context => Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_replace_scheme_and_path()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamReRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithDownstreamPathTemplate("any old string")
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                .WithDownstreamScheme("https")
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var config = new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(
 | 
			
		||||
                    new DownstreamRoute(
 | 
			
		||||
                    new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                    new ReRouteBuilder()
 | 
			
		||||
                        .WithDownstreamReRoute(downstreamReRoute)
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .Build())))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRequestUriIs("http://my.url/abc?q=123"))
 | 
			
		||||
                .And(x => GivenTheServiceProviderConfigIs(config))
 | 
			
		||||
                .And(x => x.GivenTheUrlReplacerWillReturn("/api/products/1"))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheDownstreamRequestUriIs("https://my.url:80/api/products/1?q=123"))
 | 
			
		||||
                .And(x => ThenTheQueryStringIs("?q=123"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_replace_query_string()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamReRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithDownstreamPathTemplate("/api/units/{subscriptionId}/{unitId}/updates")
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                .WithDownstreamScheme("https")
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var config = new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(
 | 
			
		||||
                    new DownstreamRoute(
 | 
			
		||||
                        new List<PlaceholderNameAndValue>
 | 
			
		||||
                        {
 | 
			
		||||
                            new PlaceholderNameAndValue("{subscriptionId}", "1"),
 | 
			
		||||
                            new PlaceholderNameAndValue("{unitId}", "2")
 | 
			
		||||
                        },
 | 
			
		||||
                        new ReRouteBuilder()
 | 
			
		||||
                            .WithDownstreamReRoute(downstreamReRoute)
 | 
			
		||||
                            .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                            .Build())))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:5000/api/subscriptions/1/updates?unitId=2"))
 | 
			
		||||
                .And(x => GivenTheServiceProviderConfigIs(config))
 | 
			
		||||
                .And(x => x.GivenTheUrlReplacerWillReturn("api/units/1/2/updates"))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheDownstreamRequestUriIs("https://localhost:5000/api/units/1/2/updates"))
 | 
			
		||||
                .And(x => ThenTheQueryStringIs(""))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_replace_query_string_but_leave_non_placeholder_queries()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamReRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithDownstreamPathTemplate("/api/units/{subscriptionId}/{unitId}/updates")
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                .WithDownstreamScheme("https")
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var config = new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(
 | 
			
		||||
                    new DownstreamRoute(
 | 
			
		||||
                        new List<PlaceholderNameAndValue>
 | 
			
		||||
                        {
 | 
			
		||||
                            new PlaceholderNameAndValue("{subscriptionId}", "1"),
 | 
			
		||||
                            new PlaceholderNameAndValue("{unitId}", "2")
 | 
			
		||||
                        },
 | 
			
		||||
                        new ReRouteBuilder()
 | 
			
		||||
                            .WithDownstreamReRoute(downstreamReRoute)
 | 
			
		||||
                            .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                            .Build())))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:5000/api/subscriptions/1/updates?unitId=2&productId=2"))
 | 
			
		||||
                .And(x => GivenTheServiceProviderConfigIs(config))
 | 
			
		||||
                .And(x => x.GivenTheUrlReplacerWillReturn("api/units/1/2/updates"))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheDownstreamRequestUriIs("https://localhost:5000/api/units/1/2/updates?productId=2"))
 | 
			
		||||
                .And(x => ThenTheQueryStringIs("?productId=2"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_replace_query_string_exact_match()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamReRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithDownstreamPathTemplate("/api/units/{subscriptionId}/{unitId}/updates/{unitIdIty}")
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                .WithDownstreamScheme("https")
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var config = new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(
 | 
			
		||||
                    new DownstreamRoute(
 | 
			
		||||
                        new List<PlaceholderNameAndValue>
 | 
			
		||||
                        {
 | 
			
		||||
                            new PlaceholderNameAndValue("{subscriptionId}", "1"),
 | 
			
		||||
                            new PlaceholderNameAndValue("{unitId}", "2"),
 | 
			
		||||
                            new PlaceholderNameAndValue("{unitIdIty}", "3")
 | 
			
		||||
                        },
 | 
			
		||||
                        new ReRouteBuilder()
 | 
			
		||||
                            .WithDownstreamReRoute(downstreamReRoute)
 | 
			
		||||
                            .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                            .Build())))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:5000/api/subscriptions/1/updates?unitId=2?unitIdIty=3"))
 | 
			
		||||
                .And(x => GivenTheServiceProviderConfigIs(config))
 | 
			
		||||
                .And(x => x.GivenTheUrlReplacerWillReturn("api/units/1/2/updates/3"))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheDownstreamRequestUriIs("https://localhost:5000/api/units/1/2/updates/3"))
 | 
			
		||||
                .And(x => ThenTheQueryStringIs(""))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_create_service_fabric_url()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamReRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithDownstreamPathTemplate("any old string")
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                .WithDownstreamScheme("https")
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var config = new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                .WithType("ServiceFabric")
 | 
			
		||||
                .WithHost("localhost")
 | 
			
		||||
                .WithPort(19081)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(
 | 
			
		||||
                    new DownstreamRoute(
 | 
			
		||||
                        new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                        new ReRouteBuilder()
 | 
			
		||||
                            .WithDownstreamReRoute(downstreamReRoute)
 | 
			
		||||
                            .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                            .Build())))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRequestUriIs("http://my.url/abc?q=123"))
 | 
			
		||||
                .And(x => GivenTheServiceProviderConfigIs(config))
 | 
			
		||||
                .And(x => x.GivenTheUrlReplacerWillReturn("/api/products/1"))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheDownstreamRequestUriIs("https://my.url:80/api/products/1?q=123"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_create_service_fabric_url()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamReRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithDownstreamScheme("http")
 | 
			
		||||
                .WithServiceName("Ocelot/OcelotApp")
 | 
			
		||||
                .WithUseServiceDiscovery(true)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(
 | 
			
		||||
                new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamReRoute(downstreamReRoute)
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            var config = new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                .WithType("ServiceFabric")
 | 
			
		||||
                .WithHost("localhost")
 | 
			
		||||
                .WithPort(19081)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
                .And(x => GivenTheServiceProviderConfigIs(config))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:19081"))
 | 
			
		||||
                .And(x => x.GivenTheUrlReplacerWillReturnSequence("/api/products/1", "Ocelot/OcelotApp"))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheDownstreamRequestUriIs("http://localhost:19081/Ocelot/OcelotApp/api/products/1"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_create_service_fabric_url_with_query_string_for_stateless_service()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamReRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithDownstreamScheme("http")
 | 
			
		||||
                .WithServiceName("Ocelot/OcelotApp")
 | 
			
		||||
                .WithUseServiceDiscovery(true)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(
 | 
			
		||||
                new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamReRoute(downstreamReRoute)
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            var config = new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                .WithType("ServiceFabric")
 | 
			
		||||
                .WithHost("localhost")
 | 
			
		||||
                .WithPort(19081)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
                .And(x => GivenTheServiceProviderConfigIs(config))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:19081?Tom=test&laura=1"))
 | 
			
		||||
                .And(x => x.GivenTheUrlReplacerWillReturnSequence("/api/products/1", "Ocelot/OcelotApp"))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheDownstreamRequestUriIs("http://localhost:19081/Ocelot/OcelotApp/api/products/1?Tom=test&laura=1"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_create_service_fabric_url_with_query_string_for_stateful_service()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamReRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithDownstreamScheme("http")
 | 
			
		||||
                .WithServiceName("Ocelot/OcelotApp")
 | 
			
		||||
                .WithUseServiceDiscovery(true)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(
 | 
			
		||||
                new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamReRoute(downstreamReRoute)
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            var config = new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                .WithType("ServiceFabric")
 | 
			
		||||
                .WithHost("localhost")
 | 
			
		||||
                .WithPort(19081)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
                .And(x => GivenTheServiceProviderConfigIs(config))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:19081?PartitionKind=test&PartitionKey=1"))
 | 
			
		||||
                .And(x => x.GivenTheUrlReplacerWillReturnSequence("/api/products/1", "Ocelot/OcelotApp"))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheDownstreamRequestUriIs("http://localhost:19081/Ocelot/OcelotApp/api/products/1?PartitionKind=test&PartitionKey=1"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_create_service_fabric_url_with_version_from_upstream_path_template()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(
 | 
			
		||||
                new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder().WithDownstreamReRoute(
 | 
			
		||||
                        new DownstreamReRouteBuilder()
 | 
			
		||||
                            .WithDownstreamScheme("http")
 | 
			
		||||
                            .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("/products").Build())
 | 
			
		||||
                            .WithUseServiceDiscovery(true)
 | 
			
		||||
                            .Build()
 | 
			
		||||
                    ).Build());
 | 
			
		||||
 | 
			
		||||
            var config = new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                .WithType("ServiceFabric")
 | 
			
		||||
                .WithHost("localhost")
 | 
			
		||||
                .WithPort(19081)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
                .And(x => GivenTheServiceProviderConfigIs(config))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:19081?PartitionKind=test&PartitionKey=1"))
 | 
			
		||||
                .And(x => x.GivenTheUrlReplacerWillReturnSequence("/products", "Service_1.0/Api"))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheDownstreamRequestUriIs("http://localhost:19081/Service_1.0/Api/products?PartitionKind=test&PartitionKey=1"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void issue_473_should_not_remove_additional_query_string()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamReRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithDownstreamPathTemplate("/Authorized/{action}?server={server}")
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Post", "Get" })
 | 
			
		||||
                .WithDownstreamScheme("http")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("/uc/Authorized/{server}/{action}").Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var config = new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(
 | 
			
		||||
                    new DownstreamRoute(
 | 
			
		||||
                        new List<PlaceholderNameAndValue>
 | 
			
		||||
                        {
 | 
			
		||||
                            new PlaceholderNameAndValue("{action}", "1"),
 | 
			
		||||
                            new PlaceholderNameAndValue("{server}", "2")
 | 
			
		||||
                        },
 | 
			
		||||
                        new ReRouteBuilder()
 | 
			
		||||
                            .WithDownstreamReRoute(downstreamReRoute)
 | 
			
		||||
                            .WithUpstreamHttpMethod(new List<string> { "Post", "Get" })
 | 
			
		||||
                            .Build())))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:5000/uc/Authorized/2/1/refresh?refreshToken=2288356cfb1338fdc5ff4ca558ec785118dfe1ff2864340937da8226863ff66d"))
 | 
			
		||||
                .And(x => GivenTheServiceProviderConfigIs(config))
 | 
			
		||||
                .And(x => x.GivenTheUrlReplacerWillReturn("/Authorized/1?server=2"))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheDownstreamRequestUriIs("http://localhost:5000/Authorized/1?refreshToken=2288356cfb1338fdc5ff4ca558ec785118dfe1ff2864340937da8226863ff66d&server=2"))
 | 
			
		||||
                .And(x => ThenTheQueryStringIs("?refreshToken=2288356cfb1338fdc5ff4ca558ec785118dfe1ff2864340937da8226863ff66d&server=2"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_replace_by_empty_scheme()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamReRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithDownstreamScheme("")
 | 
			
		||||
                .WithServiceName("Ocelot/OcelotApp")
 | 
			
		||||
                .WithUseServiceDiscovery(true)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(
 | 
			
		||||
                new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamReRoute(downstreamReRoute)
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            var config = new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                .WithType("ServiceFabric")
 | 
			
		||||
                .WithHost("localhost")
 | 
			
		||||
                .WithPort(19081)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
                .And(x => GivenTheServiceProviderConfigIs(config))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRequestUriIs("https://localhost:19081?PartitionKind=test&PartitionKey=1"))
 | 
			
		||||
                .And(x => x.GivenTheUrlReplacerWillReturnSequence("/api/products/1", "Ocelot/OcelotApp"))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheDownstreamRequestUriIs("https://localhost:19081/Ocelot/OcelotApp/api/products/1?PartitionKind=test&PartitionKey=1"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheServiceProviderConfigIs(ServiceProviderConfiguration config)
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new InternalConfiguration(null, null, config, null, null, null, null, null, null);
 | 
			
		||||
            _downstreamContext.Configuration = configuration;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
            _httpContext.Items.SetIInternalConfiguration(configuration);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware = new DownstreamUrlCreatorMiddleware(_next, _loggerFactory.Object, _downstreamUrlTemplateVariableReplacer.Object);
 | 
			
		||||
            _middleware.Invoke(_httpContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute)
 | 
			
		||||
        {
 | 
			
		||||
            _middleware = new DownstreamUrlCreatorMiddleware(_next, _loggerFactory.Object, _downstreamUrlTemplateVariableReplacer.Object);
 | 
			
		||||
            _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
            _httpContext.Items.UpsertTemplatePlaceholderNameAndValues(downstreamRoute.TemplatePlaceholderNameAndValues);
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.TemplatePlaceholderNameAndValues = downstreamRoute.TemplatePlaceholderNameAndValues;
 | 
			
		||||
            _downstreamContext.DownstreamReRoute = downstreamRoute.ReRoute.DownstreamReRoute[0];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownstreamRequestUriIs(string uri)
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamReRoute(downstreamRoute.ReRoute.DownstreamReRoute[0]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownstreamRequestUriIs(string uri)
 | 
			
		||||
        {
 | 
			
		||||
            _request.RequestUri = new Uri(uri);
 | 
			
		||||
            _downstreamContext.DownstreamRequest = new DownstreamRequest(_request);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheUrlReplacerWillReturnSequence(params string[] paths)
 | 
			
		||||
        {
 | 
			
		||||
            var setup = _downstreamUrlTemplateVariableReplacer
 | 
			
		||||
                .SetupSequence(x => x.Replace(It.IsAny<string>(), It.IsAny<List<PlaceholderNameAndValue>>()));
 | 
			
		||||
            foreach (var path in paths)
 | 
			
		||||
            {
 | 
			
		||||
                var response = new OkResponse<DownstreamPath>(new DownstreamPath(path));
 | 
			
		||||
                setup.Returns(response);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheUrlReplacerWillReturn(string path)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamPath = new OkResponse<DownstreamPath>(new DownstreamPath(path));
 | 
			
		||||
            _downstreamUrlTemplateVariableReplacer
 | 
			
		||||
                .Setup(x => x.Replace(It.IsAny<string>(), It.IsAny<List<PlaceholderNameAndValue>>()))
 | 
			
		||||
                .Returns(_downstreamPath);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheDownstreamRequestUriIs(string expectedUri)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.DownstreamRequest.ToHttpRequestMessage().RequestUri.OriginalString.ShouldBe(expectedUri);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheQueryStringIs(string queryString)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.DownstreamRequest.Query.ShouldBe(queryString);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamRequest(new DownstreamRequest(_request));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheUrlReplacerWillReturnSequence(params string[] paths)
 | 
			
		||||
        {
 | 
			
		||||
            var setup = _downstreamUrlTemplateVariableReplacer
 | 
			
		||||
                .SetupSequence(x => x.Replace(It.IsAny<string>(), It.IsAny<List<PlaceholderNameAndValue>>()));
 | 
			
		||||
            foreach (var path in paths)
 | 
			
		||||
            {
 | 
			
		||||
                var response = new OkResponse<DownstreamPath>(new DownstreamPath(path));
 | 
			
		||||
                setup.Returns(response);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheUrlReplacerWillReturn(string path)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamPath = new OkResponse<DownstreamPath>(new DownstreamPath(path));
 | 
			
		||||
            _downstreamUrlTemplateVariableReplacer
 | 
			
		||||
                .Setup(x => x.Replace(It.IsAny<string>(), It.IsAny<List<PlaceholderNameAndValue>>()))
 | 
			
		||||
                .Returns(_downstreamPath);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheDownstreamRequestUriIs(string expectedUri)
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext.Items.DownstreamRequest().ToHttpRequestMessage().RequestUri.OriginalString.ShouldBe(expectedUri);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheQueryStringIs(string queryString)
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext.Items.DownstreamRequest().Query.ShouldBe(queryString);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,14 +3,13 @@ namespace Ocelot.UnitTests.Errors
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Repository;
 | 
			
		||||
    using Ocelot.Errors;
 | 
			
		||||
    using Ocelot.Errors.Middleware;
 | 
			
		||||
    using Ocelot.Infrastructure.RequestData;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Net;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
@@ -19,19 +18,17 @@ namespace Ocelot.UnitTests.Errors
 | 
			
		||||
    public class ExceptionHandlerMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private bool _shouldThrowAnException;
 | 
			
		||||
        private readonly Mock<IInternalConfigurationRepository> _configRepo;
 | 
			
		||||
        private readonly Mock<IRequestScopedDataRepository> _repo;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private readonly ExceptionHandlerMiddleware _middleware;
 | 
			
		||||
        private readonly DownstreamContext _downstreamContext;
 | 
			
		||||
        private OcelotRequestDelegate _next;
 | 
			
		||||
        private RequestDelegate _next;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
 | 
			
		||||
        public ExceptionHandlerMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _configRepo = new Mock<IInternalConfigurationRepository>();
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
            _repo = new Mock<IRequestScopedDataRepository>();
 | 
			
		||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<ExceptionHandlerMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
@@ -44,9 +41,10 @@ namespace Ocelot.UnitTests.Errors
 | 
			
		||||
                    throw new Exception("BOOM");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                context.HttpContext.Response.StatusCode = (int)HttpStatusCode.OK;
 | 
			
		||||
                _httpContext.Response.StatusCode = (int)HttpStatusCode.OK;
 | 
			
		||||
            };
 | 
			
		||||
            _middleware = new ExceptionHandlerMiddleware(_next, _loggerFactory.Object, _configRepo.Object, _repo.Object);
 | 
			
		||||
 | 
			
		||||
            _middleware = new ExceptionHandlerMiddleware(_next, _loggerFactory.Object, _repo.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
@@ -100,16 +98,6 @@ namespace Ocelot.UnitTests.Errors
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_throw_exception_if_config_provider_returns_error()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream())
 | 
			
		||||
               .And(_ => GivenTheConfigReturnsError())
 | 
			
		||||
               .When(_ => WhenICallTheMiddlewareWithTheRequestIdKey("requestidkey", "1234"))
 | 
			
		||||
               .Then(_ => ThenAnExceptionIsThrown())
 | 
			
		||||
               .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_throw_exception_if_config_provider_throws()
 | 
			
		||||
        {
 | 
			
		||||
@@ -122,32 +110,25 @@ namespace Ocelot.UnitTests.Errors
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddlewareWithTheRequestIdKey(string key, string value)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.HttpContext.Request.Headers.Add(key, value);
 | 
			
		||||
            _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
 | 
			
		||||
            _httpContext.Request.Headers.Add(key, value);
 | 
			
		||||
            //_httpContext.Setup(x => x.Request.Headers).Returns(new HeaderDictionary() { { key, value } });
 | 
			
		||||
            _middleware.Invoke(_httpContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
 | 
			
		||||
            _middleware.Invoke(_httpContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheConfigThrows()
 | 
			
		||||
        {
 | 
			
		||||
            var ex = new Exception("outer", new Exception("inner"));
 | 
			
		||||
            _configRepo
 | 
			
		||||
               .Setup(x => x.Get()).Throws(ex);
 | 
			
		||||
            // this will break when we handle not having the configuratio in the items dictionary
 | 
			
		||||
            _httpContext.Items = new Dictionary<object, object>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenAnExceptionIsThrown()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.HttpContext.Response.StatusCode.ShouldBe(500);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheConfigReturnsError()
 | 
			
		||||
        {
 | 
			
		||||
            var response = new Responses.ErrorResponse<IInternalConfiguration>(new FakeError());
 | 
			
		||||
            _configRepo
 | 
			
		||||
                .Setup(x => x.Get()).Returns(response);
 | 
			
		||||
            _httpContext.Response.StatusCode.ShouldBe(500);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void TheRequestIdIsSet(string key, string value)
 | 
			
		||||
@@ -157,9 +138,7 @@ namespace Ocelot.UnitTests.Errors
 | 
			
		||||
 | 
			
		||||
        private void GivenTheConfigurationIs(IInternalConfiguration config)
 | 
			
		||||
        {
 | 
			
		||||
            var response = new Responses.OkResponse<IInternalConfiguration>(config);
 | 
			
		||||
            _configRepo
 | 
			
		||||
                .Setup(x => x.Get()).Returns(response);
 | 
			
		||||
            _httpContext.Items.Add("IInternalConfiguration", config);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenAnExceptionWillNotBeThrownDownstream()
 | 
			
		||||
@@ -174,12 +153,12 @@ namespace Ocelot.UnitTests.Errors
 | 
			
		||||
 | 
			
		||||
        private void ThenTheResponseIsOk()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.HttpContext.Response.StatusCode.ShouldBe(200);
 | 
			
		||||
            _httpContext.Response.StatusCode.ShouldBe(200);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheResponseIsError()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.HttpContext.Response.StatusCode.ShouldBe(500);
 | 
			
		||||
            _httpContext.Response.StatusCode.ShouldBe(500);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void TheAspDotnetRequestIdIsSet()
 | 
			
		||||
@@ -190,7 +169,7 @@ namespace Ocelot.UnitTests.Errors
 | 
			
		||||
        private class FakeError : Error
 | 
			
		||||
        {
 | 
			
		||||
            internal FakeError()
 | 
			
		||||
                : base("meh", OcelotErrorCode.CannotAddDataError)
 | 
			
		||||
                : base("meh", OcelotErrorCode.CannotAddDataError, 404)
 | 
			
		||||
            {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,59 +1,59 @@
 | 
			
		||||
namespace Ocelot.UnitTests.Eureka
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.Extensions.Configuration;
 | 
			
		||||
    using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
    using Ocelot.DependencyInjection;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Ocelot.Middleware.Pipeline;
 | 
			
		||||
    using Steeltoe.Discovery.Client;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using Steeltoe.Common.Discovery;
 | 
			
		||||
    using Steeltoe.Discovery.Eureka;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
//namespace Ocelot.UnitTests.Eureka
 | 
			
		||||
//{
 | 
			
		||||
//    using Microsoft.Extensions.Configuration;
 | 
			
		||||
//    using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
//    using Ocelot.DependencyInjection;
 | 
			
		||||
//    using Ocelot.Middleware;
 | 
			
		||||
//    using Ocelot.Middleware.Pipeline;
 | 
			
		||||
//    using Steeltoe.Discovery.Client;
 | 
			
		||||
//    using Shouldly;
 | 
			
		||||
//    using Steeltoe.Common.Discovery;
 | 
			
		||||
//    using Steeltoe.Discovery.Eureka;
 | 
			
		||||
//    using TestStack.BDDfy;
 | 
			
		||||
//    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class OcelotPipelineExtensionsTests
 | 
			
		||||
    {
 | 
			
		||||
        private OcelotPipelineBuilder _builder;
 | 
			
		||||
        private OcelotRequestDelegate _handlers;
 | 
			
		||||
//    public class OcelotPipelineExtensionsTests
 | 
			
		||||
//    {
 | 
			
		||||
//        private OcelotPipelineBuilder _builder;
 | 
			
		||||
//        private OcelotRequestDelegate _handlers;
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_set_up_pipeline()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(_ => GivenTheDepedenciesAreSetUp())
 | 
			
		||||
                 .When(_ => WhenIBuild())
 | 
			
		||||
                 .Then(_ => ThenThePipelineIsBuilt())
 | 
			
		||||
                 .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
//        [Fact]
 | 
			
		||||
//        public void should_set_up_pipeline()
 | 
			
		||||
//        {
 | 
			
		||||
//            this.Given(_ => GivenTheDepedenciesAreSetUp())
 | 
			
		||||
//                 .When(_ => WhenIBuild())
 | 
			
		||||
//                 .Then(_ => ThenThePipelineIsBuilt())
 | 
			
		||||
//                 .BDDfy();
 | 
			
		||||
//        }
 | 
			
		||||
 | 
			
		||||
        private void ThenThePipelineIsBuilt()
 | 
			
		||||
        {
 | 
			
		||||
            _handlers.ShouldNotBeNull();
 | 
			
		||||
        }
 | 
			
		||||
//        private void ThenThePipelineIsBuilt()
 | 
			
		||||
//        {
 | 
			
		||||
//            _handlers.ShouldNotBeNull();
 | 
			
		||||
//        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIBuild()
 | 
			
		||||
        {
 | 
			
		||||
            _handlers = _builder.BuildOcelotPipeline(new OcelotPipelineConfiguration());
 | 
			
		||||
        }
 | 
			
		||||
//        private void WhenIBuild()
 | 
			
		||||
//        {
 | 
			
		||||
//            _handlers = _builder.BuildOcelotPipeline(new OcelotPipelineConfiguration());
 | 
			
		||||
//        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDepedenciesAreSetUp()
 | 
			
		||||
        {
 | 
			
		||||
            IConfigurationBuilder test = new ConfigurationBuilder();
 | 
			
		||||
            var root = test.Build();
 | 
			
		||||
            var services = new ServiceCollection();
 | 
			
		||||
            services.AddSingleton<IConfiguration>(root);
 | 
			
		||||
            services.AddDiscoveryClient(new DiscoveryOptions
 | 
			
		||||
            {
 | 
			
		||||
                ClientType = DiscoveryClientType.EUREKA,
 | 
			
		||||
                ClientOptions = new EurekaClientOptions()
 | 
			
		||||
                {
 | 
			
		||||
                    ShouldFetchRegistry = false,
 | 
			
		||||
                    ShouldRegisterWithEureka = false
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            services.AddOcelot();
 | 
			
		||||
            var provider = services.BuildServiceProvider();
 | 
			
		||||
            _builder = new OcelotPipelineBuilder(provider);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
//        private void GivenTheDepedenciesAreSetUp()
 | 
			
		||||
//        {
 | 
			
		||||
//            IConfigurationBuilder test = new ConfigurationBuilder();
 | 
			
		||||
//            var root = test.Build();
 | 
			
		||||
//            var services = new ServiceCollection();
 | 
			
		||||
//            services.AddSingleton<IConfiguration>(root);
 | 
			
		||||
//            services.AddDiscoveryClient(new DiscoveryOptions
 | 
			
		||||
//            {
 | 
			
		||||
//                ClientType = DiscoveryClientType.EUREKA,
 | 
			
		||||
//                ClientOptions = new EurekaClientOptions()
 | 
			
		||||
//                {
 | 
			
		||||
//                    ShouldFetchRegistry = false,
 | 
			
		||||
//                    ShouldRegisterWithEureka = false
 | 
			
		||||
//                }
 | 
			
		||||
//            });
 | 
			
		||||
//            services.AddOcelot();
 | 
			
		||||
//            var provider = services.BuildServiceProvider();
 | 
			
		||||
//            _builder = new OcelotPipelineBuilder(provider);
 | 
			
		||||
//        }
 | 
			
		||||
//    }
 | 
			
		||||
//}
 | 
			
		||||
 
 | 
			
		||||
@@ -150,7 +150,7 @@ namespace Ocelot.UnitTests.Headers
 | 
			
		||||
        private class AnyError : Error
 | 
			
		||||
        {
 | 
			
		||||
            public AnyError()
 | 
			
		||||
                : base("blahh", OcelotErrorCode.UnknownError)
 | 
			
		||||
                : base("blahh", OcelotErrorCode.UnknownError, 404)
 | 
			
		||||
            {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,16 @@
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Headers
 | 
			
		||||
namespace Ocelot.UnitTests.Headers
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
			
		||||
    using Ocelot.Headers;
 | 
			
		||||
    using Ocelot.Headers.Middleware;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Ocelot.Request.Middleware;
 | 
			
		||||
    using Ocelot.Responses;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
@@ -26,19 +26,19 @@ namespace Ocelot.UnitTests.Headers
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private ClaimsToHeadersMiddleware _middleware;
 | 
			
		||||
        private DownstreamContext _downstreamContext;
 | 
			
		||||
        private OcelotRequestDelegate _next;
 | 
			
		||||
        private RequestDelegate _next;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
 | 
			
		||||
        public ClaimsToHeadersMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
            _addHeaders = new Mock<IAddHeadersToRequest>();
 | 
			
		||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<ClaimsToHeadersMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _next = context => Task.CompletedTask;
 | 
			
		||||
            _middleware = new ClaimsToHeadersMiddleware(_next, _loggerFactory.Object, _addHeaders.Object);
 | 
			
		||||
            _downstreamContext.DownstreamRequest = new DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "http://test.com"));
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamRequest(new DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "http://test.com")));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
@@ -66,14 +66,16 @@ namespace Ocelot.UnitTests.Headers
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
 | 
			
		||||
            _middleware.Invoke(_httpContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamRoute = new OkResponse<DownstreamRoute>(downstreamRoute);
 | 
			
		||||
            _downstreamContext.TemplatePlaceholderNameAndValues = downstreamRoute.TemplatePlaceholderNameAndValues;
 | 
			
		||||
            _downstreamContext.DownstreamReRoute = downstreamRoute.ReRoute.DownstreamReRoute[0];
 | 
			
		||||
 | 
			
		||||
            _httpContext.Items.UpsertTemplatePlaceholderNameAndValues(downstreamRoute.TemplatePlaceholderNameAndValues);
 | 
			
		||||
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamReRoute(downstreamRoute.ReRoute.DownstreamReRoute[0]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheAddHeadersToDownstreamRequestReturnsOk()
 | 
			
		||||
@@ -92,7 +94,7 @@ namespace Ocelot.UnitTests.Headers
 | 
			
		||||
                .Verify(x => x.SetHeadersOnDownstreamRequest(
 | 
			
		||||
                    It.IsAny<List<ClaimToThing>>(),
 | 
			
		||||
                    It.IsAny<IEnumerable<System.Security.Claims.Claim>>(),
 | 
			
		||||
                    _downstreamContext.DownstreamRequest), Times.Once);
 | 
			
		||||
                    _httpContext.Items.DownstreamRequest()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,119 +1,121 @@
 | 
			
		||||
namespace Ocelot.UnitTests.Headers
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Authorisation.Middleware;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder;
 | 
			
		||||
    using Ocelot.Headers;
 | 
			
		||||
    using Ocelot.Headers.Middleware;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Ocelot.Request.Middleware;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class HttpHeadersTransformationMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Mock<IHttpContextRequestHeaderReplacer> _preReplacer;
 | 
			
		||||
        private readonly Mock<IHttpResponseHeaderReplacer> _postReplacer;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private readonly HttpHeadersTransformationMiddleware _middleware;
 | 
			
		||||
        private readonly DownstreamContext _downstreamContext;
 | 
			
		||||
        private OcelotRequestDelegate _next;
 | 
			
		||||
        private readonly Mock<IAddHeadersToResponse> _addHeadersToResponse;
 | 
			
		||||
        private readonly Mock<IAddHeadersToRequest> _addHeadersToRequest;
 | 
			
		||||
 | 
			
		||||
        public HttpHeadersTransformationMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _preReplacer = new Mock<IHttpContextRequestHeaderReplacer>();
 | 
			
		||||
            _postReplacer = new Mock<IHttpResponseHeaderReplacer>();
 | 
			
		||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<AuthorisationMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _next = context => Task.CompletedTask;
 | 
			
		||||
            _addHeadersToResponse = new Mock<IAddHeadersToResponse>();
 | 
			
		||||
            _addHeadersToRequest = new Mock<IAddHeadersToRequest>();
 | 
			
		||||
            _middleware = new HttpHeadersTransformationMiddleware(
 | 
			
		||||
                _next, _loggerFactory.Object, _preReplacer.Object,
 | 
			
		||||
                _postReplacer.Object, _addHeadersToResponse.Object, _addHeadersToRequest.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_pre_and_post_header_transforms()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => GivenTheFollowingRequest())
 | 
			
		||||
                .And(x => GivenTheDownstreamRequestIs())
 | 
			
		||||
                .And(x => GivenTheReRouteHasPreFindAndReplaceSetUp())
 | 
			
		||||
                .And(x => GivenTheHttpResponseMessageIs())
 | 
			
		||||
                .When(x => WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => ThenTheIHttpContextRequestHeaderReplacerIsCalledCorrectly())
 | 
			
		||||
                .Then(x => ThenAddHeadersToRequestIsCalledCorrectly())
 | 
			
		||||
                .And(x => ThenTheIHttpResponseHeaderReplacerIsCalledCorrectly())
 | 
			
		||||
                .And(x => ThenAddHeadersToResponseIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenAddHeadersToResponseIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _addHeadersToResponse
 | 
			
		||||
                .Verify(x => x.Add(_downstreamContext.DownstreamReRoute.AddHeadersToDownstream, _downstreamContext.DownstreamResponse), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenAddHeadersToRequestIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _addHeadersToRequest
 | 
			
		||||
                .Verify(x => x.SetHeadersOnDownstreamRequest(_downstreamContext.DownstreamReRoute.AddHeadersToUpstream, _downstreamContext.HttpContext), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownstreamRequestIs()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.DownstreamRequest = new DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "http://test.com"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheHttpResponseMessageIs()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.DownstreamResponse = new DownstreamResponse(new HttpResponseMessage());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheReRouteHasPreFindAndReplaceSetUp()
 | 
			
		||||
        {
 | 
			
		||||
            var fAndRs = new List<HeaderFindAndReplace>();
 | 
			
		||||
            var reRoute = new ReRouteBuilder()
 | 
			
		||||
                .WithDownstreamReRoute(new DownstreamReRouteBuilder().WithUpstreamHeaderFindAndReplace(fAndRs)
 | 
			
		||||
                    .WithDownstreamHeaderFindAndReplace(fAndRs).Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var dR = new DownstreamRoute(null, reRoute);
 | 
			
		||||
 | 
			
		||||
            _downstreamContext.TemplatePlaceholderNameAndValues = dR.TemplatePlaceholderNameAndValues;
 | 
			
		||||
            _downstreamContext.DownstreamReRoute = dR.ReRoute.DownstreamReRoute[0];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheIHttpContextRequestHeaderReplacerIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _preReplacer.Verify(x => x.Replace(It.IsAny<HttpContext>(), It.IsAny<List<HeaderFindAndReplace>>()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheIHttpResponseHeaderReplacerIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _postReplacer.Verify(x => x.Replace(It.IsAny<DownstreamContext>(), It.IsAny<List<HeaderFindAndReplace>>()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFollowingRequest()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.HttpContext.Request.Headers.Add("test", "test");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
namespace Ocelot.UnitTests.Headers
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Authorisation.Middleware;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder;
 | 
			
		||||
    using Ocelot.Headers;
 | 
			
		||||
    using Ocelot.Headers.Middleware;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Ocelot.Request.Middleware;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using Ocelot.Infrastructure.RequestData;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
 | 
			
		||||
    public class HttpHeadersTransformationMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Mock<IHttpContextRequestHeaderReplacer> _preReplacer;
 | 
			
		||||
        private readonly Mock<IHttpResponseHeaderReplacer> _postReplacer;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private readonly HttpHeadersTransformationMiddleware _middleware;
 | 
			
		||||
        private RequestDelegate _next;
 | 
			
		||||
        private readonly Mock<IAddHeadersToResponse> _addHeadersToResponse;
 | 
			
		||||
        private readonly Mock<IAddHeadersToRequest> _addHeadersToRequest;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
 | 
			
		||||
        public HttpHeadersTransformationMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
            _preReplacer = new Mock<IHttpContextRequestHeaderReplacer>();
 | 
			
		||||
            _postReplacer = new Mock<IHttpResponseHeaderReplacer>();
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<AuthorisationMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _next = context => Task.CompletedTask;
 | 
			
		||||
            _addHeadersToResponse = new Mock<IAddHeadersToResponse>();
 | 
			
		||||
            _addHeadersToRequest = new Mock<IAddHeadersToRequest>();
 | 
			
		||||
            _middleware = new HttpHeadersTransformationMiddleware(
 | 
			
		||||
                _next, _loggerFactory.Object, _preReplacer.Object,
 | 
			
		||||
                _postReplacer.Object, _addHeadersToResponse.Object, _addHeadersToRequest.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_pre_and_post_header_transforms()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => GivenTheFollowingRequest())
 | 
			
		||||
                .And(x => GivenTheDownstreamRequestIs())
 | 
			
		||||
                .And(x => GivenTheReRouteHasPreFindAndReplaceSetUp())
 | 
			
		||||
                .And(x => GivenTheHttpResponseMessageIs())
 | 
			
		||||
                .When(x => WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => ThenTheIHttpContextRequestHeaderReplacerIsCalledCorrectly())
 | 
			
		||||
                .Then(x => ThenAddHeadersToRequestIsCalledCorrectly())
 | 
			
		||||
                .And(x => ThenTheIHttpResponseHeaderReplacerIsCalledCorrectly())
 | 
			
		||||
                .And(x => ThenAddHeadersToResponseIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenAddHeadersToResponseIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _addHeadersToResponse
 | 
			
		||||
                .Verify(x => x.Add(_httpContext.Items.DownstreamReRoute().AddHeadersToDownstream, _httpContext.Items.DownstreamResponse()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenAddHeadersToRequestIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _addHeadersToRequest
 | 
			
		||||
                .Verify(x => x.SetHeadersOnDownstreamRequest(_httpContext.Items.DownstreamReRoute().AddHeadersToUpstream, _httpContext), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_httpContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownstreamRequestIs()
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamRequest(new DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "http://test.com")));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheHttpResponseMessageIs()
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamResponse(new DownstreamResponse(new HttpResponseMessage()));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheReRouteHasPreFindAndReplaceSetUp()
 | 
			
		||||
        {
 | 
			
		||||
            var fAndRs = new List<HeaderFindAndReplace>();
 | 
			
		||||
            var reRoute = new ReRouteBuilder()
 | 
			
		||||
                .WithDownstreamReRoute(new DownstreamReRouteBuilder().WithUpstreamHeaderFindAndReplace(fAndRs)
 | 
			
		||||
                    .WithDownstreamHeaderFindAndReplace(fAndRs).Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var dR = new DownstreamRoute(null, reRoute);
 | 
			
		||||
 | 
			
		||||
            _httpContext.Items.UpsertTemplatePlaceholderNameAndValues(dR.TemplatePlaceholderNameAndValues);
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamReRoute(dR.ReRoute.DownstreamReRoute[0]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheIHttpContextRequestHeaderReplacerIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _preReplacer.Verify(x => x.Replace(It.IsAny<HttpContext>(), It.IsAny<List<HeaderFindAndReplace>>()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheIHttpResponseHeaderReplacerIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _postReplacer.Verify(x => x.Replace(It.IsAny<HttpContext>(), It.IsAny<List<HeaderFindAndReplace>>()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFollowingRequest()
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext.Request.Headers.Add("test", "test");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@ namespace Ocelot.UnitTests.Headers
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
    using Ocelot.Headers;
 | 
			
		||||
    using Ocelot.Infrastructure;
 | 
			
		||||
    using Ocelot.Infrastructure.RequestData;
 | 
			
		||||
@@ -263,8 +264,11 @@ namespace Ocelot.UnitTests.Headers
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheReplacer()
 | 
			
		||||
        {
 | 
			
		||||
            var context = new DownstreamContext(new DefaultHttpContext()) { DownstreamResponse = _response, DownstreamRequest = _request };
 | 
			
		||||
            _result = _replacer.Replace(context, _headerFindAndReplaces);
 | 
			
		||||
            var httpContext = new DefaultHttpContext();
 | 
			
		||||
            httpContext.Items.UpsertDownstreamResponse(_response);
 | 
			
		||||
            httpContext.Items.UpsertDownstreamRequest(_request);
 | 
			
		||||
 | 
			
		||||
            _result = _replacer.Replace(httpContext, _headerFindAndReplaces);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheHeaderShouldBe(string key, string value)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,123 +1,123 @@
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Authorisation;
 | 
			
		||||
using Ocelot.Errors;
 | 
			
		||||
using Ocelot.Infrastructure.Claims.Parser;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Security.Claims;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Infrastructure
 | 
			
		||||
{
 | 
			
		||||
    public class ScopesAuthoriserTests
 | 
			
		||||
    {
 | 
			
		||||
        private ScopesAuthoriser _authoriser;
 | 
			
		||||
        public Mock<IClaimsParser> _parser;
 | 
			
		||||
        private ClaimsPrincipal _principal;
 | 
			
		||||
        private List<string> _allowedScopes;
 | 
			
		||||
        private Response<bool> _result;
 | 
			
		||||
 | 
			
		||||
        public ScopesAuthoriserTests()
 | 
			
		||||
        {
 | 
			
		||||
            _parser = new Mock<IClaimsParser>();
 | 
			
		||||
            _authoriser = new ScopesAuthoriser(_parser.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_ok_if_no_allowed_scopes()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(_ => GivenTheFollowing(new ClaimsPrincipal()))
 | 
			
		||||
            .And(_ => GivenTheFollowing(new List<string>()))
 | 
			
		||||
            .When(_ => WhenIAuthorise())
 | 
			
		||||
            .Then(_ => ThenTheFollowingIsReturned(new OkResponse<bool>(true)))
 | 
			
		||||
            .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_ok_if_null_allowed_scopes()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(_ => GivenTheFollowing(new ClaimsPrincipal()))
 | 
			
		||||
            .And(_ => GivenTheFollowing((List<string>)null))
 | 
			
		||||
            .When(_ => WhenIAuthorise())
 | 
			
		||||
            .Then(_ => ThenTheFollowingIsReturned(new OkResponse<bool>(true)))
 | 
			
		||||
            .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_error_if_claims_parser_returns_error()
 | 
			
		||||
        {
 | 
			
		||||
            var fakeError = new FakeError();
 | 
			
		||||
            this.Given(_ => GivenTheFollowing(new ClaimsPrincipal()))
 | 
			
		||||
            .And(_ => GivenTheParserReturns(new ErrorResponse<List<string>>(fakeError)))
 | 
			
		||||
            .And(_ => GivenTheFollowing(new List<string>() { "doesntmatter" }))
 | 
			
		||||
            .When(_ => WhenIAuthorise())
 | 
			
		||||
            .Then(_ => ThenTheFollowingIsReturned(new ErrorResponse<bool>(fakeError)))
 | 
			
		||||
            .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_match_scopes_and_return_ok_result()
 | 
			
		||||
        {
 | 
			
		||||
            var claimsPrincipal = new ClaimsPrincipal();
 | 
			
		||||
            var allowedScopes = new List<string>() { "someScope" };
 | 
			
		||||
 | 
			
		||||
            this.Given(_ => GivenTheFollowing(claimsPrincipal))
 | 
			
		||||
            .And(_ => GivenTheParserReturns(new OkResponse<List<string>>(allowedScopes)))
 | 
			
		||||
            .And(_ => GivenTheFollowing(allowedScopes))
 | 
			
		||||
            .When(_ => WhenIAuthorise())
 | 
			
		||||
            .Then(_ => ThenTheFollowingIsReturned(new OkResponse<bool>(true)))
 | 
			
		||||
            .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_match_scopes_and_return_error_result()
 | 
			
		||||
        {
 | 
			
		||||
            var fakeError = new FakeError();
 | 
			
		||||
            var claimsPrincipal = new ClaimsPrincipal();
 | 
			
		||||
            var allowedScopes = new List<string>() { "someScope" };
 | 
			
		||||
            var userScopes = new List<string>() { "anotherScope" };
 | 
			
		||||
 | 
			
		||||
            this.Given(_ => GivenTheFollowing(claimsPrincipal))
 | 
			
		||||
            .And(_ => GivenTheParserReturns(new OkResponse<List<string>>(userScopes)))
 | 
			
		||||
            .And(_ => GivenTheFollowing(allowedScopes))
 | 
			
		||||
            .When(_ => WhenIAuthorise())
 | 
			
		||||
            .Then(_ => ThenTheFollowingIsReturned(new ErrorResponse<bool>(fakeError)))
 | 
			
		||||
            .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheParserReturns(Response<List<string>> response)
 | 
			
		||||
        {
 | 
			
		||||
            _parser.Setup(x => x.GetValuesByClaimType(It.IsAny<IEnumerable<Claim>>(), It.IsAny<string>())).Returns(response);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFollowing(ClaimsPrincipal principal)
 | 
			
		||||
        {
 | 
			
		||||
            _principal = principal;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFollowing(List<string> allowedScopes)
 | 
			
		||||
        {
 | 
			
		||||
            _allowedScopes = allowedScopes;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIAuthorise()
 | 
			
		||||
        {
 | 
			
		||||
            _result = _authoriser.Authorise(_principal, _allowedScopes);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheFollowingIsReturned(Response<bool> expected)
 | 
			
		||||
        {
 | 
			
		||||
            _result.Data.ShouldBe(expected.Data);
 | 
			
		||||
            _result.IsError.ShouldBe(expected.IsError);
 | 
			
		||||
        }
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Authorisation;
 | 
			
		||||
using Ocelot.Errors;
 | 
			
		||||
using Ocelot.Infrastructure.Claims.Parser;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Security.Claims;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Infrastructure
 | 
			
		||||
{
 | 
			
		||||
    public class ScopesAuthoriserTests
 | 
			
		||||
    {
 | 
			
		||||
        private ScopesAuthoriser _authoriser;
 | 
			
		||||
        public Mock<IClaimsParser> _parser;
 | 
			
		||||
        private ClaimsPrincipal _principal;
 | 
			
		||||
        private List<string> _allowedScopes;
 | 
			
		||||
        private Response<bool> _result;
 | 
			
		||||
 | 
			
		||||
        public ScopesAuthoriserTests()
 | 
			
		||||
        {
 | 
			
		||||
            _parser = new Mock<IClaimsParser>();
 | 
			
		||||
            _authoriser = new ScopesAuthoriser(_parser.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_ok_if_no_allowed_scopes()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(_ => GivenTheFollowing(new ClaimsPrincipal()))
 | 
			
		||||
            .And(_ => GivenTheFollowing(new List<string>()))
 | 
			
		||||
            .When(_ => WhenIAuthorise())
 | 
			
		||||
            .Then(_ => ThenTheFollowingIsReturned(new OkResponse<bool>(true)))
 | 
			
		||||
            .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_ok_if_null_allowed_scopes()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(_ => GivenTheFollowing(new ClaimsPrincipal()))
 | 
			
		||||
            .And(_ => GivenTheFollowing((List<string>)null))
 | 
			
		||||
            .When(_ => WhenIAuthorise())
 | 
			
		||||
            .Then(_ => ThenTheFollowingIsReturned(new OkResponse<bool>(true)))
 | 
			
		||||
            .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_error_if_claims_parser_returns_error()
 | 
			
		||||
        {
 | 
			
		||||
            var fakeError = new FakeError();
 | 
			
		||||
            this.Given(_ => GivenTheFollowing(new ClaimsPrincipal()))
 | 
			
		||||
            .And(_ => GivenTheParserReturns(new ErrorResponse<List<string>>(fakeError)))
 | 
			
		||||
            .And(_ => GivenTheFollowing(new List<string>() { "doesntmatter" }))
 | 
			
		||||
            .When(_ => WhenIAuthorise())
 | 
			
		||||
            .Then(_ => ThenTheFollowingIsReturned(new ErrorResponse<bool>(fakeError)))
 | 
			
		||||
            .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_match_scopes_and_return_ok_result()
 | 
			
		||||
        {
 | 
			
		||||
            var claimsPrincipal = new ClaimsPrincipal();
 | 
			
		||||
            var allowedScopes = new List<string>() { "someScope" };
 | 
			
		||||
 | 
			
		||||
            this.Given(_ => GivenTheFollowing(claimsPrincipal))
 | 
			
		||||
            .And(_ => GivenTheParserReturns(new OkResponse<List<string>>(allowedScopes)))
 | 
			
		||||
            .And(_ => GivenTheFollowing(allowedScopes))
 | 
			
		||||
            .When(_ => WhenIAuthorise())
 | 
			
		||||
            .Then(_ => ThenTheFollowingIsReturned(new OkResponse<bool>(true)))
 | 
			
		||||
            .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_match_scopes_and_return_error_result()
 | 
			
		||||
        {
 | 
			
		||||
            var fakeError = new FakeError();
 | 
			
		||||
            var claimsPrincipal = new ClaimsPrincipal();
 | 
			
		||||
            var allowedScopes = new List<string>() { "someScope" };
 | 
			
		||||
            var userScopes = new List<string>() { "anotherScope" };
 | 
			
		||||
 | 
			
		||||
            this.Given(_ => GivenTheFollowing(claimsPrincipal))
 | 
			
		||||
            .And(_ => GivenTheParserReturns(new OkResponse<List<string>>(userScopes)))
 | 
			
		||||
            .And(_ => GivenTheFollowing(allowedScopes))
 | 
			
		||||
            .When(_ => WhenIAuthorise())
 | 
			
		||||
            .Then(_ => ThenTheFollowingIsReturned(new ErrorResponse<bool>(fakeError)))
 | 
			
		||||
            .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheParserReturns(Response<List<string>> response)
 | 
			
		||||
        {
 | 
			
		||||
            _parser.Setup(x => x.GetValuesByClaimType(It.IsAny<IEnumerable<Claim>>(), It.IsAny<string>())).Returns(response);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFollowing(ClaimsPrincipal principal)
 | 
			
		||||
        {
 | 
			
		||||
            _principal = principal;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFollowing(List<string> allowedScopes)
 | 
			
		||||
        {
 | 
			
		||||
            _allowedScopes = allowedScopes;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIAuthorise()
 | 
			
		||||
        {
 | 
			
		||||
            _result = _authoriser.Authorise(_principal, _allowedScopes);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheFollowingIsReturned(Response<bool> expected)
 | 
			
		||||
        {
 | 
			
		||||
            _result.Data.ShouldBe(expected.Data);
 | 
			
		||||
            _result.IsError.ShouldBe(expected.IsError);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class FakeError : Error
 | 
			
		||||
    {
 | 
			
		||||
        public FakeError() : base("fake error", OcelotErrorCode.CannotAddDataError)
 | 
			
		||||
        public FakeError() : base("fake error", OcelotErrorCode.CannotAddDataError, 404)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -21,19 +21,19 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
        private readonly CookieStickySessions _stickySessions;
 | 
			
		||||
        private readonly Mock<ILoadBalancer> _loadBalancer;
 | 
			
		||||
        private readonly int _defaultExpiryInMs;
 | 
			
		||||
        private DownstreamContext _downstreamContext;
 | 
			
		||||
        private Response<ServiceHostAndPort> _result;
 | 
			
		||||
        private Response<ServiceHostAndPort> _firstHostAndPort;
 | 
			
		||||
        private Response<ServiceHostAndPort> _secondHostAndPort;
 | 
			
		||||
        private readonly FakeBus<StickySession> _bus;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
 | 
			
		||||
        public CookieStickySessionsTests()
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
            _bus = new FakeBus<StickySession>();
 | 
			
		||||
            _loadBalancer = new Mock<ILoadBalancer>();
 | 
			
		||||
            _defaultExpiryInMs = 0;
 | 
			
		||||
            _stickySessions = new CookieStickySessions(_loadBalancer.Object, "sessionid", _defaultExpiryInMs, _bus);
 | 
			
		||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
@@ -116,7 +116,7 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
        private void GivenTheLoadBalancerReturnsError()
 | 
			
		||||
        {
 | 
			
		||||
            _loadBalancer
 | 
			
		||||
                .Setup(x => x.Lease(It.IsAny<DownstreamContext>()))
 | 
			
		||||
                .Setup(x => x.Lease(It.IsAny<HttpContext>()))
 | 
			
		||||
                .ReturnsAsync(new ErrorResponse<ServiceHostAndPort>(new AnyError()));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -138,14 +138,14 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
            var cookiesTwo = new FakeCookies();
 | 
			
		||||
            cookiesTwo.AddCookie("sessionid", "123");
 | 
			
		||||
            contextTwo.Request.Cookies = cookiesTwo;
 | 
			
		||||
            _firstHostAndPort = await _stickySessions.Lease(new DownstreamContext(contextOne));
 | 
			
		||||
            _secondHostAndPort = await _stickySessions.Lease(new DownstreamContext(contextTwo));
 | 
			
		||||
            _firstHostAndPort = await _stickySessions.Lease(contextOne);
 | 
			
		||||
            _secondHostAndPort = await _stickySessions.Lease(contextTwo);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheLoadBalancerReturnsSequence()
 | 
			
		||||
        {
 | 
			
		||||
            _loadBalancer
 | 
			
		||||
                .SetupSequence(x => x.Lease(It.IsAny<DownstreamContext>()))
 | 
			
		||||
                .SetupSequence(x => x.Lease(It.IsAny<HttpContext>()))
 | 
			
		||||
                .ReturnsAsync(new OkResponse<ServiceHostAndPort>(new ServiceHostAndPort("one", 80)))
 | 
			
		||||
                .ReturnsAsync(new OkResponse<ServiceHostAndPort>(new ServiceHostAndPort("two", 80)));
 | 
			
		||||
        }
 | 
			
		||||
@@ -158,8 +158,8 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
 | 
			
		||||
        private async Task WhenILeaseTwiceInARow()
 | 
			
		||||
        {
 | 
			
		||||
            _firstHostAndPort = await _stickySessions.Lease(_downstreamContext);
 | 
			
		||||
            _secondHostAndPort = await _stickySessions.Lease(_downstreamContext);
 | 
			
		||||
            _firstHostAndPort = await _stickySessions.Lease(_httpContext);
 | 
			
		||||
            _secondHostAndPort = await _stickySessions.Lease(_httpContext);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownstreamRequestHasSessionId(string value)
 | 
			
		||||
@@ -168,19 +168,19 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
            var cookies = new FakeCookies();
 | 
			
		||||
            cookies.AddCookie("sessionid", value);
 | 
			
		||||
            context.Request.Cookies = cookies;
 | 
			
		||||
            _downstreamContext = new DownstreamContext(context);
 | 
			
		||||
            _httpContext = context;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheLoadBalancerReturns()
 | 
			
		||||
        {
 | 
			
		||||
            _loadBalancer
 | 
			
		||||
                .Setup(x => x.Lease(It.IsAny<DownstreamContext>()))
 | 
			
		||||
                .Setup(x => x.Lease(It.IsAny<HttpContext>()))
 | 
			
		||||
                .ReturnsAsync(new OkResponse<ServiceHostAndPort>(new ServiceHostAndPort("", 80)));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task WhenILease()
 | 
			
		||||
        {
 | 
			
		||||
            _result = await _stickySessions.Lease(_downstreamContext);
 | 
			
		||||
            _result = await _stickySessions.Lease(_httpContext);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheHostAndPortIsNotNull()
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,8 @@ using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
 | 
			
		||||
    public class DelegateInvokingLoadBalancerCreatorTests
 | 
			
		||||
    {
 | 
			
		||||
        private DelegateInvokingLoadBalancerCreator<FakeLoadBalancer> _creator;
 | 
			
		||||
@@ -113,7 +115,7 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
            public DownstreamReRoute ReRoute { get; }
 | 
			
		||||
            public IServiceDiscoveryProvider ServiceDiscoveryProvider { get; }
 | 
			
		||||
 | 
			
		||||
            public Task<Response<ServiceHostAndPort>> Lease(DownstreamContext context)
 | 
			
		||||
            public Task<Response<ServiceHostAndPort>> Lease(HttpContext httpContext)
 | 
			
		||||
            {
 | 
			
		||||
                throw new NotImplementedException();
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -19,11 +19,11 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
        private LeastConnection _leastConnection;
 | 
			
		||||
        private List<Service> _services;
 | 
			
		||||
        private Random _random;
 | 
			
		||||
        private DownstreamContext _context;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
 | 
			
		||||
        public LeastConnectionTests()
 | 
			
		||||
        {
 | 
			
		||||
            _context = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
            _random = new Random();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -64,9 +64,9 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
 | 
			
		||||
            _leastConnection = new LeastConnection(() => Task.FromResult(availableServices), serviceName);
 | 
			
		||||
 | 
			
		||||
            var hostAndPortOne = _leastConnection.Lease(_context).Result;
 | 
			
		||||
            var hostAndPortOne = _leastConnection.Lease(_httpContext).Result;
 | 
			
		||||
            hostAndPortOne.Data.DownstreamHost.ShouldBe("127.0.0.1");
 | 
			
		||||
            var hostAndPortTwo = _leastConnection.Lease(_context).Result;
 | 
			
		||||
            var hostAndPortTwo = _leastConnection.Lease(_httpContext).Result;
 | 
			
		||||
            hostAndPortTwo.Data.DownstreamHost.ShouldBe("127.0.0.2");
 | 
			
		||||
            _leastConnection.Release(hostAndPortOne.Data);
 | 
			
		||||
            _leastConnection.Release(hostAndPortTwo.Data);
 | 
			
		||||
@@ -76,9 +76,9 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
                new Service(serviceName, new ServiceHostAndPort("127.0.0.1", 80), string.Empty, string.Empty, new string[0]),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            hostAndPortOne = _leastConnection.Lease(_context).Result;
 | 
			
		||||
            hostAndPortOne = _leastConnection.Lease(_httpContext).Result;
 | 
			
		||||
            hostAndPortOne.Data.DownstreamHost.ShouldBe("127.0.0.1");
 | 
			
		||||
            hostAndPortTwo = _leastConnection.Lease(_context).Result;
 | 
			
		||||
            hostAndPortTwo = _leastConnection.Lease(_httpContext).Result;
 | 
			
		||||
            hostAndPortTwo.Data.DownstreamHost.ShouldBe("127.0.0.1");
 | 
			
		||||
            _leastConnection.Release(hostAndPortOne.Data);
 | 
			
		||||
            _leastConnection.Release(hostAndPortTwo.Data);
 | 
			
		||||
@@ -89,9 +89,9 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
                new Service(serviceName, new ServiceHostAndPort("127.0.0.2", 80), string.Empty, string.Empty, new string[0]),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            hostAndPortOne = _leastConnection.Lease(_context).Result;
 | 
			
		||||
            hostAndPortOne = _leastConnection.Lease(_httpContext).Result;
 | 
			
		||||
            hostAndPortOne.Data.DownstreamHost.ShouldBe("127.0.0.1");
 | 
			
		||||
            hostAndPortTwo = _leastConnection.Lease(_context).Result;
 | 
			
		||||
            hostAndPortTwo = _leastConnection.Lease( _httpContext).Result;
 | 
			
		||||
            hostAndPortTwo.Data.DownstreamHost.ShouldBe("127.0.0.2");
 | 
			
		||||
            _leastConnection.Release(hostAndPortOne.Data);
 | 
			
		||||
            _leastConnection.Release(hostAndPortTwo.Data);
 | 
			
		||||
@@ -99,7 +99,7 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
 | 
			
		||||
        private async Task LeaseDelayAndRelease()
 | 
			
		||||
        {
 | 
			
		||||
            var hostAndPort = await _leastConnection.Lease(_context);
 | 
			
		||||
            var hostAndPort = await _leastConnection.Lease(_httpContext);
 | 
			
		||||
            await Task.Delay(_random.Next(1, 100));
 | 
			
		||||
            _leastConnection.Release(hostAndPort.Data);
 | 
			
		||||
        }
 | 
			
		||||
@@ -138,15 +138,15 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
            _services = availableServices;
 | 
			
		||||
            _leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName);
 | 
			
		||||
 | 
			
		||||
            var response = _leastConnection.Lease(_context).Result;
 | 
			
		||||
            var response = _leastConnection.Lease(_httpContext).Result;
 | 
			
		||||
 | 
			
		||||
            response.Data.DownstreamHost.ShouldBe(availableServices[0].HostAndPort.DownstreamHost);
 | 
			
		||||
 | 
			
		||||
            response = _leastConnection.Lease(_context).Result;
 | 
			
		||||
            response = _leastConnection.Lease(_httpContext).Result;
 | 
			
		||||
 | 
			
		||||
            response.Data.DownstreamHost.ShouldBe(availableServices[1].HostAndPort.DownstreamHost);
 | 
			
		||||
 | 
			
		||||
            response = _leastConnection.Lease(_context).Result;
 | 
			
		||||
            response = _leastConnection.Lease(_httpContext).Result;
 | 
			
		||||
 | 
			
		||||
            response.Data.DownstreamHost.ShouldBe(availableServices[2].HostAndPort.DownstreamHost);
 | 
			
		||||
        }
 | 
			
		||||
@@ -165,19 +165,19 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
            _services = availableServices;
 | 
			
		||||
            _leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName);
 | 
			
		||||
 | 
			
		||||
            var response = _leastConnection.Lease(_context).Result;
 | 
			
		||||
            var response = _leastConnection.Lease(_httpContext).Result;
 | 
			
		||||
 | 
			
		||||
            response.Data.DownstreamHost.ShouldBe(availableServices[0].HostAndPort.DownstreamHost);
 | 
			
		||||
 | 
			
		||||
            response = _leastConnection.Lease(_context).Result;
 | 
			
		||||
            response = _leastConnection.Lease(_httpContext).Result;
 | 
			
		||||
 | 
			
		||||
            response.Data.DownstreamHost.ShouldBe(availableServices[1].HostAndPort.DownstreamHost);
 | 
			
		||||
 | 
			
		||||
            response = _leastConnection.Lease(_context).Result;
 | 
			
		||||
            response = _leastConnection.Lease(_httpContext).Result;
 | 
			
		||||
 | 
			
		||||
            response.Data.DownstreamHost.ShouldBe(availableServices[0].HostAndPort.DownstreamHost);
 | 
			
		||||
 | 
			
		||||
            response = _leastConnection.Lease(_context).Result;
 | 
			
		||||
            response = _leastConnection.Lease(_httpContext).Result;
 | 
			
		||||
 | 
			
		||||
            response.Data.DownstreamHost.ShouldBe(availableServices[1].HostAndPort.DownstreamHost);
 | 
			
		||||
        }
 | 
			
		||||
@@ -196,26 +196,26 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
            _services = availableServices;
 | 
			
		||||
            _leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName);
 | 
			
		||||
 | 
			
		||||
            var response = _leastConnection.Lease(_context).Result;
 | 
			
		||||
            var response = _leastConnection.Lease(_httpContext).Result;
 | 
			
		||||
 | 
			
		||||
            response.Data.DownstreamHost.ShouldBe(availableServices[0].HostAndPort.DownstreamHost);
 | 
			
		||||
 | 
			
		||||
            response = _leastConnection.Lease(_context).Result;
 | 
			
		||||
            response = _leastConnection.Lease(_httpContext).Result;
 | 
			
		||||
 | 
			
		||||
            response.Data.DownstreamHost.ShouldBe(availableServices[1].HostAndPort.DownstreamHost);
 | 
			
		||||
 | 
			
		||||
            response = _leastConnection.Lease(_context).Result;
 | 
			
		||||
            response = _leastConnection.Lease(_httpContext).Result;
 | 
			
		||||
 | 
			
		||||
            response.Data.DownstreamHost.ShouldBe(availableServices[0].HostAndPort.DownstreamHost);
 | 
			
		||||
 | 
			
		||||
            response = _leastConnection.Lease(_context).Result;
 | 
			
		||||
            response = _leastConnection.Lease(_httpContext).Result;
 | 
			
		||||
 | 
			
		||||
            response.Data.DownstreamHost.ShouldBe(availableServices[1].HostAndPort.DownstreamHost);
 | 
			
		||||
 | 
			
		||||
            //release this so 2 should have 1 connection and we should get 2 back as our next host and port
 | 
			
		||||
            _leastConnection.Release(availableServices[1].HostAndPort);
 | 
			
		||||
 | 
			
		||||
            response = _leastConnection.Lease(_context).Result;
 | 
			
		||||
            response = _leastConnection.Lease(_httpContext).Result;
 | 
			
		||||
 | 
			
		||||
            response.Data.DownstreamHost.ShouldBe(availableServices[1].HostAndPort.DownstreamHost);
 | 
			
		||||
        }
 | 
			
		||||
@@ -276,7 +276,7 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
 | 
			
		||||
        private void WhenIGetTheNextHostAndPort()
 | 
			
		||||
        {
 | 
			
		||||
            _result = _leastConnection.Lease(_context).Result;
 | 
			
		||||
            _result = _leastConnection.Lease(_httpContext).Result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheNextHostAndPortIsReturned()
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@ using Xunit;
 | 
			
		||||
namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
{
 | 
			
		||||
    using System;
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
 | 
			
		||||
    public class LoadBalancerFactoryTests
 | 
			
		||||
    {
 | 
			
		||||
@@ -228,7 +229,7 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
 | 
			
		||||
        private class FakeLoadBalancerOne : ILoadBalancer
 | 
			
		||||
        {
 | 
			
		||||
            public Task<Response<ServiceHostAndPort>> Lease(DownstreamContext context)
 | 
			
		||||
            public Task<Response<ServiceHostAndPort>> Lease(HttpContext httpContext)
 | 
			
		||||
            {
 | 
			
		||||
                throw new System.NotImplementedException();
 | 
			
		||||
            }
 | 
			
		||||
@@ -241,7 +242,7 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
 | 
			
		||||
        private class FakeLoadBalancerTwo : ILoadBalancer
 | 
			
		||||
        {
 | 
			
		||||
            public Task<Response<ServiceHostAndPort>> Lease(DownstreamContext context)
 | 
			
		||||
            public Task<Response<ServiceHostAndPort>> Lease(HttpContext httpContext)
 | 
			
		||||
            {
 | 
			
		||||
                throw new System.NotImplementedException();
 | 
			
		||||
            }
 | 
			
		||||
@@ -254,7 +255,7 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
 | 
			
		||||
        private class FakeNoLoadBalancer : ILoadBalancer
 | 
			
		||||
        {
 | 
			
		||||
            public Task<Response<ServiceHostAndPort>> Lease(DownstreamContext context)
 | 
			
		||||
            public Task<Response<ServiceHostAndPort>> Lease(HttpContext httpContext)
 | 
			
		||||
            {
 | 
			
		||||
                throw new System.NotImplementedException();
 | 
			
		||||
            }
 | 
			
		||||
@@ -267,7 +268,7 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
 | 
			
		||||
        private class BrokenLoadBalancer : ILoadBalancer
 | 
			
		||||
        {
 | 
			
		||||
            public Task<Response<ServiceHostAndPort>> Lease(DownstreamContext context)
 | 
			
		||||
            public Task<Response<ServiceHostAndPort>> Lease(HttpContext httpContext)
 | 
			
		||||
            {
 | 
			
		||||
                throw new System.NotImplementedException();
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,8 @@ using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
 | 
			
		||||
    public class LoadBalancerHouseTests
 | 
			
		||||
    {
 | 
			
		||||
        private DownstreamReRoute _reRoute;
 | 
			
		||||
@@ -155,7 +157,7 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
 | 
			
		||||
        private class FakeLoadBalancer : ILoadBalancer
 | 
			
		||||
        {
 | 
			
		||||
            public Task<Response<ServiceHostAndPort>> Lease(DownstreamContext context)
 | 
			
		||||
            public Task<Response<ServiceHostAndPort>> Lease(HttpContext httpContext)
 | 
			
		||||
            {
 | 
			
		||||
                throw new NotImplementedException();
 | 
			
		||||
            }
 | 
			
		||||
@@ -168,7 +170,7 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
 | 
			
		||||
        private class FakeRoundRobinLoadBalancer : ILoadBalancer
 | 
			
		||||
        {
 | 
			
		||||
            public Task<Response<ServiceHostAndPort>> Lease(DownstreamContext context)
 | 
			
		||||
            public Task<Response<ServiceHostAndPort>> Lease(HttpContext httpContext)
 | 
			
		||||
            {
 | 
			
		||||
                throw new NotImplementedException();
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,3 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Linq.Expressions;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
@@ -19,8 +15,13 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using Ocelot.Infrastructure.RequestData;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Linq.Expressions;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
 | 
			
		||||
    public class LoadBalancerMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
@@ -34,21 +35,22 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private LoadBalancingMiddleware _middleware;
 | 
			
		||||
        private DownstreamContext _downstreamContext;
 | 
			
		||||
        private OcelotRequestDelegate _next;
 | 
			
		||||
        private RequestDelegate _next;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
        private Mock<IRequestScopedDataRepository> _repo;
 | 
			
		||||
 | 
			
		||||
        public LoadBalancerMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _repo = new Mock<IRequestScopedDataRepository>();
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
            _loadBalancerHouse = new Mock<ILoadBalancerHouse>();
 | 
			
		||||
            _loadBalancer = new Mock<ILoadBalancer>();
 | 
			
		||||
            _loadBalancerHouse = new Mock<ILoadBalancerHouse>();
 | 
			
		||||
            _downstreamRequest = new HttpRequestMessage(HttpMethod.Get, "http://test.com/");
 | 
			
		||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<LoadBalancingMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _next = context => Task.CompletedTask;
 | 
			
		||||
            _downstreamContext.DownstreamRequest = new DownstreamRequest(_downstreamRequest);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
@@ -133,34 +135,34 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware = new LoadBalancingMiddleware(_next, _loggerFactory.Object, _loadBalancerHouse.Object);
 | 
			
		||||
            _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
 | 
			
		||||
            _middleware.Invoke(_httpContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheConfigurationIs(ServiceProviderConfiguration config)
 | 
			
		||||
        {
 | 
			
		||||
            _config = config;
 | 
			
		||||
            var configuration = new InternalConfiguration(null, null, config, null, null, null, null, null, null);
 | 
			
		||||
            _downstreamContext.Configuration = configuration;
 | 
			
		||||
            _httpContext.Items.SetIInternalConfiguration(configuration);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownStreamUrlIs(string downstreamUrl)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamRequest.RequestUri = new System.Uri(downstreamUrl);
 | 
			
		||||
            _downstreamContext.DownstreamRequest = new DownstreamRequest(_downstreamRequest);
 | 
			
		||||
            _downstreamRequest.RequestUri = new Uri(downstreamUrl);
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamRequest(new DownstreamRequest(_downstreamRequest));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheLoadBalancerReturnsAnError()
 | 
			
		||||
        {
 | 
			
		||||
            _getHostAndPortError = new ErrorResponse<ServiceHostAndPort>(new List<Error>() { new ServicesAreNullError($"services were null for bah") });
 | 
			
		||||
            _loadBalancer
 | 
			
		||||
               .Setup(x => x.Lease(It.IsAny<DownstreamContext>()))
 | 
			
		||||
               .Setup(x => x.Lease(It.IsAny<HttpContext>()))
 | 
			
		||||
               .ReturnsAsync(_getHostAndPortError);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheLoadBalancerReturnsOk()
 | 
			
		||||
        {
 | 
			
		||||
            _loadBalancer
 | 
			
		||||
                .Setup(x => x.Lease(It.IsAny<DownstreamContext>()))
 | 
			
		||||
                .Setup(x => x.Lease(It.IsAny<HttpContext>()))
 | 
			
		||||
                .ReturnsAsync(new OkResponse<ServiceHostAndPort>(new ServiceHostAndPort("abc", 123, "https")));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -168,14 +170,14 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
        {
 | 
			
		||||
            _hostAndPort = new ServiceHostAndPort("127.0.0.1", 80);
 | 
			
		||||
            _loadBalancer
 | 
			
		||||
                .Setup(x => x.Lease(It.IsAny<DownstreamContext>()))
 | 
			
		||||
                .Setup(x => x.Lease(It.IsAny<HttpContext>()))
 | 
			
		||||
                .ReturnsAsync(new OkResponse<ServiceHostAndPort>(_hostAndPort));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownStreamRouteIs(DownstreamReRoute downstreamRoute, List<Ocelot.DownstreamRouteFinder.UrlMatcher.PlaceholderNameAndValue> placeholder)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.TemplatePlaceholderNameAndValues = placeholder;
 | 
			
		||||
            _downstreamContext.DownstreamReRoute = downstreamRoute;
 | 
			
		||||
            _httpContext.Items.UpsertTemplatePlaceholderNameAndValues(placeholder);
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamReRoute(downstreamRoute);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheLoadBalancerHouseReturns()
 | 
			
		||||
@@ -199,32 +201,32 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
 | 
			
		||||
        private void ThenAnErrorStatingLoadBalancerCouldNotBeFoundIsSetOnPipeline()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.IsError.ShouldBeTrue();
 | 
			
		||||
            _downstreamContext.Errors.ShouldBe(_getLoadBalancerHouseError.Errors);
 | 
			
		||||
            _httpContext.Items.Errors().Count.ShouldBeGreaterThan(0);
 | 
			
		||||
            _httpContext.Items.Errors().ShouldBe(_getLoadBalancerHouseError.Errors);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenAnErrorSayingReleaseFailedIsSetOnThePipeline()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.IsError.ShouldBeTrue();
 | 
			
		||||
            _downstreamContext.Errors.ShouldBe(It.IsAny<List<Error>>());
 | 
			
		||||
            _httpContext.Items.Errors().Count.ShouldBeGreaterThan(0);
 | 
			
		||||
            _httpContext.Items.Errors().ShouldBe(It.IsAny<List<Error>>());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenAnErrorStatingHostAndPortCouldNotBeFoundIsSetOnPipeline()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.IsError.ShouldBeTrue();
 | 
			
		||||
            _downstreamContext.Errors.ShouldBe(_getHostAndPortError.Errors);
 | 
			
		||||
            _httpContext.Items.Errors().Count.ShouldBeGreaterThan(0);
 | 
			
		||||
            _httpContext.Items.Errors().ShouldBe(_getHostAndPortError.Errors);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenAnHostAndPortIsSetOnPipeline()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.DownstreamRequest.Host.ShouldBeEquivalentTo("abc");
 | 
			
		||||
            _downstreamContext.DownstreamRequest.Port.ShouldBeEquivalentTo(123);
 | 
			
		||||
            _downstreamContext.DownstreamRequest.Scheme.ShouldBeEquivalentTo("https");
 | 
			
		||||
            _httpContext.Items.DownstreamRequest().Host.ShouldBeEquivalentTo("abc");
 | 
			
		||||
            _httpContext.Items.DownstreamRequest().Port.ShouldBeEquivalentTo(123);
 | 
			
		||||
            _httpContext.Items.DownstreamRequest().Scheme.ShouldBeEquivalentTo("https");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheDownstreamUrlIsReplacedWith(string expectedUri)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.DownstreamRequest.ToHttpRequestMessage().RequestUri.OriginalString.ShouldBe(expectedUri);
 | 
			
		||||
            _httpContext.Items.DownstreamRequest().ToHttpRequestMessage().RequestUri.OriginalString.ShouldBe(expectedUri);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -91,7 +91,7 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
 | 
			
		||||
        private void WhenIGetTheNextHostAndPort()
 | 
			
		||||
        {
 | 
			
		||||
            _result = _loadBalancer.Lease(new DownstreamContext(new DefaultHttpContext())).Result;
 | 
			
		||||
            _result = _loadBalancer.Lease(new DefaultHttpContext()).Result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheHostAndPortIs(ServiceHostAndPort expected)
 | 
			
		||||
 
 | 
			
		||||
@@ -17,12 +17,11 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
        private readonly RoundRobin _roundRobin;
 | 
			
		||||
        private readonly List<Service> _services;
 | 
			
		||||
        private Response<ServiceHostAndPort> _hostAndPort;
 | 
			
		||||
        private DownstreamContext _context;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
 | 
			
		||||
        public RoundRobinTests()
 | 
			
		||||
        {
 | 
			
		||||
            _context = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
            _services = new List<Service>
 | 
			
		||||
            {
 | 
			
		||||
                new Service("product", new ServiceHostAndPort("127.0.0.1", 5000), string.Empty, string.Empty, new string[0]),
 | 
			
		||||
@@ -52,18 +51,18 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
 | 
			
		||||
            while (stopWatch.ElapsedMilliseconds < 1000)
 | 
			
		||||
            {
 | 
			
		||||
                var address = _roundRobin.Lease(_context).Result;
 | 
			
		||||
                var address = _roundRobin.Lease(_httpContext).Result;
 | 
			
		||||
                address.Data.ShouldBe(_services[0].HostAndPort);
 | 
			
		||||
                address = _roundRobin.Lease(_context).Result;
 | 
			
		||||
                address = _roundRobin.Lease(_httpContext).Result;
 | 
			
		||||
                address.Data.ShouldBe(_services[1].HostAndPort);
 | 
			
		||||
                address = _roundRobin.Lease(_context).Result;
 | 
			
		||||
                address = _roundRobin.Lease(_httpContext).Result;
 | 
			
		||||
                address.Data.ShouldBe(_services[2].HostAndPort);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenIGetTheNextAddress()
 | 
			
		||||
        {
 | 
			
		||||
            _hostAndPort = _roundRobin.Lease(_context).Result;
 | 
			
		||||
            _hostAndPort = _roundRobin.Lease(_httpContext).Result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheNextAddressIndexIs(int index)
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,6 @@ using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using System;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
@@ -16,12 +15,13 @@ namespace Ocelot.UnitTests.Logging
 | 
			
		||||
        private readonly Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private IServiceCollection _serviceCollection;
 | 
			
		||||
        private IServiceProvider _serviceProvider;
 | 
			
		||||
        private DownstreamContext _downstreamContext;
 | 
			
		||||
        private string _name;
 | 
			
		||||
        private Exception _exception;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
 | 
			
		||||
        public OcelotDiagnosticListenerTests()
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
            _factory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _serviceCollection = new ServiceCollection();
 | 
			
		||||
@@ -30,44 +30,12 @@ namespace Ocelot.UnitTests.Logging
 | 
			
		||||
            _listener = new OcelotDiagnosticListener(_factory.Object, _serviceProvider);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_trace_ocelot_middleware_started()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(_ => GivenAMiddlewareName())
 | 
			
		||||
                .And(_ => GivenAContext())
 | 
			
		||||
                .When(_ => WhenOcelotMiddlewareStartedCalled())
 | 
			
		||||
                .Then(_ => ThenTheLogIs($"Ocelot.MiddlewareStarted: {_name}; {_downstreamContext.HttpContext.Request.Path}"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_trace_ocelot_middleware_finished()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(_ => GivenAMiddlewareName())
 | 
			
		||||
                .And(_ => GivenAContext())
 | 
			
		||||
                .When(_ => WhenOcelotMiddlewareFinishedCalled())
 | 
			
		||||
                .Then(_ => ThenTheLogIs($"Ocelot.MiddlewareFinished: {_name}; {_downstreamContext.HttpContext.Request.Path}"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_trace_ocelot_middleware_exception()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(_ => GivenAMiddlewareName())
 | 
			
		||||
                .And(_ => GivenAContext())
 | 
			
		||||
                .And(_ => GivenAException(new Exception("oh no")))
 | 
			
		||||
                .When(_ => WhenOcelotMiddlewareExceptionCalled())
 | 
			
		||||
                .Then(_ => ThenTheLogIs($"Ocelot.MiddlewareException: {_name}; {_exception.Message};"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_trace_middleware_started()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(_ => GivenAMiddlewareName())
 | 
			
		||||
                .And(_ => GivenAContext())
 | 
			
		||||
                .When(_ => WhenMiddlewareStartedCalled())
 | 
			
		||||
                .Then(_ => ThenTheLogIs($"MiddlewareStarting: {_name}; {_downstreamContext.HttpContext.Request.Path}"))
 | 
			
		||||
                .Then(_ => ThenTheLogIs($"MiddlewareStarting: {_name}; {_httpContext.Request.Path}"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -75,9 +43,8 @@ namespace Ocelot.UnitTests.Logging
 | 
			
		||||
        public void should_trace_middleware_finished()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(_ => GivenAMiddlewareName())
 | 
			
		||||
                .And(_ => GivenAContext())
 | 
			
		||||
                .When(_ => WhenMiddlewareFinishedCalled())
 | 
			
		||||
                .Then(_ => ThenTheLogIs($"MiddlewareFinished: {_name}; {_downstreamContext.HttpContext.Response.StatusCode}"))
 | 
			
		||||
                .Then(_ => ThenTheLogIs($"MiddlewareFinished: {_name}; {_httpContext.Response.StatusCode}"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -85,7 +52,6 @@ namespace Ocelot.UnitTests.Logging
 | 
			
		||||
        public void should_trace_middleware_exception()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(_ => GivenAMiddlewareName())
 | 
			
		||||
                .And(_ => GivenAContext())
 | 
			
		||||
                .And(_ => GivenAException(new Exception("oh no")))
 | 
			
		||||
                .When(_ => WhenMiddlewareExceptionCalled())
 | 
			
		||||
                .Then(_ => ThenTheLogIs($"MiddlewareException: {_name}; {_exception.Message};"))
 | 
			
		||||
@@ -97,29 +63,14 @@ namespace Ocelot.UnitTests.Logging
 | 
			
		||||
            _exception = exception;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenOcelotMiddlewareStartedCalled()
 | 
			
		||||
        {
 | 
			
		||||
            _listener.OcelotMiddlewareStarted(_downstreamContext, _name);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenOcelotMiddlewareFinishedCalled()
 | 
			
		||||
        {
 | 
			
		||||
            _listener.OcelotMiddlewareFinished(_downstreamContext, _name);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenOcelotMiddlewareExceptionCalled()
 | 
			
		||||
        {
 | 
			
		||||
            _listener.OcelotMiddlewareException(_exception, _downstreamContext, _name);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenMiddlewareStartedCalled()
 | 
			
		||||
        {
 | 
			
		||||
            _listener.OnMiddlewareStarting(_downstreamContext.HttpContext, _name);
 | 
			
		||||
            _listener.OnMiddlewareStarting(_httpContext, _name);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenMiddlewareFinishedCalled()
 | 
			
		||||
        {
 | 
			
		||||
            _listener.OnMiddlewareFinished(_downstreamContext.HttpContext, _name);
 | 
			
		||||
            _listener.OnMiddlewareFinished(_httpContext, _name);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenMiddlewareExceptionCalled()
 | 
			
		||||
@@ -127,11 +78,6 @@ namespace Ocelot.UnitTests.Logging
 | 
			
		||||
            _listener.OnMiddlewareException(_exception, _name);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenAContext()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenAMiddlewareName()
 | 
			
		||||
        {
 | 
			
		||||
            _name = "name";
 | 
			
		||||
 
 | 
			
		||||
@@ -1,71 +0,0 @@
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Configuration.Builder;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Ocelot.Middleware.Multiplexer;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
{
 | 
			
		||||
    public class MultiplexerTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Multiplexer _multiplexer;
 | 
			
		||||
        private readonly DownstreamContext _context;
 | 
			
		||||
        private ReRoute _reRoute;
 | 
			
		||||
        private readonly OcelotRequestDelegate _pipeline;
 | 
			
		||||
        private int _count;
 | 
			
		||||
        private Mock<IResponseAggregator> _aggregator;
 | 
			
		||||
        private Mock<IResponseAggregatorFactory> _factory;
 | 
			
		||||
 | 
			
		||||
        public MultiplexerTests()
 | 
			
		||||
        {
 | 
			
		||||
            _factory = new Mock<IResponseAggregatorFactory>();
 | 
			
		||||
            _aggregator = new Mock<IResponseAggregator>();
 | 
			
		||||
            _context = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
            _pipeline = context => Task.FromResult(_count++);
 | 
			
		||||
            _factory.Setup(x => x.Get(It.IsAny<ReRoute>())).Returns(_aggregator.Object);
 | 
			
		||||
            _multiplexer = new Multiplexer(_factory.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_multiplex()
 | 
			
		||||
        {
 | 
			
		||||
            var reRoute = new ReRouteBuilder().WithDownstreamReRoute(new DownstreamReRouteBuilder().Build()).WithDownstreamReRoute(new DownstreamReRouteBuilder().Build()).Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFollowing(reRoute))
 | 
			
		||||
                .When(x => WhenIMultiplex())
 | 
			
		||||
                .Then(x => ThePipelineIsCalled(2))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_multiplex()
 | 
			
		||||
        {
 | 
			
		||||
            var reRoute = new ReRouteBuilder().WithDownstreamReRoute(new DownstreamReRouteBuilder().Build()).Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFollowing(reRoute))
 | 
			
		||||
                .When(x => WhenIMultiplex())
 | 
			
		||||
                .Then(x => ThePipelineIsCalled(1))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFollowing(ReRoute reRoute)
 | 
			
		||||
        {
 | 
			
		||||
            _reRoute = reRoute;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIMultiplex()
 | 
			
		||||
        {
 | 
			
		||||
            _multiplexer.Multiplex(_context, _reRoute, _pipeline).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThePipelineIsCalled(int expected)
 | 
			
		||||
        {
 | 
			
		||||
            _count.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,73 +0,0 @@
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Errors;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Ocelot.UnitTests.Responder;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
{
 | 
			
		||||
    public class OcelotMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private FakeMiddleware _middleware;
 | 
			
		||||
        private List<Error> _errors;
 | 
			
		||||
 | 
			
		||||
        public OcelotMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _errors = new List<Error>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _middleware = new FakeMiddleware(_logger.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_log_error()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => GivenAnError(new AnyError()))
 | 
			
		||||
                .When(x => WhenISetTheError())
 | 
			
		||||
                .Then(x => ThenTheErrorIsLogged(1))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_log_errors()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => GivenAnError(new AnyError()))
 | 
			
		||||
                .And(x => GivenAnError(new AnyError()))
 | 
			
		||||
                .When(x => WhenISetTheErrors())
 | 
			
		||||
                .Then(x => ThenTheErrorIsLogged(2))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenISetTheErrors()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.SetPipelineError(new DownstreamContext(new DefaultHttpContext()), _errors);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheErrorIsLogged(int times)
 | 
			
		||||
        {
 | 
			
		||||
            _logger.Verify(x => x.LogWarning("blahh"), Times.Exactly(times));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenISetTheError()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.SetPipelineError(new DownstreamContext(new DefaultHttpContext()), _errors[0]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenAnError(Error error)
 | 
			
		||||
        {
 | 
			
		||||
            _errors.Add(error);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class FakeMiddleware : OcelotMiddleware
 | 
			
		||||
    {
 | 
			
		||||
        public FakeMiddleware(IOcelotLogger logger)
 | 
			
		||||
            : base(logger)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Builder;
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Microsoft.Extensions.Configuration;
 | 
			
		||||
    using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
    using Ocelot.DependencyInjection;
 | 
			
		||||
@@ -7,7 +9,6 @@ namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
    using Ocelot.DownstreamUrlCreator.Middleware;
 | 
			
		||||
    using Ocelot.LoadBalancer.Middleware;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Ocelot.Middleware.Pipeline;
 | 
			
		||||
    using Ocelot.Request.Middleware;
 | 
			
		||||
    using Ocelot.WebSockets.Middleware;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
@@ -16,8 +17,8 @@ namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
 | 
			
		||||
    public class OcelotPipelineExtensionsTests
 | 
			
		||||
    {
 | 
			
		||||
        private OcelotPipelineBuilder _builder;
 | 
			
		||||
        private OcelotRequestDelegate _handlers;
 | 
			
		||||
        private ApplicationBuilder _builder;
 | 
			
		||||
        private RequestDelegate _handlers;
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_set_up_pipeline()
 | 
			
		||||
@@ -50,15 +51,14 @@ namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
        private void WhenIExpandBuild()
 | 
			
		||||
        {
 | 
			
		||||
            OcelotPipelineConfiguration configuration = new OcelotPipelineConfiguration();
 | 
			
		||||
            configuration.MapWhenOcelotPipeline.Add((app) =>
 | 
			
		||||
            //Func<HttpContext,  bool>, Action<IApplicationBuilder>
 | 
			
		||||
            configuration.MapWhenOcelotPipeline.Add((httpContext) => httpContext.WebSockets.IsWebSocketRequest, app =>
 | 
			
		||||
            {
 | 
			
		||||
                app.UseDownstreamRouteFinderMiddleware();
 | 
			
		||||
                app.UseDownstreamRequestInitialiser();
 | 
			
		||||
                app.UseLoadBalancingMiddleware();
 | 
			
		||||
                app.UseDownstreamUrlCreatorMiddleware();
 | 
			
		||||
                app.UseWebSocketsProxyMiddleware();
 | 
			
		||||
 | 
			
		||||
                return context => context.HttpContext.WebSockets.IsWebSocketRequest;
 | 
			
		||||
            });
 | 
			
		||||
            _handlers = _builder.BuildOcelotPipeline(new OcelotPipelineConfiguration());
 | 
			
		||||
        }
 | 
			
		||||
@@ -71,7 +71,7 @@ namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
            services.AddSingleton<IConfiguration>(root);
 | 
			
		||||
            services.AddOcelot();
 | 
			
		||||
            var provider = services.BuildServiceProvider();
 | 
			
		||||
            _builder = new OcelotPipelineBuilder(provider);
 | 
			
		||||
            _builder = new ApplicationBuilder(provider);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,4 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Hosting;
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
@@ -11,19 +8,22 @@ namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
    using Ocelot.DependencyInjection;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Ocelot.Middleware.Pipeline;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Reflection;
 | 
			
		||||
    using Microsoft.AspNetCore.Builder;
 | 
			
		||||
    using Ocelot.Errors.Middleware;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
    public class OcelotPiplineBuilderTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IServiceCollection _services;
 | 
			
		||||
        private readonly IConfiguration _configRoot;
 | 
			
		||||
        private DownstreamContext _downstreamContext;
 | 
			
		||||
        private int _counter;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
 | 
			
		||||
        public OcelotPiplineBuilderTests()
 | 
			
		||||
        {
 | 
			
		||||
@@ -32,6 +32,7 @@ namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
            _services.AddSingleton<IWebHostEnvironment>(GetHostingEnvironment());
 | 
			
		||||
            _services.AddSingleton<IConfiguration>(_configRoot);
 | 
			
		||||
            _services.AddOcelot();
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -64,61 +65,58 @@ namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
        private void WhenIUseAGeneric()
 | 
			
		||||
        {
 | 
			
		||||
            var provider = _services.BuildServiceProvider();
 | 
			
		||||
            IOcelotPipelineBuilder builder = new OcelotPipelineBuilder(provider);
 | 
			
		||||
            builder = builder.UseMiddleware<Ocelot.Errors.Middleware.ExceptionHandlerMiddleware>();
 | 
			
		||||
            IApplicationBuilder builder = new ApplicationBuilder(provider);
 | 
			
		||||
            builder = builder.UseMiddleware<ExceptionHandlerMiddleware>();
 | 
			
		||||
            var del = builder.Build();
 | 
			
		||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
            del.Invoke(_downstreamContext);
 | 
			
		||||
            del.Invoke(_httpContext);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheGenericIsInThePipeline()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.HttpContext.Response.StatusCode.ShouldBe(500);
 | 
			
		||||
            _httpContext.Response.StatusCode.ShouldBe(500);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIUseAFunc()
 | 
			
		||||
        {
 | 
			
		||||
            _counter = 0;
 | 
			
		||||
            var provider = _services.BuildServiceProvider();
 | 
			
		||||
            IOcelotPipelineBuilder builder = new OcelotPipelineBuilder(provider);
 | 
			
		||||
            IApplicationBuilder builder = new ApplicationBuilder(provider);
 | 
			
		||||
            builder = builder.Use(async (ctx, next) =>
 | 
			
		||||
            {
 | 
			
		||||
                _counter++;
 | 
			
		||||
                await next.Invoke();
 | 
			
		||||
            });
 | 
			
		||||
            var del = builder.Build();
 | 
			
		||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
            del.Invoke(_downstreamContext);
 | 
			
		||||
            del.Invoke(_httpContext);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheFuncIsInThePipeline()
 | 
			
		||||
        {
 | 
			
		||||
            _counter.ShouldBe(1);
 | 
			
		||||
            _downstreamContext.HttpContext.Response.StatusCode.ShouldBe(404);
 | 
			
		||||
            _httpContext.Response.StatusCode.ShouldBe(404);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void Middleware_Multi_Parameters_Invoke()
 | 
			
		||||
        {
 | 
			
		||||
            var provider = _services.BuildServiceProvider();
 | 
			
		||||
            IOcelotPipelineBuilder builder = new OcelotPipelineBuilder(provider);
 | 
			
		||||
            IApplicationBuilder builder = new ApplicationBuilder(provider);
 | 
			
		||||
            builder = builder.UseMiddleware<MultiParametersInvokeMiddleware>();
 | 
			
		||||
            var del = builder.Build();
 | 
			
		||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
            del.Invoke(_downstreamContext);
 | 
			
		||||
            del.Invoke(_httpContext);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private class MultiParametersInvokeMiddleware : OcelotMiddleware
 | 
			
		||||
        {
 | 
			
		||||
            private readonly OcelotRequestDelegate _next;
 | 
			
		||||
            private readonly RequestDelegate _next;
 | 
			
		||||
 | 
			
		||||
            public MultiParametersInvokeMiddleware(OcelotRequestDelegate next)
 | 
			
		||||
            public MultiParametersInvokeMiddleware(RequestDelegate next)
 | 
			
		||||
                : base(new FakeLogger())
 | 
			
		||||
            {
 | 
			
		||||
                _next = next;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public Task Invoke(DownstreamContext context, IServiceProvider serviceProvider)
 | 
			
		||||
            public Task Invoke(HttpContext context, IServiceProvider serviceProvider)
 | 
			
		||||
            {
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,86 +1,86 @@
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Configuration.Builder;
 | 
			
		||||
using Ocelot.Middleware.Multiplexer;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
using static Ocelot.UnitTests.Middleware.UserDefinedResponseAggregatorTests;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Configuration.Builder;
 | 
			
		||||
using Ocelot.Multiplexer;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
using static Ocelot.UnitTests.Multiplexing.UserDefinedResponseAggregatorTests;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
{
 | 
			
		||||
    public class DefinedAggregatorProviderTests
 | 
			
		||||
    {
 | 
			
		||||
        private ServiceLocatorDefinedAggregatorProvider _provider;
 | 
			
		||||
        private Response<IDefinedAggregator> _aggregator;
 | 
			
		||||
        private ReRoute _reRoute;
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_find_aggregator()
 | 
			
		||||
        {
 | 
			
		||||
            var reRoute = new ReRouteBuilder()
 | 
			
		||||
                .WithAggregator("TestDefinedAggregator")
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(_ => GivenDefinedAggregator())
 | 
			
		||||
                .And(_ => GivenReRoute(reRoute))
 | 
			
		||||
                .When(_ => WhenIGet())
 | 
			
		||||
                .Then(_ => ThenTheAggregatorIsReturned())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_find_aggregator()
 | 
			
		||||
        {
 | 
			
		||||
            var reRoute = new ReRouteBuilder()
 | 
			
		||||
                .WithAggregator("TestDefinedAggregator")
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(_ => GivenNoDefinedAggregator())
 | 
			
		||||
                .And(_ => GivenReRoute(reRoute))
 | 
			
		||||
                .When(_ => WhenIGet())
 | 
			
		||||
                .Then(_ => ThenAnErrorIsReturned())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenDefinedAggregator()
 | 
			
		||||
        {
 | 
			
		||||
            var serviceCollection = new ServiceCollection();
 | 
			
		||||
            serviceCollection.AddSingleton<IDefinedAggregator, TestDefinedAggregator>();
 | 
			
		||||
            var services = serviceCollection.BuildServiceProvider();
 | 
			
		||||
            _provider = new ServiceLocatorDefinedAggregatorProvider(services);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheAggregatorIsReturned()
 | 
			
		||||
        {
 | 
			
		||||
            _aggregator.Data.ShouldNotBeNull();
 | 
			
		||||
            _aggregator.Data.ShouldBeOfType<TestDefinedAggregator>();
 | 
			
		||||
            _aggregator.IsError.ShouldBeFalse();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenNoDefinedAggregator()
 | 
			
		||||
        {
 | 
			
		||||
            var serviceCollection = new ServiceCollection();
 | 
			
		||||
            var services = serviceCollection.BuildServiceProvider();
 | 
			
		||||
            _provider = new ServiceLocatorDefinedAggregatorProvider(services);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenReRoute(ReRoute reRoute)
 | 
			
		||||
        {
 | 
			
		||||
            _reRoute = reRoute;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIGet()
 | 
			
		||||
        {
 | 
			
		||||
            _aggregator = _provider.Get(_reRoute);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenAnErrorIsReturned()
 | 
			
		||||
        {
 | 
			
		||||
            _aggregator.IsError.ShouldBeTrue();
 | 
			
		||||
            _aggregator.Errors[0].Message.ShouldBe("Could not find Aggregator: TestDefinedAggregator");
 | 
			
		||||
            _aggregator.Errors[0].ShouldBeOfType<CouldNotFindAggregatorError>();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
namespace Ocelot.UnitTests.Multiplexing
 | 
			
		||||
{
 | 
			
		||||
    public class DefinedAggregatorProviderTests
 | 
			
		||||
    {
 | 
			
		||||
        private ServiceLocatorDefinedAggregatorProvider _provider;
 | 
			
		||||
        private Response<IDefinedAggregator> _aggregator;
 | 
			
		||||
        private ReRoute _reRoute;
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_find_aggregator()
 | 
			
		||||
        {
 | 
			
		||||
            var reRoute = new ReRouteBuilder()
 | 
			
		||||
                .WithAggregator("TestDefinedAggregator")
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(_ => GivenDefinedAggregator())
 | 
			
		||||
                .And(_ => GivenReRoute(reRoute))
 | 
			
		||||
                .When(_ => WhenIGet())
 | 
			
		||||
                .Then(_ => ThenTheAggregatorIsReturned())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_find_aggregator()
 | 
			
		||||
        {
 | 
			
		||||
            var reRoute = new ReRouteBuilder()
 | 
			
		||||
                .WithAggregator("TestDefinedAggregator")
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(_ => GivenNoDefinedAggregator())
 | 
			
		||||
                .And(_ => GivenReRoute(reRoute))
 | 
			
		||||
                .When(_ => WhenIGet())
 | 
			
		||||
                .Then(_ => ThenAnErrorIsReturned())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenDefinedAggregator()
 | 
			
		||||
        {
 | 
			
		||||
            var serviceCollection = new ServiceCollection();
 | 
			
		||||
            serviceCollection.AddSingleton<IDefinedAggregator, TestDefinedAggregator>();
 | 
			
		||||
            var services = serviceCollection.BuildServiceProvider();
 | 
			
		||||
            _provider = new ServiceLocatorDefinedAggregatorProvider(services);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheAggregatorIsReturned()
 | 
			
		||||
        {
 | 
			
		||||
            _aggregator.Data.ShouldNotBeNull();
 | 
			
		||||
            _aggregator.Data.ShouldBeOfType<TestDefinedAggregator>();
 | 
			
		||||
            _aggregator.IsError.ShouldBeFalse();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenNoDefinedAggregator()
 | 
			
		||||
        {
 | 
			
		||||
            var serviceCollection = new ServiceCollection();
 | 
			
		||||
            var services = serviceCollection.BuildServiceProvider();
 | 
			
		||||
            _provider = new ServiceLocatorDefinedAggregatorProvider(services);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenReRoute(ReRoute reRoute)
 | 
			
		||||
        {
 | 
			
		||||
            _reRoute = reRoute;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIGet()
 | 
			
		||||
        {
 | 
			
		||||
            _aggregator = _provider.Get(_reRoute);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenAnErrorIsReturned()
 | 
			
		||||
        {
 | 
			
		||||
            _aggregator.IsError.ShouldBeTrue();
 | 
			
		||||
            _aggregator.Errors[0].Message.ShouldBe("Could not find Aggregator: TestDefinedAggregator");
 | 
			
		||||
            _aggregator.Errors[0].ShouldBeOfType<CouldNotFindAggregatorError>();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,81 @@
 | 
			
		||||
namespace Ocelot.UnitTests.Multiplexing
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Ocelot.Multiplexer;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class MultiplexingMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly MultiplexingMiddleware _middleware;
 | 
			
		||||
        private DownstreamRoute _downstreamRoute;
 | 
			
		||||
        private int _count;
 | 
			
		||||
        private Mock<IResponseAggregator> _aggregator;
 | 
			
		||||
        private Mock<IResponseAggregatorFactory> _factory;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
        private RequestDelegate _next;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
 | 
			
		||||
        public MultiplexingMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
            _factory = new Mock<IResponseAggregatorFactory>();
 | 
			
		||||
            _aggregator = new Mock<IResponseAggregator>();
 | 
			
		||||
            _factory.Setup(x => x.Get(It.IsAny<ReRoute>())).Returns(_aggregator.Object);
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<MultiplexingMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _next = context => Task.FromResult(_count++);
 | 
			
		||||
            _middleware = new MultiplexingMiddleware(_next, _loggerFactory.Object, _factory.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_multiplex()
 | 
			
		||||
        {
 | 
			
		||||
            var reRoute = new ReRouteBuilder().WithDownstreamReRoute(new DownstreamReRouteBuilder().Build()).WithDownstreamReRoute(new DownstreamReRouteBuilder().Build()).Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFollowing(reRoute))
 | 
			
		||||
                .When(x => WhenIMultiplex())
 | 
			
		||||
                .Then(x => ThePipelineIsCalled(2))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_multiplex()
 | 
			
		||||
        {
 | 
			
		||||
            var reRoute = new ReRouteBuilder().WithDownstreamReRoute(new DownstreamReRouteBuilder().Build()).Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFollowing(reRoute))
 | 
			
		||||
                .When(x => WhenIMultiplex())
 | 
			
		||||
                .Then(x => ThePipelineIsCalled(1))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFollowing(ReRoute reRoute)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamRoute = new DownstreamRoute(new List<PlaceholderNameAndValue>(), reRoute);
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamRoute(_downstreamRoute);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIMultiplex()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_httpContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThePipelineIsCalled(int expected)
 | 
			
		||||
        {
 | 
			
		||||
            _count.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,65 +1,65 @@
 | 
			
		||||
namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
{
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.Middleware.Multiplexer;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class ResponseAggregatorFactoryTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly InMemoryResponseAggregatorFactory _factory;
 | 
			
		||||
        private Mock<IDefinedAggregatorProvider> _provider;
 | 
			
		||||
        private ReRoute _reRoute;
 | 
			
		||||
        private IResponseAggregator _aggregator;
 | 
			
		||||
 | 
			
		||||
        public ResponseAggregatorFactoryTests()
 | 
			
		||||
        {
 | 
			
		||||
            _provider = new Mock<IDefinedAggregatorProvider>();
 | 
			
		||||
            _aggregator = new SimpleJsonResponseAggregator();
 | 
			
		||||
            _factory = new InMemoryResponseAggregatorFactory(_provider.Object, _aggregator);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_simple_json_aggregator()
 | 
			
		||||
        {
 | 
			
		||||
            var reRoute = new ReRouteBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(_ => GivenReRoute(reRoute))
 | 
			
		||||
                .When(_ => WhenIGet())
 | 
			
		||||
                .Then(_ => ThenTheAggregatorIs<SimpleJsonResponseAggregator>())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_user_defined_aggregator()
 | 
			
		||||
        {
 | 
			
		||||
            var reRoute = new ReRouteBuilder()
 | 
			
		||||
                .WithAggregator("doesntmatter")
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(_ => GivenReRoute(reRoute))
 | 
			
		||||
                .When(_ => WhenIGet())
 | 
			
		||||
                .Then(_ => ThenTheAggregatorIs<UserDefinedResponseAggregator>())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenReRoute(ReRoute reRoute)
 | 
			
		||||
        {
 | 
			
		||||
            _reRoute = reRoute;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIGet()
 | 
			
		||||
        {
 | 
			
		||||
            _aggregator = _factory.Get(_reRoute);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheAggregatorIs<T>()
 | 
			
		||||
        {
 | 
			
		||||
            _aggregator.ShouldBeOfType<T>();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
namespace Ocelot.UnitTests.Multiplexing
 | 
			
		||||
{
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.Multiplexer;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class ResponseAggregatorFactoryTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly InMemoryResponseAggregatorFactory _factory;
 | 
			
		||||
        private Mock<IDefinedAggregatorProvider> _provider;
 | 
			
		||||
        private ReRoute _reRoute;
 | 
			
		||||
        private IResponseAggregator _aggregator;
 | 
			
		||||
 | 
			
		||||
        public ResponseAggregatorFactoryTests()
 | 
			
		||||
        {
 | 
			
		||||
            _provider = new Mock<IDefinedAggregatorProvider>();
 | 
			
		||||
            _aggregator = new SimpleJsonResponseAggregator();
 | 
			
		||||
            _factory = new InMemoryResponseAggregatorFactory(_provider.Object, _aggregator);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_simple_json_aggregator()
 | 
			
		||||
        {
 | 
			
		||||
            var reRoute = new ReRouteBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(_ => GivenReRoute(reRoute))
 | 
			
		||||
                .When(_ => WhenIGet())
 | 
			
		||||
                .Then(_ => ThenTheAggregatorIs<SimpleJsonResponseAggregator>())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_user_defined_aggregator()
 | 
			
		||||
        {
 | 
			
		||||
            var reRoute = new ReRouteBuilder()
 | 
			
		||||
                .WithAggregator("doesntmatter")
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(_ => GivenReRoute(reRoute))
 | 
			
		||||
                .When(_ => WhenIGet())
 | 
			
		||||
                .Then(_ => ThenTheAggregatorIs<UserDefinedResponseAggregator>())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenReRoute(ReRoute reRoute)
 | 
			
		||||
        {
 | 
			
		||||
            _reRoute = reRoute;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIGet()
 | 
			
		||||
        {
 | 
			
		||||
            _aggregator = _factory.Get(_reRoute);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheAggregatorIs<T>()
 | 
			
		||||
        {
 | 
			
		||||
            _aggregator.ShouldBeOfType<T>();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -4,7 +4,7 @@ using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Configuration.Builder;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Ocelot.Middleware.Multiplexer;
 | 
			
		||||
using Ocelot.Multiplexer;
 | 
			
		||||
using Ocelot.UnitTests.Responder;
 | 
			
		||||
using Ocelot.Values;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
@@ -15,13 +15,13 @@ using System.Text;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
namespace Ocelot.UnitTests.Multiplexing
 | 
			
		||||
{
 | 
			
		||||
    public class SimpleJsonResponseAggregatorTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly SimpleJsonResponseAggregator _aggregator;
 | 
			
		||||
        private List<DownstreamContext> _downstreamContexts;
 | 
			
		||||
        private DownstreamContext _upstreamContext;
 | 
			
		||||
        private List<HttpContext> _downstreamContexts;
 | 
			
		||||
        private HttpContext _upstreamContext;
 | 
			
		||||
        private ReRoute _reRoute;
 | 
			
		||||
 | 
			
		||||
        public SimpleJsonResponseAggregatorTests()
 | 
			
		||||
@@ -53,24 +53,21 @@ namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var commentsResponseContent = @"[{""id"":1,""writerId"":1,""postId"":1,""text"":""text1""},{""id"":2,""writerId"":2,""postId"":2,""text"":""text2""},{""id"":3,""writerId"":2,""postId"":1,""text"":""text21""}]";
 | 
			
		||||
            var commentsDownstreamContext = new DownstreamContext(new DefaultHttpContext())
 | 
			
		||||
            {
 | 
			
		||||
                DownstreamResponse = new DownstreamResponse(new StringContent(commentsResponseContent, Encoding.UTF8, "application/json"), HttpStatusCode.OK, new EditableList<KeyValuePair<string, IEnumerable<string>>>(), "some reason"),
 | 
			
		||||
                DownstreamReRoute = commentsDownstreamReRoute
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var commentsDownstreamContext = new DefaultHttpContext();
 | 
			
		||||
            commentsDownstreamContext.Items.UpsertDownstreamResponse(new DownstreamResponse(new StringContent(commentsResponseContent, Encoding.UTF8, "application/json"), HttpStatusCode.OK, new EditableList<KeyValuePair<string, IEnumerable<string>>>(), "some reason"));
 | 
			
		||||
            commentsDownstreamContext.Items.UpsertDownstreamReRoute(commentsDownstreamReRoute);
 | 
			
		||||
 | 
			
		||||
            var userDetailsResponseContent = @"[{""id"":1,""firstName"":""abolfazl"",""lastName"":""rajabpour""},{""id"":2,""firstName"":""reza"",""lastName"":""rezaei""}]";
 | 
			
		||||
            var userDetailsDownstreamContext = new DownstreamContext(new DefaultHttpContext())
 | 
			
		||||
            {
 | 
			
		||||
                DownstreamResponse = new DownstreamResponse(new StringContent(userDetailsResponseContent, Encoding.UTF8, "application/json"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "some reason"),
 | 
			
		||||
                DownstreamReRoute = userDetailsDownstreamReRoute
 | 
			
		||||
            };
 | 
			
		||||
            var userDetailsDownstreamContext = new DefaultHttpContext();
 | 
			
		||||
            userDetailsDownstreamContext.Items.UpsertDownstreamResponse(new DownstreamResponse(new StringContent(userDetailsResponseContent, Encoding.UTF8, "application/json"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "some reason"));
 | 
			
		||||
            userDetailsDownstreamContext.Items.UpsertDownstreamReRoute(userDetailsDownstreamReRoute);
 | 
			
		||||
 | 
			
		||||
            var downstreamContexts = new List<DownstreamContext> { commentsDownstreamContext, userDetailsDownstreamContext };
 | 
			
		||||
            var downstreamContexts = new List<HttpContext> { commentsDownstreamContext, userDetailsDownstreamContext };
 | 
			
		||||
 | 
			
		||||
            var expected = "{\"Comments\":" + commentsResponseContent + ",\"UserDetails\":" + userDetailsResponseContent + "}";
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheUpstreamContext(new DownstreamContext(new DefaultHttpContext())))
 | 
			
		||||
            this.Given(x => GivenTheUpstreamContext(new DefaultHttpContext()))
 | 
			
		||||
                .And(x => GivenTheReRoute(reRoute))
 | 
			
		||||
                .And(x => GivenTheDownstreamContext(downstreamContexts))
 | 
			
		||||
                .When(x => WhenIAggregate())
 | 
			
		||||
@@ -97,23 +94,19 @@ namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
                .WithDownstreamReRoutes(downstreamReRoutes)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var billDownstreamContext = new DownstreamContext(new DefaultHttpContext())
 | 
			
		||||
            {
 | 
			
		||||
                DownstreamResponse = new DownstreamResponse(new StringContent("Bill says hi"), HttpStatusCode.OK, new EditableList<KeyValuePair<string, IEnumerable<string>>>(), "some reason"),
 | 
			
		||||
                DownstreamReRoute = billDownstreamReRoute
 | 
			
		||||
            };
 | 
			
		||||
            var billDownstreamContext = new DefaultHttpContext();
 | 
			
		||||
            billDownstreamContext.Items.UpsertDownstreamResponse(new DownstreamResponse(new StringContent("Bill says hi"), HttpStatusCode.OK, new EditableList<KeyValuePair<string, IEnumerable<string>>>(), "some reason"));
 | 
			
		||||
            billDownstreamContext.Items.UpsertDownstreamReRoute(billDownstreamReRoute);
 | 
			
		||||
 | 
			
		||||
            var georgeDownstreamContext = new DownstreamContext(new DefaultHttpContext())
 | 
			
		||||
            {
 | 
			
		||||
                DownstreamResponse = new DownstreamResponse(new StringContent("George says hi"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "some reason"),
 | 
			
		||||
                DownstreamReRoute = georgeDownstreamReRoute
 | 
			
		||||
            };
 | 
			
		||||
            var georgeDownstreamContext = new DefaultHttpContext();
 | 
			
		||||
            georgeDownstreamContext.Items.UpsertDownstreamResponse(new DownstreamResponse(new StringContent("George says hi"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "some reason"));
 | 
			
		||||
            georgeDownstreamContext.Items.UpsertDownstreamReRoute(georgeDownstreamReRoute);
 | 
			
		||||
 | 
			
		||||
            var downstreamContexts = new List<DownstreamContext> { billDownstreamContext, georgeDownstreamContext };
 | 
			
		||||
            var downstreamContexts = new List<HttpContext> { billDownstreamContext, georgeDownstreamContext };
 | 
			
		||||
 | 
			
		||||
            var expected = "{\"Bill\":Bill says hi,\"George\":George says hi}";
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheUpstreamContext(new DownstreamContext(new DefaultHttpContext())))
 | 
			
		||||
            this.Given(x => GivenTheUpstreamContext(new DefaultHttpContext()))
 | 
			
		||||
                .And(x => GivenTheReRoute(reRoute))
 | 
			
		||||
                .And(x => GivenTheDownstreamContext(downstreamContexts))
 | 
			
		||||
                .When(x => WhenIAggregate())
 | 
			
		||||
@@ -140,25 +133,21 @@ namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
                .WithDownstreamReRoutes(downstreamReRoutes)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var billDownstreamContext = new DownstreamContext(new DefaultHttpContext())
 | 
			
		||||
            {
 | 
			
		||||
                DownstreamResponse = new DownstreamResponse(new StringContent("Bill says hi"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "some reason"),
 | 
			
		||||
                DownstreamReRoute = billDownstreamReRoute
 | 
			
		||||
            };
 | 
			
		||||
            var billDownstreamContext = new DefaultHttpContext();
 | 
			
		||||
            billDownstreamContext.Items.UpsertDownstreamResponse(new DownstreamResponse(new StringContent("Bill says hi"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "some reason"));
 | 
			
		||||
            billDownstreamContext.Items.UpsertDownstreamReRoute(billDownstreamReRoute);
 | 
			
		||||
 | 
			
		||||
            var georgeDownstreamContext = new DownstreamContext(new DefaultHttpContext())
 | 
			
		||||
            {
 | 
			
		||||
                DownstreamResponse = new DownstreamResponse(new StringContent("Error"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "some reason"),
 | 
			
		||||
                DownstreamReRoute = georgeDownstreamReRoute,
 | 
			
		||||
            };
 | 
			
		||||
            var georgeDownstreamContext = new DefaultHttpContext();
 | 
			
		||||
            georgeDownstreamContext.Items.UpsertDownstreamResponse(new DownstreamResponse(new StringContent("Error"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "some reason"));
 | 
			
		||||
            georgeDownstreamContext.Items.UpsertDownstreamReRoute(georgeDownstreamReRoute);
 | 
			
		||||
 | 
			
		||||
            georgeDownstreamContext.Errors.Add(new AnyError());
 | 
			
		||||
            georgeDownstreamContext.Items.SetError(new AnyError());
 | 
			
		||||
 | 
			
		||||
            var downstreamContexts = new List<DownstreamContext> { billDownstreamContext, georgeDownstreamContext };
 | 
			
		||||
            var downstreamContexts = new List<HttpContext> { billDownstreamContext, georgeDownstreamContext };
 | 
			
		||||
 | 
			
		||||
            var expected = "Error";
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheUpstreamContext(new DownstreamContext(new DefaultHttpContext())))
 | 
			
		||||
            this.Given(x => GivenTheUpstreamContext(new DefaultHttpContext()))
 | 
			
		||||
                .And(x => GivenTheReRoute(reRoute))
 | 
			
		||||
                .And(x => GivenTheDownstreamContext(downstreamContexts))
 | 
			
		||||
                .When(x => WhenIAggregate())
 | 
			
		||||
@@ -169,13 +158,13 @@ namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
 | 
			
		||||
        private void ThenTheReasonPhraseIs(string expected)
 | 
			
		||||
        {
 | 
			
		||||
            _upstreamContext.DownstreamResponse.ReasonPhrase.ShouldBe(expected);
 | 
			
		||||
            _upstreamContext.Items.DownstreamResponse().ReasonPhrase.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheErrorIsMapped()
 | 
			
		||||
        {
 | 
			
		||||
            _upstreamContext.Errors.ShouldBe(_downstreamContexts[1].Errors);
 | 
			
		||||
            _upstreamContext.DownstreamResponse.ShouldBe(_downstreamContexts[1].DownstreamResponse);
 | 
			
		||||
            _upstreamContext.Items.Errors().ShouldBe(_downstreamContexts[1].Items.Errors());
 | 
			
		||||
            _upstreamContext.Items.DownstreamResponse().ShouldBe(_downstreamContexts[1].Items.DownstreamResponse());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheReRoute(ReRoute reRoute)
 | 
			
		||||
@@ -183,12 +172,12 @@ namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
            _reRoute = reRoute;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheUpstreamContext(DownstreamContext upstreamContext)
 | 
			
		||||
        private void GivenTheUpstreamContext(HttpContext upstreamContext)
 | 
			
		||||
        {
 | 
			
		||||
            _upstreamContext = upstreamContext;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownstreamContext(List<DownstreamContext> downstreamContexts)
 | 
			
		||||
        private void GivenTheDownstreamContext(List<HttpContext> downstreamContexts)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContexts = downstreamContexts;
 | 
			
		||||
        }
 | 
			
		||||
@@ -200,7 +189,7 @@ namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
 | 
			
		||||
        private void ThenTheContentIs(string expected)
 | 
			
		||||
        {
 | 
			
		||||
            var content = _upstreamContext.DownstreamResponse.Content.ReadAsStringAsync()
 | 
			
		||||
            var content = _upstreamContext.Items.DownstreamResponse().Content.ReadAsStringAsync()
 | 
			
		||||
                .GetAwaiter()
 | 
			
		||||
                .GetResult();
 | 
			
		||||
 | 
			
		||||
@@ -209,14 +198,14 @@ namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
 | 
			
		||||
        private void ThenTheContentTypeIs(string expected)
 | 
			
		||||
        {
 | 
			
		||||
            _upstreamContext.DownstreamResponse.Content.Headers.ContentType.MediaType.ShouldBe(expected);
 | 
			
		||||
            _upstreamContext.Items.DownstreamResponse().Content.Headers.ContentType.MediaType.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheUpstreamContextIsMappedForNonAggregate()
 | 
			
		||||
        {
 | 
			
		||||
            _upstreamContext.DownstreamRequest.ShouldBe(_downstreamContexts[0].DownstreamRequest);
 | 
			
		||||
            _upstreamContext.DownstreamResponse.ShouldBe(_downstreamContexts[0].DownstreamResponse);
 | 
			
		||||
            _upstreamContext.Errors.ShouldBe(_downstreamContexts[0].Errors);
 | 
			
		||||
            _upstreamContext.Items.DownstreamRequest().ShouldBe(_downstreamContexts[0].Items.DownstreamRequest());
 | 
			
		||||
            _upstreamContext.Items.DownstreamRequest().ShouldBe(_downstreamContexts[0].Items.DownstreamRequest());
 | 
			
		||||
            _upstreamContext.Items.Errors().ShouldBe(_downstreamContexts[0].Items.Errors());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,29 +1,29 @@
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Configuration.Builder;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Ocelot.Middleware.Multiplexer;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Ocelot.UnitTests.Responder;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Net;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
namespace Ocelot.UnitTests.Multiplexing
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Ocelot.Multiplexer;
 | 
			
		||||
    using Ocelot.Responses;
 | 
			
		||||
    using Ocelot.UnitTests.Responder;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Linq;
 | 
			
		||||
    using System.Net;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class UserDefinedResponseAggregatorTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly UserDefinedResponseAggregator _aggregator;
 | 
			
		||||
        private readonly Mock<IDefinedAggregatorProvider> _provider;
 | 
			
		||||
        private ReRoute _reRoute;
 | 
			
		||||
        private List<DownstreamContext> _contexts;
 | 
			
		||||
        private DownstreamContext _context;
 | 
			
		||||
        private List<HttpContext> _contexts;
 | 
			
		||||
        private HttpContext _context;
 | 
			
		||||
 | 
			
		||||
        public UserDefinedResponseAggregatorTests()
 | 
			
		||||
        {
 | 
			
		||||
@@ -36,18 +36,18 @@ namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
        {
 | 
			
		||||
            var reRoute = new ReRouteBuilder().Build();
 | 
			
		||||
 | 
			
		||||
            var context = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
            var context = new DefaultHttpContext();
 | 
			
		||||
 | 
			
		||||
            var contexts = new List<DownstreamContext>
 | 
			
		||||
            var contextA = new DefaultHttpContext();
 | 
			
		||||
            contextA.Items.UpsertDownstreamResponse(new DownstreamResponse(new StringContent("Tom"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "some reason"));
 | 
			
		||||
 | 
			
		||||
            var contextB = new DefaultHttpContext();
 | 
			
		||||
            contextB.Items.UpsertDownstreamResponse(new DownstreamResponse(new StringContent("Laura"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "some reason"));
 | 
			
		||||
 | 
			
		||||
            var contexts = new List<HttpContext>()
 | 
			
		||||
            {
 | 
			
		||||
                new DownstreamContext(new DefaultHttpContext())
 | 
			
		||||
                {
 | 
			
		||||
                    DownstreamResponse = new DownstreamResponse(new StringContent("Tom"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "some reason")
 | 
			
		||||
                },
 | 
			
		||||
                new DownstreamContext(new DefaultHttpContext())
 | 
			
		||||
                {
 | 
			
		||||
                    DownstreamResponse = new DownstreamResponse(new StringContent("Laura"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "some reason")
 | 
			
		||||
                }
 | 
			
		||||
                contextA,
 | 
			
		||||
                contextB,
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(_ => GivenTheProviderReturnsAggregator())
 | 
			
		||||
@@ -65,18 +65,18 @@ namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
        {
 | 
			
		||||
            var reRoute = new ReRouteBuilder().Build();
 | 
			
		||||
 | 
			
		||||
            var context = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
            var context = new DefaultHttpContext();
 | 
			
		||||
 | 
			
		||||
            var contexts = new List<DownstreamContext>
 | 
			
		||||
            var contextA = new DefaultHttpContext();
 | 
			
		||||
            contextA.Items.UpsertDownstreamResponse(new DownstreamResponse(new StringContent("Tom"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "some reason"));
 | 
			
		||||
 | 
			
		||||
            var contextB = new DefaultHttpContext();
 | 
			
		||||
            contextB.Items.UpsertDownstreamResponse(new DownstreamResponse(new StringContent("Laura"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "some reason"));
 | 
			
		||||
 | 
			
		||||
            var contexts = new List<HttpContext>()
 | 
			
		||||
            {
 | 
			
		||||
                new DownstreamContext(new DefaultHttpContext())
 | 
			
		||||
                {
 | 
			
		||||
                    DownstreamResponse = new DownstreamResponse(new StringContent("Tom"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "some reason")
 | 
			
		||||
                },
 | 
			
		||||
                new DownstreamContext(new DefaultHttpContext())
 | 
			
		||||
                {
 | 
			
		||||
                    DownstreamResponse = new DownstreamResponse(new StringContent("Laura"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "some reason")
 | 
			
		||||
                }
 | 
			
		||||
                contextA,
 | 
			
		||||
                contextB,
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(_ => GivenTheProviderReturnsError())
 | 
			
		||||
@@ -91,8 +91,8 @@ namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
 | 
			
		||||
        private void ThenTheErrorIsReturned()
 | 
			
		||||
        {
 | 
			
		||||
            _context.IsError.ShouldBeTrue();
 | 
			
		||||
            _context.Errors.Count.ShouldBe(1);
 | 
			
		||||
            _context.Items.Errors().Count.ShouldBeGreaterThan(0);
 | 
			
		||||
            _context.Items.Errors().Count.ShouldBe(1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheProviderReturnsError()
 | 
			
		||||
@@ -102,7 +102,7 @@ namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
 | 
			
		||||
        private async Task ThenTheContentIsCorrect()
 | 
			
		||||
        {
 | 
			
		||||
            var content = await _context.DownstreamResponse.Content.ReadAsStringAsync();
 | 
			
		||||
            var content = await _context.Items.DownstreamResponse().Content.ReadAsStringAsync();
 | 
			
		||||
            content.ShouldBe("Tom, Laura");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -111,12 +111,12 @@ namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
            _provider.Verify(x => x.Get(_reRoute), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenContext(DownstreamContext context)
 | 
			
		||||
        private void GivenContext(HttpContext context)
 | 
			
		||||
        {
 | 
			
		||||
            _context = context;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenContexts(List<DownstreamContext> contexts)
 | 
			
		||||
        private void GivenContexts(List<HttpContext> contexts)
 | 
			
		||||
        {
 | 
			
		||||
            _contexts = contexts;
 | 
			
		||||
        }
 | 
			
		||||
@@ -139,12 +139,12 @@ namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
 | 
			
		||||
        public class TestDefinedAggregator : IDefinedAggregator
 | 
			
		||||
        {
 | 
			
		||||
            public async Task<DownstreamResponse> Aggregate(List<DownstreamContext> responses)
 | 
			
		||||
            public async Task<DownstreamResponse> Aggregate(List<HttpContext> responses)
 | 
			
		||||
            {
 | 
			
		||||
                var tom = await responses[0].DownstreamResponse.Content.ReadAsStringAsync();
 | 
			
		||||
                var laura = await responses[1].DownstreamResponse.Content.ReadAsStringAsync();
 | 
			
		||||
                var tom = await responses[0].Items.DownstreamResponse().Content.ReadAsStringAsync();
 | 
			
		||||
                var laura = await responses[1].Items.DownstreamResponse().Content.ReadAsStringAsync();
 | 
			
		||||
                var content = $"{tom}, {laura}";
 | 
			
		||||
                var headers = responses.SelectMany(x => x.DownstreamResponse.Headers).ToList();
 | 
			
		||||
                var headers = responses.SelectMany(x => x.Items.DownstreamResponse().Headers).ToList();
 | 
			
		||||
                return new DownstreamResponse(new StringContent(content), HttpStatusCode.OK, headers, "some reason");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -1,194 +1,194 @@
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Errors;
 | 
			
		||||
using Ocelot.Infrastructure.Claims.Parser;
 | 
			
		||||
using Ocelot.QueryStrings;
 | 
			
		||||
using Ocelot.Request.Middleware;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Security.Claims;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.QueryStrings
 | 
			
		||||
{
 | 
			
		||||
    public class AddQueriesToRequestTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly AddQueriesToRequest _addQueriesToRequest;
 | 
			
		||||
        private DownstreamRequest _downstreamRequest;
 | 
			
		||||
        private readonly Mock<IClaimsParser> _parser;
 | 
			
		||||
        private List<ClaimToThing> _configuration;
 | 
			
		||||
        private List<Claim> _claims;
 | 
			
		||||
        private Response _result;
 | 
			
		||||
        private Response<string> _claimValue;
 | 
			
		||||
        private HttpRequestMessage _request;
 | 
			
		||||
 | 
			
		||||
        public AddQueriesToRequestTests()
 | 
			
		||||
        {
 | 
			
		||||
            _request = new HttpRequestMessage(HttpMethod.Post, "http://my.url/abc?q=123");
 | 
			
		||||
            _parser = new Mock<IClaimsParser>();
 | 
			
		||||
            _addQueriesToRequest = new AddQueriesToRequest(_parser.Object);
 | 
			
		||||
            _downstreamRequest = new DownstreamRequest(_request);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_new_queries_to_downstream_request()
 | 
			
		||||
        {
 | 
			
		||||
            var claims = new List<Claim>
 | 
			
		||||
            {
 | 
			
		||||
                new Claim("test", "data")
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(
 | 
			
		||||
                x => x.GivenAClaimToThing(new List<ClaimToThing>
 | 
			
		||||
                {
 | 
			
		||||
                    new ClaimToThing("query-key", "", "", 0)
 | 
			
		||||
                }))
 | 
			
		||||
                .Given(x => x.GivenClaims(claims))
 | 
			
		||||
                .And(x => x.GivenTheClaimParserReturns(new OkResponse<string>("value")))
 | 
			
		||||
                .When(x => x.WhenIAddQueriesToTheRequest())
 | 
			
		||||
                .Then(x => x.ThenTheResultIsSuccess())
 | 
			
		||||
                .And(x => x.ThenTheQueryIsAdded())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_new_queries_to_downstream_request_and_preserve_other_queries()
 | 
			
		||||
        {
 | 
			
		||||
            var claims = new List<Claim>
 | 
			
		||||
            {
 | 
			
		||||
                new Claim("test", "data")
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(
 | 
			
		||||
                x => x.GivenAClaimToThing(new List<ClaimToThing>
 | 
			
		||||
                {
 | 
			
		||||
                    new ClaimToThing("query-key", "", "", 0)
 | 
			
		||||
                }))
 | 
			
		||||
                .Given(x => x.GivenClaims(claims))
 | 
			
		||||
                .And(x => GivenTheDownstreamRequestHasQueryString("?test=1&test=2"))
 | 
			
		||||
                .And(x => x.GivenTheClaimParserReturns(new OkResponse<string>("value")))
 | 
			
		||||
                .When(x => x.WhenIAddQueriesToTheRequest())
 | 
			
		||||
                .Then(x => x.ThenTheResultIsSuccess())
 | 
			
		||||
                .And(x => x.ThenTheQueryIsAdded())
 | 
			
		||||
                .And(x => TheTheQueryStringIs("?test=1&test=2&query-key=value"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void TheTheQueryStringIs(string expected)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamRequest.Query.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_replace_existing_queries_on_downstream_request()
 | 
			
		||||
        {
 | 
			
		||||
            var claims = new List<Claim>
 | 
			
		||||
            {
 | 
			
		||||
                new Claim("test", "data")
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(
 | 
			
		||||
                x => x.GivenAClaimToThing(new List<ClaimToThing>
 | 
			
		||||
                {
 | 
			
		||||
                    new ClaimToThing("query-key", "", "", 0)
 | 
			
		||||
                }))
 | 
			
		||||
                .And(x => x.GivenClaims(claims))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRequestHasQueryString("query-key", "initial"))
 | 
			
		||||
                .And(x => x.GivenTheClaimParserReturns(new OkResponse<string>("value")))
 | 
			
		||||
                .When(x => x.WhenIAddQueriesToTheRequest())
 | 
			
		||||
                .Then(x => x.ThenTheResultIsSuccess())
 | 
			
		||||
                .And(x => x.ThenTheQueryIsAdded())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_error()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(
 | 
			
		||||
               x => x.GivenAClaimToThing(new List<ClaimToThing>
 | 
			
		||||
               {
 | 
			
		||||
                    new ClaimToThing("", "", "", 0)
 | 
			
		||||
               }))
 | 
			
		||||
               .Given(x => x.GivenClaims(new List<Claim>()))
 | 
			
		||||
               .And(x => x.GivenTheClaimParserReturns(new ErrorResponse<string>(new List<Error>
 | 
			
		||||
               {
 | 
			
		||||
                   new AnyError()
 | 
			
		||||
               })))
 | 
			
		||||
               .When(x => x.WhenIAddQueriesToTheRequest())
 | 
			
		||||
               .Then(x => x.ThenTheResultIsError())
 | 
			
		||||
               .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheQueryIsAdded()
 | 
			
		||||
        {
 | 
			
		||||
            var queries = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(_downstreamRequest.ToHttpRequestMessage().RequestUri.OriginalString);
 | 
			
		||||
            var query = queries.First(x => x.Key == "query-key");
 | 
			
		||||
            query.Value.First().ShouldBe(_claimValue.Data);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenAClaimToThing(List<ClaimToThing> configuration)
 | 
			
		||||
        {
 | 
			
		||||
            _configuration = configuration;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenClaims(List<Claim> claims)
 | 
			
		||||
        {
 | 
			
		||||
            _claims = claims;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownstreamRequestHasQueryString(string queryString)
 | 
			
		||||
        {
 | 
			
		||||
            _request = new HttpRequestMessage(HttpMethod.Post, $"http://my.url/abc{queryString}");
 | 
			
		||||
            _downstreamRequest = new DownstreamRequest(_request);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownstreamRequestHasQueryString(string key, string value)
 | 
			
		||||
        {
 | 
			
		||||
            var newUri = Microsoft.AspNetCore.WebUtilities.QueryHelpers
 | 
			
		||||
                .AddQueryString(_downstreamRequest.ToHttpRequestMessage().RequestUri.OriginalString, key, value);
 | 
			
		||||
 | 
			
		||||
            _request.RequestUri = new Uri(newUri);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheClaimParserReturns(Response<string> claimValue)
 | 
			
		||||
        {
 | 
			
		||||
            _claimValue = claimValue;
 | 
			
		||||
            _parser
 | 
			
		||||
                .Setup(
 | 
			
		||||
                    x =>
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Errors;
 | 
			
		||||
using Ocelot.Infrastructure.Claims.Parser;
 | 
			
		||||
using Ocelot.QueryStrings;
 | 
			
		||||
using Ocelot.Request.Middleware;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Security.Claims;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.QueryStrings
 | 
			
		||||
{
 | 
			
		||||
    public class AddQueriesToRequestTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly AddQueriesToRequest _addQueriesToRequest;
 | 
			
		||||
        private DownstreamRequest _downstreamRequest;
 | 
			
		||||
        private readonly Mock<IClaimsParser> _parser;
 | 
			
		||||
        private List<ClaimToThing> _configuration;
 | 
			
		||||
        private List<Claim> _claims;
 | 
			
		||||
        private Response _result;
 | 
			
		||||
        private Response<string> _claimValue;
 | 
			
		||||
        private HttpRequestMessage _request;
 | 
			
		||||
 | 
			
		||||
        public AddQueriesToRequestTests()
 | 
			
		||||
        {
 | 
			
		||||
            _request = new HttpRequestMessage(HttpMethod.Post, "http://my.url/abc?q=123");
 | 
			
		||||
            _parser = new Mock<IClaimsParser>();
 | 
			
		||||
            _addQueriesToRequest = new AddQueriesToRequest(_parser.Object);
 | 
			
		||||
            _downstreamRequest = new DownstreamRequest(_request);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_new_queries_to_downstream_request()
 | 
			
		||||
        {
 | 
			
		||||
            var claims = new List<Claim>
 | 
			
		||||
            {
 | 
			
		||||
                new Claim("test", "data")
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(
 | 
			
		||||
                x => x.GivenAClaimToThing(new List<ClaimToThing>
 | 
			
		||||
                {
 | 
			
		||||
                    new ClaimToThing("query-key", "", "", 0)
 | 
			
		||||
                }))
 | 
			
		||||
                .Given(x => x.GivenClaims(claims))
 | 
			
		||||
                .And(x => x.GivenTheClaimParserReturns(new OkResponse<string>("value")))
 | 
			
		||||
                .When(x => x.WhenIAddQueriesToTheRequest())
 | 
			
		||||
                .Then(x => x.ThenTheResultIsSuccess())
 | 
			
		||||
                .And(x => x.ThenTheQueryIsAdded())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_new_queries_to_downstream_request_and_preserve_other_queries()
 | 
			
		||||
        {
 | 
			
		||||
            var claims = new List<Claim>
 | 
			
		||||
            {
 | 
			
		||||
                new Claim("test", "data")
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(
 | 
			
		||||
                x => x.GivenAClaimToThing(new List<ClaimToThing>
 | 
			
		||||
                {
 | 
			
		||||
                    new ClaimToThing("query-key", "", "", 0)
 | 
			
		||||
                }))
 | 
			
		||||
                .Given(x => x.GivenClaims(claims))
 | 
			
		||||
                .And(x => GivenTheDownstreamRequestHasQueryString("?test=1&test=2"))
 | 
			
		||||
                .And(x => x.GivenTheClaimParserReturns(new OkResponse<string>("value")))
 | 
			
		||||
                .When(x => x.WhenIAddQueriesToTheRequest())
 | 
			
		||||
                .Then(x => x.ThenTheResultIsSuccess())
 | 
			
		||||
                .And(x => x.ThenTheQueryIsAdded())
 | 
			
		||||
                .And(x => TheTheQueryStringIs("?test=1&test=2&query-key=value"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void TheTheQueryStringIs(string expected)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamRequest.Query.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_replace_existing_queries_on_downstream_request()
 | 
			
		||||
        {
 | 
			
		||||
            var claims = new List<Claim>
 | 
			
		||||
            {
 | 
			
		||||
                new Claim("test", "data")
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(
 | 
			
		||||
                x => x.GivenAClaimToThing(new List<ClaimToThing>
 | 
			
		||||
                {
 | 
			
		||||
                    new ClaimToThing("query-key", "", "", 0)
 | 
			
		||||
                }))
 | 
			
		||||
                .And(x => x.GivenClaims(claims))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRequestHasQueryString("query-key", "initial"))
 | 
			
		||||
                .And(x => x.GivenTheClaimParserReturns(new OkResponse<string>("value")))
 | 
			
		||||
                .When(x => x.WhenIAddQueriesToTheRequest())
 | 
			
		||||
                .Then(x => x.ThenTheResultIsSuccess())
 | 
			
		||||
                .And(x => x.ThenTheQueryIsAdded())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_error()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(
 | 
			
		||||
               x => x.GivenAClaimToThing(new List<ClaimToThing>
 | 
			
		||||
               {
 | 
			
		||||
                    new ClaimToThing("", "", "", 0)
 | 
			
		||||
               }))
 | 
			
		||||
               .Given(x => x.GivenClaims(new List<Claim>()))
 | 
			
		||||
               .And(x => x.GivenTheClaimParserReturns(new ErrorResponse<string>(new List<Error>
 | 
			
		||||
               {
 | 
			
		||||
                   new AnyError()
 | 
			
		||||
               })))
 | 
			
		||||
               .When(x => x.WhenIAddQueriesToTheRequest())
 | 
			
		||||
               .Then(x => x.ThenTheResultIsError())
 | 
			
		||||
               .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheQueryIsAdded()
 | 
			
		||||
        {
 | 
			
		||||
            var queries = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(_downstreamRequest.ToHttpRequestMessage().RequestUri.OriginalString);
 | 
			
		||||
            var query = queries.First(x => x.Key == "query-key");
 | 
			
		||||
            query.Value.First().ShouldBe(_claimValue.Data);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenAClaimToThing(List<ClaimToThing> configuration)
 | 
			
		||||
        {
 | 
			
		||||
            _configuration = configuration;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenClaims(List<Claim> claims)
 | 
			
		||||
        {
 | 
			
		||||
            _claims = claims;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownstreamRequestHasQueryString(string queryString)
 | 
			
		||||
        {
 | 
			
		||||
            _request = new HttpRequestMessage(HttpMethod.Post, $"http://my.url/abc{queryString}");
 | 
			
		||||
            _downstreamRequest = new DownstreamRequest(_request);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownstreamRequestHasQueryString(string key, string value)
 | 
			
		||||
        {
 | 
			
		||||
            var newUri = Microsoft.AspNetCore.WebUtilities.QueryHelpers
 | 
			
		||||
                .AddQueryString(_downstreamRequest.ToHttpRequestMessage().RequestUri.OriginalString, key, value);
 | 
			
		||||
 | 
			
		||||
            _request.RequestUri = new Uri(newUri);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheClaimParserReturns(Response<string> claimValue)
 | 
			
		||||
        {
 | 
			
		||||
            _claimValue = claimValue;
 | 
			
		||||
            _parser
 | 
			
		||||
                .Setup(
 | 
			
		||||
                    x =>
 | 
			
		||||
                        x.GetValue(It.IsAny<IEnumerable<Claim>>(),
 | 
			
		||||
                        It.IsAny<string>(),
 | 
			
		||||
                        It.IsAny<string>(),
 | 
			
		||||
                        It.IsAny<int>()))
 | 
			
		||||
                .Returns(_claimValue);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIAddQueriesToTheRequest()
 | 
			
		||||
        {
 | 
			
		||||
            _result = _addQueriesToRequest.SetQueriesOnDownstreamRequest(_configuration, _claims, _downstreamRequest);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheResultIsSuccess()
 | 
			
		||||
        {
 | 
			
		||||
            _result.IsError.ShouldBe(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheResultIsError()
 | 
			
		||||
        {
 | 
			
		||||
            _result.IsError.ShouldBe(true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private class AnyError : Error
 | 
			
		||||
        {
 | 
			
		||||
                        It.IsAny<string>(),
 | 
			
		||||
                        It.IsAny<int>()))
 | 
			
		||||
                .Returns(_claimValue);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIAddQueriesToTheRequest()
 | 
			
		||||
        {
 | 
			
		||||
            _result = _addQueriesToRequest.SetQueriesOnDownstreamRequest(_configuration, _claims, _downstreamRequest);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheResultIsSuccess()
 | 
			
		||||
        {
 | 
			
		||||
            _result.IsError.ShouldBe(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheResultIsError()
 | 
			
		||||
        {
 | 
			
		||||
            _result.IsError.ShouldBe(true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private class AnyError : Error
 | 
			
		||||
        {
 | 
			
		||||
            public AnyError()
 | 
			
		||||
                : base("blahh", OcelotErrorCode.UnknownError)
 | 
			
		||||
            {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
                : base("blahh", OcelotErrorCode.UnknownError, 404)
 | 
			
		||||
            {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,97 +1,102 @@
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.QueryStrings
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.QueryStrings;
 | 
			
		||||
    using Ocelot.QueryStrings.Middleware;
 | 
			
		||||
    using Ocelot.Request.Middleware;
 | 
			
		||||
    using Ocelot.Responses;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Security.Claims;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.QueryStrings
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.QueryStrings;
 | 
			
		||||
    using Ocelot.QueryStrings.Middleware;
 | 
			
		||||
    using Ocelot.Request.Middleware;
 | 
			
		||||
    using Ocelot.Responses;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Security.Claims;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using Ocelot.Infrastructure.RequestData;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
 | 
			
		||||
    public class ClaimsToQueryStringMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Mock<IAddQueriesToRequest> _addQueries;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private ClaimsToQueryStringMiddleware _middleware;
 | 
			
		||||
        private DownstreamContext _downstreamContext;
 | 
			
		||||
        private OcelotRequestDelegate _next;
 | 
			
		||||
 | 
			
		||||
        public ClaimsToQueryStringMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<ClaimsToQueryStringMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _next = context => Task.CompletedTask;
 | 
			
		||||
    public class ClaimsToQueryStringMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Mock<IAddQueriesToRequest> _addQueries;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private ClaimsToQueryStringMiddleware _middleware;
 | 
			
		||||
        private RequestDelegate _next;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
        private Mock<IRequestScopedDataRepository> _repo;
 | 
			
		||||
 | 
			
		||||
        public ClaimsToQueryStringMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _repo = new Mock<IRequestScopedDataRepository>();
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<ClaimsToQueryStringMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _next = context => Task.CompletedTask;
 | 
			
		||||
            _addQueries = new Mock<IAddQueriesToRequest>();
 | 
			
		||||
            _downstreamContext.DownstreamRequest = new DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "http://test.com"));
 | 
			
		||||
            _middleware = new ClaimsToQueryStringMiddleware(_next, _loggerFactory.Object, _addQueries.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_add_queries_correctly()
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamRequest(new DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "http://test.com")));
 | 
			
		||||
            _middleware = new ClaimsToQueryStringMiddleware(_next, _loggerFactory.Object, _addQueries.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_add_queries_correctly()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamReRoute(new DownstreamReRouteBuilder()
 | 
			
		||||
                        .WithDownstreamPathTemplate("any old string")
 | 
			
		||||
                        .WithClaimsToQueries(new List<ClaimToThing>
 | 
			
		||||
                        {
 | 
			
		||||
                            new ClaimToThing("UserId", "Subject", "", 0)
 | 
			
		||||
                        })
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .Build())
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
                .And(x => x.GivenTheAddHeadersToRequestReturnsOk())
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheAddQueriesToRequestIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_httpContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheAddHeadersToRequestReturnsOk()
 | 
			
		||||
        {
 | 
			
		||||
            _addQueries
 | 
			
		||||
                .Setup(x => x.SetQueriesOnDownstreamRequest(
 | 
			
		||||
                    It.IsAny<List<ClaimToThing>>(),
 | 
			
		||||
                    It.IsAny<IEnumerable<Claim>>(),
 | 
			
		||||
                    It.IsAny<DownstreamRequest>()))
 | 
			
		||||
                .Returns(new OkResponse());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheAddQueriesToRequestIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _addQueries
 | 
			
		||||
                .Verify(x => x.SetQueriesOnDownstreamRequest(
 | 
			
		||||
                    It.IsAny<List<ClaimToThing>>(),
 | 
			
		||||
                    It.IsAny<IEnumerable<Claim>>(),
 | 
			
		||||
                    _httpContext.Items.DownstreamRequest()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute)
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamReRoute(new DownstreamReRouteBuilder()
 | 
			
		||||
                        .WithDownstreamPathTemplate("any old string")
 | 
			
		||||
                        .WithClaimsToQueries(new List<ClaimToThing>
 | 
			
		||||
                        {
 | 
			
		||||
                            new ClaimToThing("UserId", "Subject", "", 0)
 | 
			
		||||
                        })
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .Build())
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                    .Build());
 | 
			
		||||
            _httpContext.Items.UpsertTemplatePlaceholderNameAndValues(downstreamRoute.TemplatePlaceholderNameAndValues);
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
                .And(x => x.GivenTheAddHeadersToRequestReturnsOk())
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheAddQueriesToRequestIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheAddHeadersToRequestReturnsOk()
 | 
			
		||||
        {
 | 
			
		||||
            _addQueries
 | 
			
		||||
                .Setup(x => x.SetQueriesOnDownstreamRequest(
 | 
			
		||||
                    It.IsAny<List<ClaimToThing>>(),
 | 
			
		||||
                    It.IsAny<IEnumerable<Claim>>(),
 | 
			
		||||
                    It.IsAny<DownstreamRequest>()))
 | 
			
		||||
                .Returns(new OkResponse());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheAddQueriesToRequestIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _addQueries
 | 
			
		||||
                .Verify(x => x.SetQueriesOnDownstreamRequest(
 | 
			
		||||
                    It.IsAny<List<ClaimToThing>>(),
 | 
			
		||||
                    It.IsAny<IEnumerable<Claim>>(),
 | 
			
		||||
                    _downstreamContext.DownstreamRequest), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.TemplatePlaceholderNameAndValues = downstreamRoute.TemplatePlaceholderNameAndValues;
 | 
			
		||||
            _downstreamContext.DownstreamReRoute = downstreamRoute.ReRoute.DownstreamReRoute[0];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamReRoute(downstreamRoute.ReRoute.DownstreamReRoute[0]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,179 +1,186 @@
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.RateLimit
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Microsoft.Extensions.Caching.Memory;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.RateLimit;
 | 
			
		||||
    using Ocelot.RateLimit.Middleware;
 | 
			
		||||
    using Ocelot.Request.Middleware;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.IO;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class ClientRateLimitMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private int _responseStatusCode;
 | 
			
		||||
        private IRateLimitCounterHandler _rateLimitCounterHandler;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private readonly ClientRateLimitMiddleware _middleware;
 | 
			
		||||
        private readonly DownstreamContext _downstreamContext;
 | 
			
		||||
        private OcelotRequestDelegate _next;
 | 
			
		||||
        private readonly string _url;
 | 
			
		||||
 | 
			
		||||
        public ClientRateLimitMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _url = "http://localhost:51879";
 | 
			
		||||
            var cacheEntryOptions = new MemoryCacheOptions();
 | 
			
		||||
            _rateLimitCounterHandler = new MemoryCacheRateLimitCounterHandler(new MemoryCache(cacheEntryOptions));
 | 
			
		||||
            var httpContext = new DefaultHttpContext();
 | 
			
		||||
            _downstreamContext = new DownstreamContext(httpContext);
 | 
			
		||||
            _downstreamContext.HttpContext.Response.Body = new FakeStream();
 | 
			
		||||
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<ClientRateLimitMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _next = context => Task.CompletedTask;
 | 
			
		||||
            _middleware = new ClientRateLimitMiddleware(_next, _loggerFactory.Object, _rateLimitCounterHandler);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_middleware_and_ratelimiting()
 | 
			
		||||
        {
 | 
			
		||||
            var upstreamTemplate = new UpstreamPathTemplateBuilder().Build();
 | 
			
		||||
 | 
			
		||||
            var downstreamReRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithEnableRateLimiting(true)
 | 
			
		||||
                .WithRateLimitOptions(new RateLimitOptions(true, "ClientId", () => new List<string>(), false, "", "", new RateLimitRule("1s", 100, 3), 429))
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                .WithUpstreamPathTemplate(upstreamTemplate)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new ReRouteBuilder()
 | 
			
		||||
                .WithDownstreamReRoute(downstreamReRoute)
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<Ocelot.DownstreamRouteFinder.UrlMatcher.PlaceholderNameAndValue>(), reRoute);
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddlewareMultipleTime(2))
 | 
			
		||||
                .Then(x => x.ThenresponseStatusCodeIs200())
 | 
			
		||||
                .When(x => x.WhenICallTheMiddlewareMultipleTime(3))
 | 
			
		||||
                .Then(x => x.ThenresponseStatusCodeIs429())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_middleware_withWhitelistClient()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<Ocelot.DownstreamRouteFinder.UrlMatcher.PlaceholderNameAndValue>(),
 | 
			
		||||
                 new ReRouteBuilder()
 | 
			
		||||
                     .WithDownstreamReRoute(new DownstreamReRouteBuilder()
 | 
			
		||||
                         .WithEnableRateLimiting(true)
 | 
			
		||||
                         .WithRateLimitOptions(
 | 
			
		||||
                             new Ocelot.Configuration.RateLimitOptions(true, "ClientId", () => new List<string>() { "ocelotclient2" }, false, "", "", new RateLimitRule("1s", 100, 3), 429))
 | 
			
		||||
                         .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                         .Build())
 | 
			
		||||
                     .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                     .Build());
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddlewareWithWhiteClient())
 | 
			
		||||
                .Then(x => x.ThenresponseStatusCodeIs200())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.TemplatePlaceholderNameAndValues = downstreamRoute.TemplatePlaceholderNameAndValues;
 | 
			
		||||
            _downstreamContext.DownstreamReRoute = downstreamRoute.ReRoute.DownstreamReRoute[0];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddlewareMultipleTime(int times)
 | 
			
		||||
        {
 | 
			
		||||
            var clientId = "ocelotclient1";
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < times; i++)
 | 
			
		||||
            {
 | 
			
		||||
                var request = new HttpRequestMessage(new HttpMethod("GET"), _url);
 | 
			
		||||
                request.Headers.Add("ClientId", clientId);
 | 
			
		||||
                _downstreamContext.DownstreamRequest = new DownstreamRequest(request);
 | 
			
		||||
 | 
			
		||||
                _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
 | 
			
		||||
                _responseStatusCode = (int)_downstreamContext.HttpContext.Response.StatusCode;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddlewareWithWhiteClient()
 | 
			
		||||
        {
 | 
			
		||||
            var clientId = "ocelotclient2";
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < 10; i++)
 | 
			
		||||
            {
 | 
			
		||||
                var request = new HttpRequestMessage(new HttpMethod("GET"), _url);
 | 
			
		||||
                request.Headers.Add("ClientId", clientId);
 | 
			
		||||
                _downstreamContext.DownstreamRequest = new DownstreamRequest(request);
 | 
			
		||||
                _downstreamContext.HttpContext.Request.Headers.TryAdd("ClientId", clientId);
 | 
			
		||||
 | 
			
		||||
                _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
 | 
			
		||||
                _responseStatusCode = (int)_downstreamContext.HttpContext.Response.StatusCode;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenresponseStatusCodeIs429()
 | 
			
		||||
        {
 | 
			
		||||
            _responseStatusCode.ShouldBe(429);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenresponseStatusCodeIs200()
 | 
			
		||||
        {
 | 
			
		||||
            _responseStatusCode.ShouldBe(200);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    internal class FakeStream : Stream
 | 
			
		||||
    {
 | 
			
		||||
        public override void Flush()
 | 
			
		||||
        {
 | 
			
		||||
            //do nothing
 | 
			
		||||
            //throw new System.NotImplementedException();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override int Read(byte[] buffer, int offset, int count)
 | 
			
		||||
        {
 | 
			
		||||
            throw new System.NotImplementedException();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override long Seek(long offset, SeekOrigin origin)
 | 
			
		||||
        {
 | 
			
		||||
            throw new System.NotImplementedException();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override void SetLength(long value)
 | 
			
		||||
        {
 | 
			
		||||
            throw new System.NotImplementedException();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override void Write(byte[] buffer, int offset, int count)
 | 
			
		||||
        {
 | 
			
		||||
            //do nothing
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override bool CanRead { get; }
 | 
			
		||||
        public override bool CanSeek { get; }
 | 
			
		||||
        public override bool CanWrite => true;
 | 
			
		||||
        public override long Length { get; }
 | 
			
		||||
        public override long Position { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.RateLimit
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Microsoft.Extensions.Caching.Memory;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.RateLimit;
 | 
			
		||||
    using Ocelot.RateLimit.Middleware;
 | 
			
		||||
    using Ocelot.Request.Middleware;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.IO;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using Ocelot.Infrastructure.RequestData;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
 | 
			
		||||
    public class ClientRateLimitMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private int _responseStatusCode;
 | 
			
		||||
        private IRateLimitCounterHandler _rateLimitCounterHandler;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private readonly ClientRateLimitMiddleware _middleware;
 | 
			
		||||
        private RequestDelegate _next;
 | 
			
		||||
        private DownstreamResponse _downstreamResponse;
 | 
			
		||||
        private readonly string _url;
 | 
			
		||||
 | 
			
		||||
        public ClientRateLimitMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _url = "http://localhost:51879";
 | 
			
		||||
            var cacheEntryOptions = new MemoryCacheOptions();
 | 
			
		||||
            _rateLimitCounterHandler = new MemoryCacheRateLimitCounterHandler(new MemoryCache(cacheEntryOptions));
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<ClientRateLimitMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _next = context => Task.CompletedTask;
 | 
			
		||||
            _middleware = new ClientRateLimitMiddleware(_next, _loggerFactory.Object, _rateLimitCounterHandler);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_middleware_and_ratelimiting()
 | 
			
		||||
        {
 | 
			
		||||
            var upstreamTemplate = new UpstreamPathTemplateBuilder().Build();
 | 
			
		||||
 | 
			
		||||
            var downstreamReRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithEnableRateLimiting(true)
 | 
			
		||||
                .WithRateLimitOptions(new RateLimitOptions(true, "ClientId", () => new List<string>(), false, "", "", new RateLimitRule("1s", 100, 3), 429))
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                .WithUpstreamPathTemplate(upstreamTemplate)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new ReRouteBuilder()
 | 
			
		||||
                .WithDownstreamReRoute(downstreamReRoute)
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<Ocelot.DownstreamRouteFinder.UrlMatcher.PlaceholderNameAndValue>(), reRoute);
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.WhenICallTheMiddlewareMultipleTimes(2, downstreamRoute))
 | 
			
		||||
                .Then(x => x.ThenThereIsNoDownstreamResponse())
 | 
			
		||||
                .When(x => x.WhenICallTheMiddlewareMultipleTimes(3, downstreamRoute))
 | 
			
		||||
                .Then(x => x.ThenTheResponseIs429())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_middleware_withWhitelistClient()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<Ocelot.DownstreamRouteFinder.UrlMatcher.PlaceholderNameAndValue>(),
 | 
			
		||||
                 new ReRouteBuilder()
 | 
			
		||||
                     .WithDownstreamReRoute(new DownstreamReRouteBuilder()
 | 
			
		||||
                         .WithEnableRateLimiting(true)
 | 
			
		||||
                         .WithRateLimitOptions(
 | 
			
		||||
                             new Ocelot.Configuration.RateLimitOptions(true, "ClientId", () => new List<string>() { "ocelotclient2" }, false, "", "", new RateLimitRule("1s", 100, 3), 429))
 | 
			
		||||
                         .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                         .Build())
 | 
			
		||||
                     .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                     .Build());
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.WhenICallTheMiddlewareWithWhiteClient(downstreamRoute))
 | 
			
		||||
                .Then(x => x.ThenThereIsNoDownstreamResponse())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddlewareMultipleTimes(int times, DownstreamRoute downstreamRoute)
 | 
			
		||||
        {
 | 
			
		||||
            var httpContexts = new List<HttpContext>();
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < times; i++)
 | 
			
		||||
            {
 | 
			
		||||
                var httpContext = new DefaultHttpContext();
 | 
			
		||||
                httpContext.Response.Body = new FakeStream();
 | 
			
		||||
                httpContext.Items.UpsertDownstreamReRoute(downstreamRoute.ReRoute.DownstreamReRoute[0]);
 | 
			
		||||
                httpContext.Items.UpsertTemplatePlaceholderNameAndValues(downstreamRoute.TemplatePlaceholderNameAndValues);
 | 
			
		||||
                httpContext.Items.UpsertDownstreamRoute(downstreamRoute);
 | 
			
		||||
                var clientId = "ocelotclient1";
 | 
			
		||||
                var request = new HttpRequestMessage(new HttpMethod("GET"), _url);
 | 
			
		||||
                httpContext.Items.UpsertDownstreamRequest(new DownstreamRequest(request));
 | 
			
		||||
                httpContext.Request.Headers.TryAdd("ClientId", clientId);
 | 
			
		||||
                httpContexts.Add(httpContext);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            foreach (var httpContext in httpContexts)
 | 
			
		||||
            {
 | 
			
		||||
                _middleware.Invoke(httpContext).GetAwaiter().GetResult();
 | 
			
		||||
                var ds = httpContext.Items.DownstreamResponse();
 | 
			
		||||
                _downstreamResponse = ds;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddlewareWithWhiteClient(DownstreamRoute downstreamRoute)
 | 
			
		||||
        {
 | 
			
		||||
            var clientId = "ocelotclient2";
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < 10; i++)
 | 
			
		||||
            {
 | 
			
		||||
                var httpContext = new DefaultHttpContext();
 | 
			
		||||
                httpContext.Response.Body = new FakeStream();
 | 
			
		||||
                httpContext.Items.UpsertDownstreamReRoute(downstreamRoute.ReRoute.DownstreamReRoute[0]);
 | 
			
		||||
                httpContext.Items.UpsertTemplatePlaceholderNameAndValues(downstreamRoute.TemplatePlaceholderNameAndValues);
 | 
			
		||||
                httpContext.Items.UpsertDownstreamRoute(downstreamRoute);
 | 
			
		||||
                var request = new HttpRequestMessage(new HttpMethod("GET"), _url);
 | 
			
		||||
                request.Headers.Add("ClientId", clientId);
 | 
			
		||||
                httpContext.Items.UpsertDownstreamRequest(new DownstreamRequest(request));
 | 
			
		||||
                httpContext.Request.Headers.TryAdd("ClientId", clientId);
 | 
			
		||||
                _middleware.Invoke(httpContext).GetAwaiter().GetResult();
 | 
			
		||||
                var ds = httpContext.Items.DownstreamResponse();
 | 
			
		||||
                _downstreamResponse = ds;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheResponseIs429()
 | 
			
		||||
        {
 | 
			
		||||
            var code = (int)_downstreamResponse.StatusCode;
 | 
			
		||||
            code.ShouldBe(429);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenThereIsNoDownstreamResponse()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamResponse.ShouldBeNull();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    internal class FakeStream : Stream
 | 
			
		||||
    {
 | 
			
		||||
        public override void Flush()
 | 
			
		||||
        {
 | 
			
		||||
            //do nothing
 | 
			
		||||
            //throw new System.NotImplementedException();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override int Read(byte[] buffer, int offset, int count)
 | 
			
		||||
        {
 | 
			
		||||
            throw new System.NotImplementedException();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override long Seek(long offset, SeekOrigin origin)
 | 
			
		||||
        {
 | 
			
		||||
            throw new System.NotImplementedException();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override void SetLength(long value)
 | 
			
		||||
        {
 | 
			
		||||
            throw new System.NotImplementedException();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override void Write(byte[] buffer, int offset, int count)
 | 
			
		||||
        {
 | 
			
		||||
            //do nothing
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override bool CanRead { get; }
 | 
			
		||||
        public override bool CanSeek { get; }
 | 
			
		||||
        public override bool CanWrite => true;
 | 
			
		||||
        public override long Length { get; }
 | 
			
		||||
        public override long Position { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -15,32 +15,23 @@
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
 | 
			
		||||
    public class DownstreamRequestInitialiserMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly DownstreamRequestInitialiserMiddleware _middleware;
 | 
			
		||||
 | 
			
		||||
        private readonly Mock<HttpContext> _httpContext;
 | 
			
		||||
 | 
			
		||||
        private readonly Mock<HttpRequest> _httpRequest;
 | 
			
		||||
 | 
			
		||||
        private readonly Mock<OcelotRequestDelegate> _next;
 | 
			
		||||
 | 
			
		||||
        private readonly HttpContext _httpContext;
 | 
			
		||||
        private readonly Mock<RequestDelegate> _next;
 | 
			
		||||
        private readonly Mock<IRequestMapper> _requestMapper;
 | 
			
		||||
 | 
			
		||||
        private readonly Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
 | 
			
		||||
        private readonly Mock<IOcelotLogger> _logger;
 | 
			
		||||
 | 
			
		||||
        private Response<HttpRequestMessage> _mappedRequest;
 | 
			
		||||
        private DownstreamContext _downstreamContext;
 | 
			
		||||
 | 
			
		||||
        public DownstreamRequestInitialiserMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext = new Mock<HttpContext>();
 | 
			
		||||
            _httpRequest = new Mock<HttpRequest>();
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
            _requestMapper = new Mock<IRequestMapper>();
 | 
			
		||||
            _next = new Mock<OcelotRequestDelegate>();
 | 
			
		||||
            _next = new Mock<RequestDelegate>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
@@ -53,8 +44,6 @@
 | 
			
		||||
                _loggerFactory.Object,
 | 
			
		||||
                _requestMapper.Object,
 | 
			
		||||
                new DownstreamRequestCreator(new FrameworkDescription()));
 | 
			
		||||
 | 
			
		||||
            _downstreamContext = new DownstreamContext(_httpContext.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
@@ -97,14 +86,12 @@
 | 
			
		||||
 | 
			
		||||
        private void ThenTheDownstreamRequestMethodIs(string expected)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.DownstreamRequest.Method.ShouldBe(expected);
 | 
			
		||||
            _httpContext.Items.DownstreamRequest().Method.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheHttpContextContainsARequest()
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext
 | 
			
		||||
                .Setup(hc => hc.Request)
 | 
			
		||||
                .Returns(_httpRequest.Object);
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamReRoute(new DownstreamReRouteBuilder().Build());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheMapperWillReturnAMappedRequest()
 | 
			
		||||
@@ -127,38 +114,38 @@
 | 
			
		||||
 | 
			
		||||
        private void WhenTheMiddlewareIsInvoked()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
 | 
			
		||||
            _middleware.Invoke(_httpContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheContexRequestIsMappedToADownstreamRequest()
 | 
			
		||||
        {
 | 
			
		||||
            _requestMapper.Verify(rm => rm.Map(_httpRequest.Object, _downstreamContext.DownstreamReRoute), Times.Once);
 | 
			
		||||
            _requestMapper.Verify(rm => rm.Map(_httpContext.Request, _httpContext.Items.DownstreamReRoute()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheDownstreamRequestIsStored()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.DownstreamRequest.ShouldNotBeNull();
 | 
			
		||||
            _httpContext.Items.DownstreamRequest().ShouldNotBeNull();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheDownstreamRequestIsNotStored()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.DownstreamRequest.ShouldBeNull();
 | 
			
		||||
            _httpContext.Items.DownstreamRequest().ShouldBeNull();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenAPipelineErrorIsStored()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.IsError.ShouldBeTrue();
 | 
			
		||||
            _downstreamContext.Errors.ShouldBe(_mappedRequest.Errors);
 | 
			
		||||
            _httpContext.Items.Errors().Count.ShouldBeGreaterThan(0);
 | 
			
		||||
            _httpContext.Items.Errors().ShouldBe(_mappedRequest.Errors);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheNextMiddlewareIsInvoked()
 | 
			
		||||
        {
 | 
			
		||||
            _next.Verify(n => n(_downstreamContext), Times.Once);
 | 
			
		||||
            _next.Verify(n => n(_httpContext), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheNextMiddlewareIsNotInvoked()
 | 
			
		||||
        {
 | 
			
		||||
            _next.Verify(n => n(It.IsAny<DownstreamContext>()), Times.Never);
 | 
			
		||||
            _next.Verify(n => n(It.IsAny<HttpContext>()), Times.Never);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,222 +1,223 @@
 | 
			
		||||
namespace Ocelot.UnitTests.RequestId
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
			
		||||
    using Ocelot.Infrastructure.RequestData;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Ocelot.Request.Middleware;
 | 
			
		||||
    using Ocelot.RequestId.Middleware;
 | 
			
		||||
    using Ocelot.Responses;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Linq;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class ReRouteRequestIdMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly HttpRequestMessage _downstreamRequest;
 | 
			
		||||
        private string _value;
 | 
			
		||||
        private string _key;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private readonly ReRouteRequestIdMiddleware _middleware;
 | 
			
		||||
        private readonly DownstreamContext _downstreamContext;
 | 
			
		||||
        private OcelotRequestDelegate _next;
 | 
			
		||||
        private readonly Mock<IRequestScopedDataRepository> _repo;
 | 
			
		||||
 | 
			
		||||
        public ReRouteRequestIdMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamRequest = new HttpRequestMessage(HttpMethod.Get, "http://test.com");
 | 
			
		||||
            _repo = new Mock<IRequestScopedDataRepository>();
 | 
			
		||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<ReRouteRequestIdMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _next = context =>
 | 
			
		||||
            {
 | 
			
		||||
                context.HttpContext.Response.Headers.Add("LSRequestId", context.HttpContext.TraceIdentifier);
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            };
 | 
			
		||||
            _middleware = new ReRouteRequestIdMiddleware(_next, _loggerFactory.Object, _repo.Object);
 | 
			
		||||
            _downstreamContext.DownstreamRequest = new DownstreamRequest(_downstreamRequest);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_pass_down_request_id_from_upstream_request()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamReRoute(new DownstreamReRouteBuilder()
 | 
			
		||||
                        .WithDownstreamPathTemplate("any old string")
 | 
			
		||||
                        .WithRequestIdKey("LSRequestId")
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .Build())
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                .Build());
 | 
			
		||||
 | 
			
		||||
            var requestId = Guid.NewGuid().ToString();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
                .And(x => GivenThereIsNoGlobalRequestId())
 | 
			
		||||
                .And(x => x.GivenTheRequestIdIsAddedToTheRequest("LSRequestId", requestId))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheTraceIdIs(requestId))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_request_id_when_not_on_upstream_request()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamReRoute(new DownstreamReRouteBuilder()
 | 
			
		||||
                        .WithDownstreamPathTemplate("any old string")
 | 
			
		||||
                        .WithRequestIdKey("LSRequestId")
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .Build())
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
                .And(x => GivenThereIsNoGlobalRequestId())
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheTraceIdIsAnything())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_request_id_scoped_repo_for_logging_later()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamReRoute(new DownstreamReRouteBuilder()
 | 
			
		||||
                        .WithDownstreamPathTemplate("any old string")
 | 
			
		||||
                        .WithRequestIdKey("LSRequestId")
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .Build())
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            var requestId = Guid.NewGuid().ToString();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
                .And(x => GivenThereIsNoGlobalRequestId())
 | 
			
		||||
                .And(x => x.GivenTheRequestIdIsAddedToTheRequest("LSRequestId", requestId))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheTraceIdIs(requestId))
 | 
			
		||||
                .And(x => ThenTheRequestIdIsSaved())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_update_request_id_scoped_repo_for_logging_later()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamReRoute(new DownstreamReRouteBuilder()
 | 
			
		||||
                        .WithDownstreamPathTemplate("any old string")
 | 
			
		||||
                        .WithRequestIdKey("LSRequestId")
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .Build())
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            var requestId = Guid.NewGuid().ToString();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
                .And(x => GivenTheRequestIdWasSetGlobally())
 | 
			
		||||
                .And(x => x.GivenTheRequestIdIsAddedToTheRequest("LSRequestId", requestId))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheTraceIdIs(requestId))
 | 
			
		||||
                .And(x => ThenTheRequestIdIsUpdated())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_update_if_global_request_id_is_same_as_re_route_request_id()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamReRoute(new DownstreamReRouteBuilder()
 | 
			
		||||
                        .WithDownstreamPathTemplate("any old string")
 | 
			
		||||
                        .WithRequestIdKey("LSRequestId")
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .Build())
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            var requestId = "alreadyset";
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
                .And(x => GivenTheRequestIdWasSetGlobally())
 | 
			
		||||
                .And(x => x.GivenTheRequestIdIsAddedToTheRequest("LSRequestId", requestId))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheTraceIdIs(requestId))
 | 
			
		||||
                .And(x => ThenTheRequestIdIsNotUpdated())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsNoGlobalRequestId()
 | 
			
		||||
        {
 | 
			
		||||
            _repo.Setup(x => x.Get<string>("RequestId")).Returns(new OkResponse<string>(null));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheRequestIdWasSetGlobally()
 | 
			
		||||
        {
 | 
			
		||||
            _repo.Setup(x => x.Get<string>("RequestId")).Returns(new OkResponse<string>("alreadyset"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheRequestIdIsSaved()
 | 
			
		||||
        {
 | 
			
		||||
            _repo.Verify(x => x.Add("RequestId", _value), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheRequestIdIsUpdated()
 | 
			
		||||
        {
 | 
			
		||||
            _repo.Verify(x => x.Update("RequestId", _value), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheRequestIdIsNotUpdated()
 | 
			
		||||
        {
 | 
			
		||||
            _repo.Verify(x => x.Update("RequestId", _value), Times.Never);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.TemplatePlaceholderNameAndValues = downstreamRoute.TemplatePlaceholderNameAndValues;
 | 
			
		||||
            _downstreamContext.DownstreamReRoute = downstreamRoute.ReRoute.DownstreamReRoute[0];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheRequestIdIsAddedToTheRequest(string key, string value)
 | 
			
		||||
        {
 | 
			
		||||
            _key = key;
 | 
			
		||||
            _value = value;
 | 
			
		||||
            _downstreamContext.HttpContext.Request.Headers.TryAdd(_key, _value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheTraceIdIsAnything()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.HttpContext.Response.Headers.TryGetValue("LSRequestId", out var value);
 | 
			
		||||
            value.First().ShouldNotBeNullOrEmpty();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheTraceIdIs(string expected)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.HttpContext.Response.Headers.TryGetValue("LSRequestId", out var value);
 | 
			
		||||
            value.First().ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
namespace Ocelot.UnitTests.RequestId
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.UrlMatcher;
 | 
			
		||||
    using Ocelot.Infrastructure.RequestData;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Ocelot.Request.Middleware;
 | 
			
		||||
    using Ocelot.RequestId.Middleware;
 | 
			
		||||
    using Ocelot.Responses;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Linq;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class ReRouteRequestIdMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly HttpRequestMessage _downstreamRequest;
 | 
			
		||||
        private string _value;
 | 
			
		||||
        private string _key;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private readonly ReRouteRequestIdMiddleware _middleware;
 | 
			
		||||
        private RequestDelegate _next;
 | 
			
		||||
        private readonly Mock<IRequestScopedDataRepository> _repo;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
        public ReRouteRequestIdMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
            _downstreamRequest = new HttpRequestMessage(HttpMethod.Get, "http://test.com");
 | 
			
		||||
            _repo = new Mock<IRequestScopedDataRepository>();
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<ReRouteRequestIdMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _next = context =>
 | 
			
		||||
            {
 | 
			
		||||
                _httpContext.Response.Headers.Add("LSRequestId", _httpContext.TraceIdentifier);
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            };
 | 
			
		||||
            _middleware = new ReRouteRequestIdMiddleware(_next, _loggerFactory.Object, _repo.Object);
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamRequest(new DownstreamRequest(_downstreamRequest));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_pass_down_request_id_from_upstream_request()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamReRoute(new DownstreamReRouteBuilder()
 | 
			
		||||
                        .WithDownstreamPathTemplate("any old string")
 | 
			
		||||
                        .WithRequestIdKey("LSRequestId")
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .Build())
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                .Build());
 | 
			
		||||
 | 
			
		||||
            var requestId = Guid.NewGuid().ToString();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
                .And(x => GivenThereIsNoGlobalRequestId())
 | 
			
		||||
                .And(x => x.GivenTheRequestIdIsAddedToTheRequest("LSRequestId", requestId))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheTraceIdIs(requestId))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_request_id_when_not_on_upstream_request()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamReRoute(new DownstreamReRouteBuilder()
 | 
			
		||||
                        .WithDownstreamPathTemplate("any old string")
 | 
			
		||||
                        .WithRequestIdKey("LSRequestId")
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .Build())
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
                .And(x => GivenThereIsNoGlobalRequestId())
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheTraceIdIsAnything())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_request_id_scoped_repo_for_logging_later()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamReRoute(new DownstreamReRouteBuilder()
 | 
			
		||||
                        .WithDownstreamPathTemplate("any old string")
 | 
			
		||||
                        .WithRequestIdKey("LSRequestId")
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .Build())
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            var requestId = Guid.NewGuid().ToString();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
                .And(x => GivenThereIsNoGlobalRequestId())
 | 
			
		||||
                .And(x => x.GivenTheRequestIdIsAddedToTheRequest("LSRequestId", requestId))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheTraceIdIs(requestId))
 | 
			
		||||
                .And(x => ThenTheRequestIdIsSaved())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_update_request_id_scoped_repo_for_logging_later()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamReRoute(new DownstreamReRouteBuilder()
 | 
			
		||||
                        .WithDownstreamPathTemplate("any old string")
 | 
			
		||||
                        .WithRequestIdKey("LSRequestId")
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .Build())
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            var requestId = Guid.NewGuid().ToString();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
                .And(x => GivenTheRequestIdWasSetGlobally())
 | 
			
		||||
                .And(x => x.GivenTheRequestIdIsAddedToTheRequest("LSRequestId", requestId))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheTraceIdIs(requestId))
 | 
			
		||||
                .And(x => ThenTheRequestIdIsUpdated())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_update_if_global_request_id_is_same_as_re_route_request_id()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamRoute = new DownstreamRoute(new List<PlaceholderNameAndValue>(),
 | 
			
		||||
                new ReRouteBuilder()
 | 
			
		||||
                    .WithDownstreamReRoute(new DownstreamReRouteBuilder()
 | 
			
		||||
                        .WithDownstreamPathTemplate("any old string")
 | 
			
		||||
                        .WithRequestIdKey("LSRequestId")
 | 
			
		||||
                        .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                        .Build())
 | 
			
		||||
                    .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                    .Build());
 | 
			
		||||
 | 
			
		||||
            var requestId = "alreadyset";
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
 | 
			
		||||
                .And(x => GivenTheRequestIdWasSetGlobally())
 | 
			
		||||
                .And(x => x.GivenTheRequestIdIsAddedToTheRequest("LSRequestId", requestId))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheTraceIdIs(requestId))
 | 
			
		||||
                .And(x => ThenTheRequestIdIsNotUpdated())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_httpContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsNoGlobalRequestId()
 | 
			
		||||
        {
 | 
			
		||||
            _repo.Setup(x => x.Get<string>("RequestId")).Returns(new OkResponse<string>(null));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheRequestIdWasSetGlobally()
 | 
			
		||||
        {
 | 
			
		||||
            _repo.Setup(x => x.Get<string>("RequestId")).Returns(new OkResponse<string>("alreadyset"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheRequestIdIsSaved()
 | 
			
		||||
        {
 | 
			
		||||
            _repo.Verify(x => x.Add("RequestId", _value), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheRequestIdIsUpdated()
 | 
			
		||||
        {
 | 
			
		||||
            _repo.Verify(x => x.Update("RequestId", _value), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheRequestIdIsNotUpdated()
 | 
			
		||||
        {
 | 
			
		||||
            _repo.Verify(x => x.Update("RequestId", _value), Times.Never);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute)
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext.Items.UpsertTemplatePlaceholderNameAndValues(downstreamRoute.TemplatePlaceholderNameAndValues);
 | 
			
		||||
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamReRoute(downstreamRoute.ReRoute.DownstreamReRoute[0]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheRequestIdIsAddedToTheRequest(string key, string value)
 | 
			
		||||
        {
 | 
			
		||||
            _key = key;
 | 
			
		||||
            _value = value;
 | 
			
		||||
            _httpContext.Request.Headers.TryAdd(_key, _value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheTraceIdIsAnything()
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext.Response.Headers.TryGetValue("LSRequestId", out var value);
 | 
			
		||||
            value.First().ShouldNotBeNullOrEmpty();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheTraceIdIs(string expected)
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext.Response.Headers.TryGetValue("LSRequestId", out var value);
 | 
			
		||||
            value.First().ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,449 +1,446 @@
 | 
			
		||||
using Microsoft.AspNetCore.Builder;
 | 
			
		||||
using Microsoft.AspNetCore.Hosting;
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Configuration.Builder;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Ocelot.Request.Middleware;
 | 
			
		||||
using Ocelot.Requester;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Net;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Requester
 | 
			
		||||
{
 | 
			
		||||
    public class HttpClientBuilderTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private HttpClientBuilder _builder;
 | 
			
		||||
        private readonly Mock<IDelegatingHandlerHandlerFactory> _factory;
 | 
			
		||||
        private IHttpClient _httpClient;
 | 
			
		||||
        private HttpResponseMessage _response;
 | 
			
		||||
        private DownstreamContext _context;
 | 
			
		||||
        private readonly Mock<IHttpClientCache> _cacheHandlers;
 | 
			
		||||
        private readonly Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private int _count;
 | 
			
		||||
        private IWebHost _host;
 | 
			
		||||
        private IHttpClient _againHttpClient;
 | 
			
		||||
        private IHttpClient _firstHttpClient;
 | 
			
		||||
        private MemoryHttpClientCache _realCache;
 | 
			
		||||
 | 
			
		||||
        public HttpClientBuilderTests()
 | 
			
		||||
        {
 | 
			
		||||
            _cacheHandlers = new Mock<IHttpClientCache>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _factory = new Mock<IDelegatingHandlerHandlerFactory>();
 | 
			
		||||
            _builder = new HttpClientBuilder(_factory.Object, _cacheHandlers.Object, _logger.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_build_http_client()
 | 
			
		||||
        {
 | 
			
		||||
            var qosOptions = new QoSOptionsBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFactoryReturns())
 | 
			
		||||
                .And(x => GivenARequest(reRoute))
 | 
			
		||||
                .When(x => WhenIBuild())
 | 
			
		||||
                .Then(x => ThenTheHttpClientShouldNotBeNull())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_get_from_cache()
 | 
			
		||||
        {
 | 
			
		||||
            var qosOptions = new QoSOptionsBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenARealCache())
 | 
			
		||||
                .And(x => GivenTheFactoryReturns())
 | 
			
		||||
                .And(x => GivenARequest(reRoute))
 | 
			
		||||
                .And(x => WhenIBuildTheFirstTime())
 | 
			
		||||
                .And(x => WhenISave())
 | 
			
		||||
                .And(x => WhenIBuildAgain())
 | 
			
		||||
                .And(x => WhenISave())
 | 
			
		||||
                .When(x => WhenIBuildAgain())
 | 
			
		||||
                .Then(x => ThenTheHttpClientIsFromTheCache())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_get_from_cache_with_different_query_string()
 | 
			
		||||
        {
 | 
			
		||||
            var qosOptions = new QoSOptionsBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenARealCache())
 | 
			
		||||
                .And(x => GivenTheFactoryReturns())
 | 
			
		||||
                .And(x => GivenARequest(reRoute, "http://wwww.someawesomewebsite.com/woot?badman=1"))
 | 
			
		||||
                .And(x => WhenIBuildTheFirstTime())
 | 
			
		||||
                .And(x => WhenISave())
 | 
			
		||||
                .And(x => WhenIBuildAgain())
 | 
			
		||||
                .And(x => GivenARequest(reRoute, "http://wwww.someawesomewebsite.com/woot?badman=2"))
 | 
			
		||||
                .And(x => WhenISave())
 | 
			
		||||
                .When(x => WhenIBuildAgain())
 | 
			
		||||
                .Then(x => ThenTheHttpClientIsFromTheCache())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_get_from_cache_with_different_query_string()
 | 
			
		||||
        {
 | 
			
		||||
            var qosOptions = new QoSOptionsBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRouteA = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithContainsQueryString(true).WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRouteB = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithContainsQueryString(true).WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenARealCache())
 | 
			
		||||
                .And(x => GivenTheFactoryReturns())
 | 
			
		||||
                .And(x => GivenARequest(reRouteA, "http://wwww.someawesomewebsite.com/woot?badman=1"))
 | 
			
		||||
                .And(x => WhenIBuildTheFirstTime())
 | 
			
		||||
                .And(x => WhenISave())
 | 
			
		||||
                .And(x => WhenIBuildAgain())
 | 
			
		||||
                .And(x => GivenARequest(reRouteB, "http://wwww.someawesomewebsite.com/woot?badman=2"))
 | 
			
		||||
                .And(x => WhenISave())
 | 
			
		||||
                .When(x => WhenIBuildAgain())
 | 
			
		||||
                .Then(x => ThenTheHttpClientIsNotFromTheCache())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_log_if_ignoring_ssl_errors()
 | 
			
		||||
        {
 | 
			
		||||
            var qosOptions = new QoSOptionsBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
                .WithDangerousAcceptAnyServerCertificateValidator(true)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFactoryReturns())
 | 
			
		||||
                .And(x => GivenARequest(reRoute))
 | 
			
		||||
                .When(x => WhenIBuild())
 | 
			
		||||
                .Then(x => ThenTheHttpClientShouldNotBeNull())
 | 
			
		||||
                .Then(x => ThenTheDangerousAcceptAnyServerCertificateValidatorWarningIsLogged())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_delegating_handlers_in_order()
 | 
			
		||||
        {
 | 
			
		||||
            var qosOptions = new QoSOptionsBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var fakeOne = new FakeDelegatingHandler();
 | 
			
		||||
            var fakeTwo = new FakeDelegatingHandler();
 | 
			
		||||
 | 
			
		||||
            var handlers = new List<Func<DelegatingHandler>>()
 | 
			
		||||
            {
 | 
			
		||||
                () => fakeOne,
 | 
			
		||||
                () => fakeTwo
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFactoryReturns(handlers))
 | 
			
		||||
                .And(x => GivenARequest(reRoute))
 | 
			
		||||
                .And(x => WhenIBuild())
 | 
			
		||||
                .When(x => WhenICallTheClient())
 | 
			
		||||
                .Then(x => ThenTheFakeAreHandledInOrder(fakeOne, fakeTwo))
 | 
			
		||||
                .And(x => ThenSomethingIsReturned())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_re_use_cookies_from_container()
 | 
			
		||||
        {
 | 
			
		||||
            var qosOptions = new QoSOptionsBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, true, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(_ => GivenADownstreamService())
 | 
			
		||||
                .And(_ => GivenARequest(reRoute))
 | 
			
		||||
                .And(_ => GivenTheFactoryReturnsNothing())
 | 
			
		||||
                .And(_ => WhenIBuild())
 | 
			
		||||
                .And(_ => WhenICallTheClient("http://localhost:5003"))
 | 
			
		||||
                .And(_ => ThenTheCookieIsSet())
 | 
			
		||||
                .And(_ => GivenTheClientIsCached())
 | 
			
		||||
                .And(_ => WhenIBuild())
 | 
			
		||||
                .When(_ => WhenICallTheClient("http://localhost:5003"))
 | 
			
		||||
                .Then(_ => ThenTheResponseIsOk())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("GET")]
 | 
			
		||||
        [InlineData("POST")]
 | 
			
		||||
        [InlineData("PUT")]
 | 
			
		||||
        [InlineData("DELETE")]
 | 
			
		||||
        [InlineData("PATCH")]
 | 
			
		||||
        public void should_add_verb_to_cache_key(string verb)
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamUrl = "http://localhost:5012/";
 | 
			
		||||
 | 
			
		||||
            var method = new HttpMethod(verb);
 | 
			
		||||
 | 
			
		||||
            var qosOptions = new QoSOptionsBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(_ => GivenADownstreamService())
 | 
			
		||||
                .And(_ => GivenARequestWithAUrlAndMethod(reRoute, downstreamUrl, method))
 | 
			
		||||
                .And(_ => GivenTheFactoryReturnsNothing())
 | 
			
		||||
                .And(_ => WhenIBuild())
 | 
			
		||||
                .And(_ => GivenCacheIsCalledWithExpectedKey($"{method.ToString()}:{downstreamUrl}"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenARealCache()
 | 
			
		||||
        {
 | 
			
		||||
            _realCache = new MemoryHttpClientCache();
 | 
			
		||||
            _builder = new HttpClientBuilder(_factory.Object, _realCache, _logger.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheHttpClientIsFromTheCache()
 | 
			
		||||
        {
 | 
			
		||||
            _againHttpClient.ShouldBe(_firstHttpClient);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheHttpClientIsNotFromTheCache()
 | 
			
		||||
        {
 | 
			
		||||
            _againHttpClient.ShouldNotBe(_firstHttpClient);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenISave()
 | 
			
		||||
        {
 | 
			
		||||
            _builder.Save();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenCacheIsCalledWithExpectedKey(string expectedKey)
 | 
			
		||||
        {
 | 
			
		||||
            _cacheHandlers.Verify(x => x.Get(It.IsAny<DownstreamReRoute>()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheDangerousAcceptAnyServerCertificateValidatorWarningIsLogged()
 | 
			
		||||
        {
 | 
			
		||||
            _logger.Verify(x => x.LogWarning($"You have ignored all SSL warnings by using DangerousAcceptAnyServerCertificateValidator for this DownstreamReRoute, UpstreamPathTemplate: {_context.DownstreamReRoute.UpstreamPathTemplate}, DownstreamPathTemplate: {_context.DownstreamReRoute.DownstreamPathTemplate}"), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheClientIsCached()
 | 
			
		||||
        {
 | 
			
		||||
            _cacheHandlers.Setup(x => x.Get(It.IsAny<DownstreamReRoute>())).Returns(_httpClient);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheCookieIsSet()
 | 
			
		||||
        {
 | 
			
		||||
            _response.Headers.TryGetValues("Set-Cookie", out var test).ShouldBeTrue();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheClient(string url)
 | 
			
		||||
        {
 | 
			
		||||
            _response = _httpClient
 | 
			
		||||
                .SendAsync(new HttpRequestMessage(HttpMethod.Get, url))
 | 
			
		||||
                .GetAwaiter()
 | 
			
		||||
                .GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheResponseIsOk()
 | 
			
		||||
        {
 | 
			
		||||
            _response.StatusCode.ShouldBe(HttpStatusCode.OK);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenADownstreamService()
 | 
			
		||||
        {
 | 
			
		||||
            _host = new WebHostBuilder()
 | 
			
		||||
                .UseUrls("http://localhost:5003")
 | 
			
		||||
                .UseKestrel()
 | 
			
		||||
                .UseContentRoot(Directory.GetCurrentDirectory())
 | 
			
		||||
                .UseIISIntegration()
 | 
			
		||||
                .Configure(app =>
 | 
			
		||||
                {
 | 
			
		||||
                    app.Run(context =>
 | 
			
		||||
                    {
 | 
			
		||||
                        if (_count == 0)
 | 
			
		||||
                        {
 | 
			
		||||
                            context.Response.Cookies.Append("test", "0");
 | 
			
		||||
                            context.Response.StatusCode = 200;
 | 
			
		||||
                            _count++;
 | 
			
		||||
                            return Task.CompletedTask;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        if (_count == 1)
 | 
			
		||||
                        {
 | 
			
		||||
                            if (context.Request.Cookies.TryGetValue("test", out var cookieValue) || context.Request.Headers.TryGetValue("Set-Cookie", out var headerValue))
 | 
			
		||||
                            {
 | 
			
		||||
                                context.Response.StatusCode = 200;
 | 
			
		||||
                                return Task.CompletedTask;
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            context.Response.StatusCode = 500;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        return Task.CompletedTask;
 | 
			
		||||
                    });
 | 
			
		||||
                })
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            _host.Start();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenARequest(DownstreamReRoute downstream)
 | 
			
		||||
        {
 | 
			
		||||
            GivenARequest(downstream, "http://localhost:5003");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenARequest(DownstreamReRoute downstream, string downstreamUrl)
 | 
			
		||||
        {
 | 
			
		||||
            GivenARequestWithAUrlAndMethod(downstream, downstreamUrl, HttpMethod.Get);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenARequestWithAUrlAndMethod(DownstreamReRoute downstream, string url, HttpMethod method)
 | 
			
		||||
        {
 | 
			
		||||
            var context = new DownstreamContext(new DefaultHttpContext())
 | 
			
		||||
            {
 | 
			
		||||
                DownstreamReRoute = downstream,
 | 
			
		||||
                DownstreamRequest = new DownstreamRequest(new HttpRequestMessage() { RequestUri = new Uri(url), Method = method }),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            _context = context;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenSomethingIsReturned()
 | 
			
		||||
        {
 | 
			
		||||
            _response.ShouldNotBeNull();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheClient()
 | 
			
		||||
        {
 | 
			
		||||
            _response = _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, "http://test.com")).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheFakeAreHandledInOrder(FakeDelegatingHandler fakeOne, FakeDelegatingHandler fakeTwo)
 | 
			
		||||
        {
 | 
			
		||||
            fakeOne.TimeCalled.ShouldBeGreaterThan(fakeTwo.TimeCalled);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFactoryReturns()
 | 
			
		||||
        {
 | 
			
		||||
            var handlers = new List<Func<DelegatingHandler>>() { () => new FakeDelegatingHandler() };
 | 
			
		||||
 | 
			
		||||
            _factory
 | 
			
		||||
                .Setup(x => x.Get(It.IsAny<DownstreamReRoute>()))
 | 
			
		||||
                .Returns(new OkResponse<List<Func<DelegatingHandler>>>(handlers));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFactoryReturnsNothing()
 | 
			
		||||
        {
 | 
			
		||||
            var handlers = new List<Func<DelegatingHandler>>();
 | 
			
		||||
 | 
			
		||||
            _factory
 | 
			
		||||
                .Setup(x => x.Get(It.IsAny<DownstreamReRoute>()))
 | 
			
		||||
                .Returns(new OkResponse<List<Func<DelegatingHandler>>>(handlers));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFactoryReturns(List<Func<DelegatingHandler>> handlers)
 | 
			
		||||
        {
 | 
			
		||||
            _factory
 | 
			
		||||
               .Setup(x => x.Get(It.IsAny<DownstreamReRoute>()))
 | 
			
		||||
               .Returns(new OkResponse<List<Func<DelegatingHandler>>>(handlers));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIBuild()
 | 
			
		||||
        {
 | 
			
		||||
            _httpClient = _builder.Create(_context);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIBuildTheFirstTime()
 | 
			
		||||
        {
 | 
			
		||||
            _firstHttpClient = _builder.Create(_context);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIBuildAgain()
 | 
			
		||||
        {
 | 
			
		||||
            _builder = new HttpClientBuilder(_factory.Object, _realCache, _logger.Object);
 | 
			
		||||
            _againHttpClient = _builder.Create(_context);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheHttpClientShouldNotBeNull()
 | 
			
		||||
        {
 | 
			
		||||
            _httpClient.ShouldNotBeNull();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            _response?.Dispose();
 | 
			
		||||
            _host?.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
using Microsoft.AspNetCore.Builder;
 | 
			
		||||
using Microsoft.AspNetCore.Hosting;
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Configuration.Builder;
 | 
			
		||||
using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Ocelot.Request.Middleware;
 | 
			
		||||
using Ocelot.Requester;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Net;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Requester
 | 
			
		||||
{
 | 
			
		||||
    public class HttpClientBuilderTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private HttpClientBuilder _builder;
 | 
			
		||||
        private readonly Mock<IDelegatingHandlerHandlerFactory> _factory;
 | 
			
		||||
        private IHttpClient _httpClient;
 | 
			
		||||
        private HttpResponseMessage _response;
 | 
			
		||||
        private HttpContext _context;
 | 
			
		||||
        private readonly Mock<IHttpClientCache> _cacheHandlers;
 | 
			
		||||
        private readonly Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private int _count;
 | 
			
		||||
        private IWebHost _host;
 | 
			
		||||
        private IHttpClient _againHttpClient;
 | 
			
		||||
        private IHttpClient _firstHttpClient;
 | 
			
		||||
        private MemoryHttpClientCache _realCache;
 | 
			
		||||
 | 
			
		||||
        public HttpClientBuilderTests()
 | 
			
		||||
        {
 | 
			
		||||
            _cacheHandlers = new Mock<IHttpClientCache>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _factory = new Mock<IDelegatingHandlerHandlerFactory>();
 | 
			
		||||
            _builder = new HttpClientBuilder(_factory.Object, _cacheHandlers.Object, _logger.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_build_http_client()
 | 
			
		||||
        {
 | 
			
		||||
            var qosOptions = new QoSOptionsBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFactoryReturns())
 | 
			
		||||
                .And(x => GivenARequest(reRoute))
 | 
			
		||||
                .When(x => WhenIBuild())
 | 
			
		||||
                .Then(x => ThenTheHttpClientShouldNotBeNull())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_get_from_cache()
 | 
			
		||||
        {
 | 
			
		||||
            var qosOptions = new QoSOptionsBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenARealCache())
 | 
			
		||||
                .And(x => GivenTheFactoryReturns())
 | 
			
		||||
                .And(x => GivenARequest(reRoute))
 | 
			
		||||
                .And(x => WhenIBuildTheFirstTime())
 | 
			
		||||
                .And(x => WhenISave())
 | 
			
		||||
                .And(x => WhenIBuildAgain())
 | 
			
		||||
                .And(x => WhenISave())
 | 
			
		||||
                .When(x => WhenIBuildAgain())
 | 
			
		||||
                .Then(x => ThenTheHttpClientIsFromTheCache())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_get_from_cache_with_different_query_string()
 | 
			
		||||
        {
 | 
			
		||||
            var qosOptions = new QoSOptionsBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenARealCache())
 | 
			
		||||
                .And(x => GivenTheFactoryReturns())
 | 
			
		||||
                .And(x => GivenARequest(reRoute, "http://wwww.someawesomewebsite.com/woot?badman=1"))
 | 
			
		||||
                .And(x => WhenIBuildTheFirstTime())
 | 
			
		||||
                .And(x => WhenISave())
 | 
			
		||||
                .And(x => WhenIBuildAgain())
 | 
			
		||||
                .And(x => GivenARequest(reRoute, "http://wwww.someawesomewebsite.com/woot?badman=2"))
 | 
			
		||||
                .And(x => WhenISave())
 | 
			
		||||
                .When(x => WhenIBuildAgain())
 | 
			
		||||
                .Then(x => ThenTheHttpClientIsFromTheCache())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_get_from_cache_with_different_query_string()
 | 
			
		||||
        {
 | 
			
		||||
            var qosOptions = new QoSOptionsBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRouteA = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithContainsQueryString(true).WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRouteB = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithContainsQueryString(true).WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenARealCache())
 | 
			
		||||
                .And(x => GivenTheFactoryReturns())
 | 
			
		||||
                .And(x => GivenARequest(reRouteA, "http://wwww.someawesomewebsite.com/woot?badman=1"))
 | 
			
		||||
                .And(x => WhenIBuildTheFirstTime())
 | 
			
		||||
                .And(x => WhenISave())
 | 
			
		||||
                .And(x => WhenIBuildAgain())
 | 
			
		||||
                .And(x => GivenARequest(reRouteB, "http://wwww.someawesomewebsite.com/woot?badman=2"))
 | 
			
		||||
                .And(x => WhenISave())
 | 
			
		||||
                .When(x => WhenIBuildAgain())
 | 
			
		||||
                .Then(x => ThenTheHttpClientIsNotFromTheCache())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_log_if_ignoring_ssl_errors()
 | 
			
		||||
        {
 | 
			
		||||
            var qosOptions = new QoSOptionsBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
                .WithDangerousAcceptAnyServerCertificateValidator(true)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFactoryReturns())
 | 
			
		||||
                .And(x => GivenARequest(reRoute))
 | 
			
		||||
                .When(x => WhenIBuild())
 | 
			
		||||
                .Then(x => ThenTheHttpClientShouldNotBeNull())
 | 
			
		||||
                .Then(x => ThenTheDangerousAcceptAnyServerCertificateValidatorWarningIsLogged())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_delegating_handlers_in_order()
 | 
			
		||||
        {
 | 
			
		||||
            var qosOptions = new QoSOptionsBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var fakeOne = new FakeDelegatingHandler();
 | 
			
		||||
            var fakeTwo = new FakeDelegatingHandler();
 | 
			
		||||
 | 
			
		||||
            var handlers = new List<Func<DelegatingHandler>>()
 | 
			
		||||
            {
 | 
			
		||||
                () => fakeOne,
 | 
			
		||||
                () => fakeTwo
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFactoryReturns(handlers))
 | 
			
		||||
                .And(x => GivenARequest(reRoute))
 | 
			
		||||
                .And(x => WhenIBuild())
 | 
			
		||||
                .When(x => WhenICallTheClient())
 | 
			
		||||
                .Then(x => ThenTheFakeAreHandledInOrder(fakeOne, fakeTwo))
 | 
			
		||||
                .And(x => ThenSomethingIsReturned())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_re_use_cookies_from_container()
 | 
			
		||||
        {
 | 
			
		||||
            var qosOptions = new QoSOptionsBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, true, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(_ => GivenADownstreamService())
 | 
			
		||||
                .And(_ => GivenARequest(reRoute))
 | 
			
		||||
                .And(_ => GivenTheFactoryReturnsNothing())
 | 
			
		||||
                .And(_ => WhenIBuild())
 | 
			
		||||
                .And(_ => WhenICallTheClient("http://localhost:5003"))
 | 
			
		||||
                .And(_ => ThenTheCookieIsSet())
 | 
			
		||||
                .And(_ => GivenTheClientIsCached())
 | 
			
		||||
                .And(_ => WhenIBuild())
 | 
			
		||||
                .When(_ => WhenICallTheClient("http://localhost:5003"))
 | 
			
		||||
                .Then(_ => ThenTheResponseIsOk())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Theory]
 | 
			
		||||
        [InlineData("GET")]
 | 
			
		||||
        [InlineData("POST")]
 | 
			
		||||
        [InlineData("PUT")]
 | 
			
		||||
        [InlineData("DELETE")]
 | 
			
		||||
        [InlineData("PATCH")]
 | 
			
		||||
        public void should_add_verb_to_cache_key(string verb)
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamUrl = "http://localhost:5012/";
 | 
			
		||||
 | 
			
		||||
            var method = new HttpMethod(verb);
 | 
			
		||||
 | 
			
		||||
            var qosOptions = new QoSOptionsBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(_ => GivenADownstreamService())
 | 
			
		||||
                .And(_ => GivenARequestWithAUrlAndMethod(reRoute, downstreamUrl, method))
 | 
			
		||||
                .And(_ => GivenTheFactoryReturnsNothing())
 | 
			
		||||
                .And(_ => WhenIBuild())
 | 
			
		||||
                .And(_ => GivenCacheIsCalledWithExpectedKey($"{method.ToString()}:{downstreamUrl}"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenARealCache()
 | 
			
		||||
        {
 | 
			
		||||
            _realCache = new MemoryHttpClientCache();
 | 
			
		||||
            _builder = new HttpClientBuilder(_factory.Object, _realCache, _logger.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheHttpClientIsFromTheCache()
 | 
			
		||||
        {
 | 
			
		||||
            _againHttpClient.ShouldBe(_firstHttpClient);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheHttpClientIsNotFromTheCache()
 | 
			
		||||
        {
 | 
			
		||||
            _againHttpClient.ShouldNotBe(_firstHttpClient);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenISave()
 | 
			
		||||
        {
 | 
			
		||||
            _builder.Save();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenCacheIsCalledWithExpectedKey(string expectedKey)
 | 
			
		||||
        {
 | 
			
		||||
            _cacheHandlers.Verify(x => x.Get(It.IsAny<DownstreamReRoute>()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheDangerousAcceptAnyServerCertificateValidatorWarningIsLogged()
 | 
			
		||||
        {
 | 
			
		||||
            _logger.Verify(x => x.LogWarning($"You have ignored all SSL warnings by using DangerousAcceptAnyServerCertificateValidator for this DownstreamReRoute, UpstreamPathTemplate: {_context.Items.DownstreamReRoute().UpstreamPathTemplate}, DownstreamPathTemplate: {_context.Items.DownstreamReRoute().DownstreamPathTemplate}"), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheClientIsCached()
 | 
			
		||||
        {
 | 
			
		||||
            _cacheHandlers.Setup(x => x.Get(It.IsAny<DownstreamReRoute>())).Returns(_httpClient);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheCookieIsSet()
 | 
			
		||||
        {
 | 
			
		||||
            _response.Headers.TryGetValues("Set-Cookie", out var test).ShouldBeTrue();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheClient(string url)
 | 
			
		||||
        {
 | 
			
		||||
            _response = _httpClient
 | 
			
		||||
                .SendAsync(new HttpRequestMessage(HttpMethod.Get, url))
 | 
			
		||||
                .GetAwaiter()
 | 
			
		||||
                .GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheResponseIsOk()
 | 
			
		||||
        {
 | 
			
		||||
            _response.StatusCode.ShouldBe(HttpStatusCode.OK);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenADownstreamService()
 | 
			
		||||
        {
 | 
			
		||||
            _host = new WebHostBuilder()
 | 
			
		||||
                .UseUrls("http://localhost:5003")
 | 
			
		||||
                .UseKestrel()
 | 
			
		||||
                .UseContentRoot(Directory.GetCurrentDirectory())
 | 
			
		||||
                .UseIISIntegration()
 | 
			
		||||
                .Configure(app =>
 | 
			
		||||
                {
 | 
			
		||||
                    app.Run(context =>
 | 
			
		||||
                    {
 | 
			
		||||
                        if (_count == 0)
 | 
			
		||||
                        {
 | 
			
		||||
                            context.Response.Cookies.Append("test", "0");
 | 
			
		||||
                            context.Response.StatusCode = 200;
 | 
			
		||||
                            _count++;
 | 
			
		||||
                            return Task.CompletedTask;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        if (_count == 1)
 | 
			
		||||
                        {
 | 
			
		||||
                            if (context.Request.Cookies.TryGetValue("test", out var cookieValue) || context.Request.Headers.TryGetValue("Set-Cookie", out var headerValue))
 | 
			
		||||
                            {
 | 
			
		||||
                                context.Response.StatusCode = 200;
 | 
			
		||||
                                return Task.CompletedTask;
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            context.Response.StatusCode = 500;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        return Task.CompletedTask;
 | 
			
		||||
                    });
 | 
			
		||||
                })
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            _host.Start();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenARequest(DownstreamReRoute downstream)
 | 
			
		||||
        {
 | 
			
		||||
            GivenARequest(downstream, "http://localhost:5003");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenARequest(DownstreamReRoute downstream, string downstreamUrl)
 | 
			
		||||
        {
 | 
			
		||||
            GivenARequestWithAUrlAndMethod(downstream, downstreamUrl, HttpMethod.Get);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenARequestWithAUrlAndMethod(DownstreamReRoute downstream, string url, HttpMethod method)
 | 
			
		||||
        {
 | 
			
		||||
            _context = new DefaultHttpContext();
 | 
			
		||||
            _context.Items.UpsertDownstreamReRoute(downstream);
 | 
			
		||||
            _context.Items.UpsertDownstreamRequest(new DownstreamRequest(new HttpRequestMessage() { RequestUri = new Uri(url), Method = method }));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenSomethingIsReturned()
 | 
			
		||||
        {
 | 
			
		||||
            _response.ShouldNotBeNull();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheClient()
 | 
			
		||||
        {
 | 
			
		||||
            _response = _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, "http://test.com")).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheFakeAreHandledInOrder(FakeDelegatingHandler fakeOne, FakeDelegatingHandler fakeTwo)
 | 
			
		||||
        {
 | 
			
		||||
            fakeOne.TimeCalled.ShouldBeGreaterThan(fakeTwo.TimeCalled);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFactoryReturns()
 | 
			
		||||
        {
 | 
			
		||||
            var handlers = new List<Func<DelegatingHandler>>() { () => new FakeDelegatingHandler() };
 | 
			
		||||
 | 
			
		||||
            _factory
 | 
			
		||||
                .Setup(x => x.Get(It.IsAny<DownstreamReRoute>()))
 | 
			
		||||
                .Returns(new OkResponse<List<Func<DelegatingHandler>>>(handlers));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFactoryReturnsNothing()
 | 
			
		||||
        {
 | 
			
		||||
            var handlers = new List<Func<DelegatingHandler>>();
 | 
			
		||||
 | 
			
		||||
            _factory
 | 
			
		||||
                .Setup(x => x.Get(It.IsAny<DownstreamReRoute>()))
 | 
			
		||||
                .Returns(new OkResponse<List<Func<DelegatingHandler>>>(handlers));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFactoryReturns(List<Func<DelegatingHandler>> handlers)
 | 
			
		||||
        {
 | 
			
		||||
            _factory
 | 
			
		||||
               .Setup(x => x.Get(It.IsAny<DownstreamReRoute>()))
 | 
			
		||||
               .Returns(new OkResponse<List<Func<DelegatingHandler>>>(handlers));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIBuild()
 | 
			
		||||
        {
 | 
			
		||||
            _httpClient = _builder.Create(_context.Items.DownstreamReRoute());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIBuildTheFirstTime()
 | 
			
		||||
        {
 | 
			
		||||
            _firstHttpClient = _builder.Create(_context.Items.DownstreamReRoute());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIBuildAgain()
 | 
			
		||||
        {
 | 
			
		||||
            _builder = new HttpClientBuilder(_factory.Object, _realCache, _logger.Object);
 | 
			
		||||
            _againHttpClient = _builder.Create(_context.Items.DownstreamReRoute());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheHttpClientShouldNotBeNull()
 | 
			
		||||
        {
 | 
			
		||||
            _httpClient.ShouldNotBeNull();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            _response?.Dispose();
 | 
			
		||||
            _host?.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,202 +1,198 @@
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Configuration.Builder;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Ocelot.Request.Middleware;
 | 
			
		||||
using Ocelot.Requester;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Configuration.Builder;
 | 
			
		||||
using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Ocelot.Request.Middleware;
 | 
			
		||||
using Ocelot.Requester;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Requester
 | 
			
		||||
{
 | 
			
		||||
    public class HttpClientHttpRequesterTest
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Mock<IHttpClientCache> _cacheHandlers;
 | 
			
		||||
        private readonly Mock<IDelegatingHandlerHandlerFactory> _factory;
 | 
			
		||||
        private Response<HttpResponseMessage> _response;
 | 
			
		||||
        private readonly HttpClientHttpRequester _httpClientRequester;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private Mock<IExceptionToErrorMapper> _mapper;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
 | 
			
		||||
        public HttpClientHttpRequesterTest()
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
            _factory = new Mock<IDelegatingHandlerHandlerFactory>();
 | 
			
		||||
            _factory.Setup(x => x.Get(It.IsAny<DownstreamReRoute>())).Returns(new OkResponse<List<Func<DelegatingHandler>>>(new List<Func<DelegatingHandler>>()));
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _loggerFactory
 | 
			
		||||
                .Setup(x => x.CreateLogger<HttpClientHttpRequester>())
 | 
			
		||||
                .Returns(_logger.Object);
 | 
			
		||||
            _cacheHandlers = new Mock<IHttpClientCache>();
 | 
			
		||||
            _mapper = new Mock<IExceptionToErrorMapper>();
 | 
			
		||||
            _httpClientRequester = new HttpClientHttpRequester(
 | 
			
		||||
                _loggerFactory.Object,
 | 
			
		||||
                _cacheHandlers.Object,
 | 
			
		||||
                _factory.Object,
 | 
			
		||||
                _mapper.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_request_correctly()
 | 
			
		||||
        {
 | 
			
		||||
            var upstreamTemplate = new UpstreamPathTemplateBuilder().WithOriginalValue("").Build();
 | 
			
		||||
 | 
			
		||||
            var qosOptions = new QoSOptionsBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(upstreamTemplate)
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Requester
 | 
			
		||||
{
 | 
			
		||||
    public class HttpClientHttpRequesterTest
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Mock<IHttpClientCache> _cacheHandlers;
 | 
			
		||||
        private readonly Mock<IDelegatingHandlerHandlerFactory> _factory;
 | 
			
		||||
        private Response<HttpResponseMessage> _response;
 | 
			
		||||
        private readonly HttpClientHttpRequester _httpClientRequester;
 | 
			
		||||
        private DownstreamContext _request;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private Mock<IExceptionToErrorMapper> _mapper;
 | 
			
		||||
            var httpContext = new DefaultHttpContext();
 | 
			
		||||
            httpContext.Items.UpsertDownstreamReRoute(reRoute);
 | 
			
		||||
            httpContext.Items.UpsertDownstreamRequest(new DownstreamRequest(new HttpRequestMessage() { RequestUri = new Uri("http://www.bbc.co.uk") }));
 | 
			
		||||
 | 
			
		||||
        public HttpClientHttpRequesterTest()
 | 
			
		||||
        {
 | 
			
		||||
            _factory = new Mock<IDelegatingHandlerHandlerFactory>();
 | 
			
		||||
            _factory.Setup(x => x.Get(It.IsAny<DownstreamReRoute>())).Returns(new OkResponse<List<Func<DelegatingHandler>>>(new List<Func<DelegatingHandler>>()));
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _loggerFactory
 | 
			
		||||
                .Setup(x => x.CreateLogger<HttpClientHttpRequester>())
 | 
			
		||||
                .Returns(_logger.Object);
 | 
			
		||||
            _cacheHandlers = new Mock<IHttpClientCache>();
 | 
			
		||||
            _mapper = new Mock<IExceptionToErrorMapper>();
 | 
			
		||||
            _httpClientRequester = new HttpClientHttpRequester(
 | 
			
		||||
                _loggerFactory.Object,
 | 
			
		||||
                _cacheHandlers.Object,
 | 
			
		||||
                _factory.Object,
 | 
			
		||||
                _mapper.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_request_correctly()
 | 
			
		||||
        {
 | 
			
		||||
            var upstreamTemplate = new UpstreamPathTemplateBuilder().WithOriginalValue("").Build();
 | 
			
		||||
 | 
			
		||||
            var qosOptions = new QoSOptionsBuilder()
 | 
			
		||||
            this.Given(x => x.GivenTheRequestIs(httpContext))
 | 
			
		||||
                .And(x => GivenTheHouseReturnsOkHandler())
 | 
			
		||||
                .When(x => x.WhenIGetResponse())
 | 
			
		||||
                .Then(x => x.ThenTheResponseIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_request_unable_to_complete_request()
 | 
			
		||||
        {
 | 
			
		||||
            var upstreamTemplate = new UpstreamPathTemplateBuilder().WithOriginalValue("").Build();
 | 
			
		||||
 | 
			
		||||
            var qosOptions = new QoSOptionsBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(upstreamTemplate)
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(upstreamTemplate)
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
            var httpContext = new DefaultHttpContext();
 | 
			
		||||
            httpContext.Items.UpsertDownstreamReRoute(reRoute);
 | 
			
		||||
            httpContext.Items.UpsertDownstreamRequest(new DownstreamRequest(new HttpRequestMessage() { RequestUri = new Uri("http://localhost:60080") }));
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheRequestIs(httpContext))
 | 
			
		||||
                .When(x => x.WhenIGetResponse())
 | 
			
		||||
                .Then(x => x.ThenTheResponseIsCalledError())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void http_client_request_times_out()
 | 
			
		||||
        {
 | 
			
		||||
            var upstreamTemplate = new UpstreamPathTemplateBuilder().WithOriginalValue("").Build();
 | 
			
		||||
 | 
			
		||||
            var qosOptions = new QoSOptionsBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(upstreamTemplate)
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().WithTimeoutValue(1).Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var context = new DownstreamContext(new DefaultHttpContext())
 | 
			
		||||
            {
 | 
			
		||||
                DownstreamReRoute = reRoute,
 | 
			
		||||
                DownstreamRequest = new DownstreamRequest(new HttpRequestMessage() { RequestUri = new Uri("http://www.bbc.co.uk") }),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheRequestIs(context))
 | 
			
		||||
                .And(x => GivenTheHouseReturnsOkHandler())
 | 
			
		||||
                .When(x => x.WhenIGetResponse())
 | 
			
		||||
                .Then(x => x.ThenTheResponseIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_request_unable_to_complete_request()
 | 
			
		||||
        {
 | 
			
		||||
            var upstreamTemplate = new UpstreamPathTemplateBuilder().WithOriginalValue("").Build();
 | 
			
		||||
 | 
			
		||||
            var qosOptions = new QoSOptionsBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(upstreamTemplate)
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var context = new DownstreamContext(new DefaultHttpContext())
 | 
			
		||||
            {
 | 
			
		||||
                DownstreamReRoute = reRoute,
 | 
			
		||||
                DownstreamRequest = new DownstreamRequest(new HttpRequestMessage() { RequestUri = new Uri("http://localhost:60080") }),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheRequestIs(context))
 | 
			
		||||
                .When(x => x.WhenIGetResponse())
 | 
			
		||||
                .Then(x => x.ThenTheResponseIsCalledError())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void http_client_request_times_out()
 | 
			
		||||
        {
 | 
			
		||||
            var upstreamTemplate = new UpstreamPathTemplateBuilder().WithOriginalValue("").Build();
 | 
			
		||||
 | 
			
		||||
            var qosOptions = new QoSOptionsBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(upstreamTemplate)
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().WithTimeoutValue(1).Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var context = new DownstreamContext(new DefaultHttpContext())
 | 
			
		||||
            {
 | 
			
		||||
                DownstreamReRoute = reRoute,
 | 
			
		||||
                DownstreamRequest = new DownstreamRequest(new HttpRequestMessage() { RequestUri = new Uri("http://localhost:60080") }),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(_ => GivenTheRequestIs(context))
 | 
			
		||||
                .And(_ => GivenTheHouseReturnsTimeoutHandler())
 | 
			
		||||
                .When(_ => WhenIGetResponse())
 | 
			
		||||
                .Then(_ => ThenTheResponseIsCalledError())
 | 
			
		||||
                .And(_ => ThenTheErrorIsTimeout())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheRequestIs(DownstreamContext request)
 | 
			
		||||
        {
 | 
			
		||||
            _request = request;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIGetResponse()
 | 
			
		||||
        {
 | 
			
		||||
            _response = _httpClientRequester.GetResponse(_request).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheResponseIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _response.IsError.ShouldBeFalse();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheResponseIsCalledError()
 | 
			
		||||
        {
 | 
			
		||||
            _response.IsError.ShouldBeTrue();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheErrorIsTimeout()
 | 
			
		||||
        {
 | 
			
		||||
            _mapper.Verify(x => x.Map(It.IsAny<Exception>()), Times.Once);
 | 
			
		||||
            _response.Errors[0].ShouldBeOfType<UnableToCompleteRequestError>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheHouseReturnsOkHandler()
 | 
			
		||||
        {
 | 
			
		||||
            var handlers = new List<Func<DelegatingHandler>>
 | 
			
		||||
            {
 | 
			
		||||
                () => new OkDelegatingHandler()
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            _factory.Setup(x => x.Get(It.IsAny<DownstreamReRoute>())).Returns(new OkResponse<List<Func<DelegatingHandler>>>(handlers));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheHouseReturnsTimeoutHandler()
 | 
			
		||||
        {
 | 
			
		||||
            var handlers = new List<Func<DelegatingHandler>>
 | 
			
		||||
            {
 | 
			
		||||
                () => new TimeoutDelegatingHandler()
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            _factory.Setup(x => x.Get(It.IsAny<DownstreamReRoute>())).Returns(new OkResponse<List<Func<DelegatingHandler>>>(handlers));
 | 
			
		||||
 | 
			
		||||
            _mapper.Setup(x => x.Map(It.IsAny<Exception>())).Returns(new UnableToCompleteRequestError(new Exception()));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private class OkDelegatingHandler : DelegatingHandler
 | 
			
		||||
        {
 | 
			
		||||
            protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 | 
			
		||||
            {
 | 
			
		||||
                return Task.FromResult(new HttpResponseMessage());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private class TimeoutDelegatingHandler : DelegatingHandler
 | 
			
		||||
        {
 | 
			
		||||
            protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 | 
			
		||||
            {
 | 
			
		||||
                await Task.Delay(100000, cancellationToken);
 | 
			
		||||
                return new HttpResponseMessage();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
            var httpContext = new DefaultHttpContext();
 | 
			
		||||
            httpContext.Items.UpsertDownstreamReRoute(reRoute);
 | 
			
		||||
            httpContext.Items.UpsertDownstreamRequest(new DownstreamRequest(new HttpRequestMessage() { RequestUri = new Uri("http://localhost:60080") }));
 | 
			
		||||
 | 
			
		||||
            this.Given(_ => GivenTheRequestIs(httpContext))
 | 
			
		||||
                .And(_ => GivenTheHouseReturnsTimeoutHandler())
 | 
			
		||||
                .When(_ => WhenIGetResponse())
 | 
			
		||||
                .Then(_ => ThenTheResponseIsCalledError())
 | 
			
		||||
                .And(_ => ThenTheErrorIsTimeout())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheRequestIs(HttpContext httpContext)
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext = httpContext;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIGetResponse()
 | 
			
		||||
        {
 | 
			
		||||
            _response = _httpClientRequester.GetResponse(_httpContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheResponseIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _response.IsError.ShouldBeFalse();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheResponseIsCalledError()
 | 
			
		||||
        {
 | 
			
		||||
            _response.IsError.ShouldBeTrue();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheErrorIsTimeout()
 | 
			
		||||
        {
 | 
			
		||||
            _mapper.Verify(x => x.Map(It.IsAny<Exception>()), Times.Once);
 | 
			
		||||
            _response.Errors[0].ShouldBeOfType<UnableToCompleteRequestError>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheHouseReturnsOkHandler()
 | 
			
		||||
        {
 | 
			
		||||
            var handlers = new List<Func<DelegatingHandler>>
 | 
			
		||||
            {
 | 
			
		||||
                () => new OkDelegatingHandler()
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            _factory.Setup(x => x.Get(It.IsAny<DownstreamReRoute>())).Returns(new OkResponse<List<Func<DelegatingHandler>>>(handlers));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheHouseReturnsTimeoutHandler()
 | 
			
		||||
        {
 | 
			
		||||
            var handlers = new List<Func<DelegatingHandler>>
 | 
			
		||||
            {
 | 
			
		||||
                () => new TimeoutDelegatingHandler()
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            _factory.Setup(x => x.Get(It.IsAny<DownstreamReRoute>())).Returns(new OkResponse<List<Func<DelegatingHandler>>>(handlers));
 | 
			
		||||
 | 
			
		||||
            _mapper.Setup(x => x.Map(It.IsAny<Exception>())).Returns(new UnableToCompleteRequestError(new Exception()));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private class OkDelegatingHandler : DelegatingHandler
 | 
			
		||||
        {
 | 
			
		||||
            protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 | 
			
		||||
            {
 | 
			
		||||
                return Task.FromResult(new HttpResponseMessage());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private class TimeoutDelegatingHandler : DelegatingHandler
 | 
			
		||||
        {
 | 
			
		||||
            protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 | 
			
		||||
            {
 | 
			
		||||
                await Task.Delay(100000, cancellationToken);
 | 
			
		||||
                return new HttpResponseMessage();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,132 +1,132 @@
 | 
			
		||||
namespace Ocelot.UnitTests.Requester
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Ocelot.Requester;
 | 
			
		||||
    using Ocelot.Requester.Middleware;
 | 
			
		||||
    using Ocelot.Responses;
 | 
			
		||||
    using Ocelot.UnitTests.Responder;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Linq;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
namespace Ocelot.UnitTests.Requester
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Ocelot.Requester;
 | 
			
		||||
    using Ocelot.Requester.Middleware;
 | 
			
		||||
    using Ocelot.Responses;
 | 
			
		||||
    using Ocelot.UnitTests.Responder;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Linq;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Infrastructure.RequestData;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
 | 
			
		||||
    public class HttpRequesterMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Mock<IHttpRequester> _requester;
 | 
			
		||||
        private Response<HttpResponseMessage> _response;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private readonly HttpRequesterMiddleware _middleware;
 | 
			
		||||
        private DownstreamContext _downstreamContext;
 | 
			
		||||
        private OcelotRequestDelegate _next;
 | 
			
		||||
 | 
			
		||||
        public HttpRequesterMiddlewareTests()
 | 
			
		||||
    public class HttpRequesterMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Mock<IHttpRequester> _requester;
 | 
			
		||||
        private Response<HttpResponseMessage> _response;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private readonly HttpRequesterMiddleware _middleware;
 | 
			
		||||
        private RequestDelegate _next;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
 | 
			
		||||
        public HttpRequesterMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
            _requester = new Mock<IHttpRequester>();
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<HttpRequesterMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _next = context => Task.CompletedTask;
 | 
			
		||||
            _middleware = new HttpRequesterMiddleware(_next, _loggerFactory.Object, _requester.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_services_correctly()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenTheRequestIs())
 | 
			
		||||
                .And(x => x.GivenTheRequesterReturns(new OkResponse<HttpResponseMessage>(new HttpResponseMessage(System.Net.HttpStatusCode.OK))))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheDownstreamResponseIsSet())
 | 
			
		||||
                .Then(x => InformationIsLogged())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_set_error()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenTheRequestIs())
 | 
			
		||||
                .And(x => x.GivenTheRequesterReturns(new ErrorResponse<HttpResponseMessage>(new AnyError())))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheErrorIsSet())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_log_downstream_internal_server_error()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenTheRequestIs())
 | 
			
		||||
                    .And(x => x.GivenTheRequesterReturns(
 | 
			
		||||
                        new OkResponse<HttpResponseMessage>(new HttpResponseMessage(System.Net.HttpStatusCode.InternalServerError))))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.WarningIsLogged())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheErrorIsSet()
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext.Items.Errors().Count.ShouldBeGreaterThan(0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_httpContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheRequestIs()
 | 
			
		||||
        {
 | 
			
		||||
            _requester = new Mock<IHttpRequester>();
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<HttpRequesterMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _next = context => Task.CompletedTask;
 | 
			
		||||
            _middleware = new HttpRequesterMiddleware(_next, _loggerFactory.Object, _requester.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_services_correctly()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenTheRequestIs())
 | 
			
		||||
                .And(x => x.GivenTheRequesterReturns(new OkResponse<HttpResponseMessage>(new HttpResponseMessage(System.Net.HttpStatusCode.OK))))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheDownstreamResponseIsSet())
 | 
			
		||||
                .Then(x => InformationIsLogged())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_set_error()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenTheRequestIs())
 | 
			
		||||
                .And(x => x.GivenTheRequesterReturns(new ErrorResponse<HttpResponseMessage>(new AnyError())))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheErrorIsSet())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_log_downstream_internal_server_error()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenTheRequestIs())
 | 
			
		||||
                    .And(x => x.GivenTheRequesterReturns(
 | 
			
		||||
                        new OkResponse<HttpResponseMessage>(new HttpResponseMessage(System.Net.HttpStatusCode.InternalServerError))))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.WarningIsLogged())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheErrorIsSet()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.IsError.ShouldBeTrue();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheRequestIs()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext =
 | 
			
		||||
                new DownstreamContext(new DefaultHttpContext())
 | 
			
		||||
                {
 | 
			
		||||
                    DownstreamReRoute = new DownstreamReRouteBuilder().Build()
 | 
			
		||||
                };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheRequesterReturns(Response<HttpResponseMessage> response)
 | 
			
		||||
        {
 | 
			
		||||
            _response = response;
 | 
			
		||||
 | 
			
		||||
            _requester
 | 
			
		||||
                .Setup(x => x.GetResponse(It.IsAny<DownstreamContext>()))
 | 
			
		||||
                .ReturnsAsync(_response);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheDownstreamResponseIsSet()
 | 
			
		||||
        {
 | 
			
		||||
            foreach (var httpResponseHeader in _response.Data.Headers)
 | 
			
		||||
            {
 | 
			
		||||
                if (_downstreamContext.DownstreamResponse.Headers.Any(x => x.Key == httpResponseHeader.Key))
 | 
			
		||||
                {
 | 
			
		||||
                    throw new Exception("Header in response not in downstreamresponse headers");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            _downstreamContext.DownstreamResponse.Content.ShouldBe(_response.Data.Content);
 | 
			
		||||
            _downstreamContext.DownstreamResponse.StatusCode.ShouldBe(_response.Data.StatusCode);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WarningIsLogged()
 | 
			
		||||
        {
 | 
			
		||||
            _logger.Verify(
 | 
			
		||||
                x => x.LogWarning(                 
 | 
			
		||||
                    It.IsAny<string>()
 | 
			
		||||
                   ),
 | 
			
		||||
                Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void InformationIsLogged()
 | 
			
		||||
        {
 | 
			
		||||
            _logger.Verify(
 | 
			
		||||
                x => x.LogInformation(
 | 
			
		||||
                    It.IsAny<string>()
 | 
			
		||||
                ),
 | 
			
		||||
                Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamReRoute(new DownstreamReRouteBuilder().Build());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheRequesterReturns(Response<HttpResponseMessage> response)
 | 
			
		||||
        {
 | 
			
		||||
            _response = response;
 | 
			
		||||
 | 
			
		||||
            _requester
 | 
			
		||||
                .Setup(x => x.GetResponse(It.IsAny<HttpContext>()))
 | 
			
		||||
                .ReturnsAsync(_response);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheDownstreamResponseIsSet()
 | 
			
		||||
        {
 | 
			
		||||
            foreach (var httpResponseHeader in _response.Data.Headers)
 | 
			
		||||
            {
 | 
			
		||||
                if (_httpContext.Items.DownstreamResponse().Headers.Any(x => x.Key == httpResponseHeader.Key))
 | 
			
		||||
                {
 | 
			
		||||
                    throw new Exception("Header in response not in downstreamresponse headers");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            _httpContext.Items.DownstreamResponse().Content.ShouldBe(_response.Data.Content);
 | 
			
		||||
            _httpContext.Items.DownstreamResponse().StatusCode.ShouldBe(_response.Data.StatusCode);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WarningIsLogged()
 | 
			
		||||
        {
 | 
			
		||||
            _logger.Verify(
 | 
			
		||||
                x => x.LogWarning(                 
 | 
			
		||||
                    It.IsAny<string>()
 | 
			
		||||
                   ),
 | 
			
		||||
                Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void InformationIsLogged()
 | 
			
		||||
        {
 | 
			
		||||
            _logger.Verify(
 | 
			
		||||
                x => x.LogInformation(
 | 
			
		||||
                    It.IsAny<string>()
 | 
			
		||||
                ),
 | 
			
		||||
                Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,15 +1,15 @@
 | 
			
		||||
using Ocelot.Errors;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Responder
 | 
			
		||||
{
 | 
			
		||||
    internal class AnyError : Error
 | 
			
		||||
    {
 | 
			
		||||
        public AnyError() : base("blahh", OcelotErrorCode.UnknownError)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public AnyError(OcelotErrorCode errorCode) : base("blah", errorCode)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
using Ocelot.Errors;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Responder
 | 
			
		||||
{
 | 
			
		||||
    internal class AnyError : Error
 | 
			
		||||
    {
 | 
			
		||||
        public AnyError() : base("blahh", OcelotErrorCode.UnknownError, 404)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public AnyError(OcelotErrorCode errorCode) : base("blah", errorCode, 404)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,78 +1,80 @@
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Responder
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.Finder;
 | 
			
		||||
    using Ocelot.Errors;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Responder;
 | 
			
		||||
    using Ocelot.Responder.Middleware;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class ResponderMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Mock<IHttpResponder> _responder;
 | 
			
		||||
        private readonly Mock<IErrorsToHttpStatusCodeMapper> _codeMapper;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private readonly ResponderMiddleware _middleware;
 | 
			
		||||
        private readonly DownstreamContext _downstreamContext;
 | 
			
		||||
        private OcelotRequestDelegate _next;
 | 
			
		||||
 | 
			
		||||
        public ResponderMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _responder = new Mock<IHttpResponder>();
 | 
			
		||||
            _codeMapper = new Mock<IErrorsToHttpStatusCodeMapper>();
 | 
			
		||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<ResponderMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _next = context => Task.CompletedTask;
 | 
			
		||||
            _middleware = new ResponderMiddleware(_next, _responder.Object, _loggerFactory.Object, _codeMapper.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_return_any_errors()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenTheHttpResponseMessageIs(new DownstreamResponse(new HttpResponseMessage())))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenThereAreNoErrors())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_any_errors()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenTheHttpResponseMessageIs(new DownstreamResponse(new HttpResponseMessage())))
 | 
			
		||||
                .And(x => x.GivenThereArePipelineErrors(new UnableToFindDownstreamRouteError("/path", "GET")))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenThereAreNoErrors())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheHttpResponseMessageIs(DownstreamResponse response)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.DownstreamResponse = response;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenThereAreNoErrors()
 | 
			
		||||
        {
 | 
			
		||||
            //todo a better assert?
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereArePipelineErrors(Error error)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.Errors.Add(error);
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Responder
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.Finder;
 | 
			
		||||
    using Ocelot.Errors;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Responder;
 | 
			
		||||
    using Ocelot.Responder.Middleware;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using Ocelot.Infrastructure.RequestData;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
 | 
			
		||||
    public class ResponderMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Mock<IHttpResponder> _responder;
 | 
			
		||||
        private readonly Mock<IErrorsToHttpStatusCodeMapper> _codeMapper;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private readonly ResponderMiddleware _middleware;
 | 
			
		||||
        private RequestDelegate _next;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
 | 
			
		||||
        public ResponderMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
            _responder = new Mock<IHttpResponder>();
 | 
			
		||||
            _codeMapper = new Mock<IErrorsToHttpStatusCodeMapper>();
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<ResponderMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _next = context => Task.CompletedTask;
 | 
			
		||||
            _middleware = new ResponderMiddleware(_next, _responder.Object, _loggerFactory.Object, _codeMapper.Object);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_return_any_errors()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenTheHttpResponseMessageIs(new DownstreamResponse(new HttpResponseMessage())))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenThereAreNoErrors())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_any_errors()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenTheHttpResponseMessageIs(new DownstreamResponse(new HttpResponseMessage())))
 | 
			
		||||
                .And(x => x.GivenThereArePipelineErrors(new UnableToFindDownstreamRouteError("/path", "GET")))
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenThereAreNoErrors())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_httpContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheHttpResponseMessageIs(DownstreamResponse response)
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamResponse(response);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenThereAreNoErrors()
 | 
			
		||||
        {
 | 
			
		||||
            //todo a better assert?
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereArePipelineErrors(Error error)
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext.Items.SetError(error);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,36 +1,37 @@
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Configuration.Builder;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Ocelot.Request.Middleware;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Ocelot.Security.IPSecurity;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Net;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Security
 | 
			
		||||
namespace Ocelot.UnitTests.Security
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Ocelot.Request.Middleware;
 | 
			
		||||
    using Ocelot.Responses;
 | 
			
		||||
    using Ocelot.Security.IPSecurity;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Net;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class IPSecurityPolicyTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly DownstreamContext _downstreamContext;
 | 
			
		||||
        private readonly DownstreamReRouteBuilder _downstreamReRouteBuilder;
 | 
			
		||||
        private readonly IPSecurityPolicy _ipSecurityPolicy;
 | 
			
		||||
        private Response response;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
 | 
			
		||||
        public IPSecurityPolicyTests()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
            _downstreamContext.DownstreamRequest = new DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "http://test.com"));
 | 
			
		||||
            _downstreamContext.HttpContext.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.1")[0];
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamRequest(new DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "http://test.com")));
 | 
			
		||||
            _httpContext.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.1")[0];
 | 
			
		||||
            _downstreamReRouteBuilder = new DownstreamReRouteBuilder();
 | 
			
		||||
            _ipSecurityPolicy = new IPSecurityPolicy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        private void should_No_blocked_Ip_and_allowed_Ip()
 | 
			
		||||
        public void should_No_blocked_Ip_and_allowed_Ip()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenSetDownstreamReRoute())
 | 
			
		||||
                .When(x => x.WhenTheSecurityPolicy())
 | 
			
		||||
@@ -39,9 +40,9 @@ namespace Ocelot.UnitTests.Security
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        private void should_blockedIp_clientIp_block()
 | 
			
		||||
        public void should_blockedIp_clientIp_block()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.HttpContext.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.1")[0];
 | 
			
		||||
            _httpContext.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.1")[0];
 | 
			
		||||
            this.Given(x => x.GivenSetBlockedIP())
 | 
			
		||||
                .Given(x => x.GivenSetDownstreamReRoute())
 | 
			
		||||
                .When(x => x.WhenTheSecurityPolicy())
 | 
			
		||||
@@ -50,9 +51,9 @@ namespace Ocelot.UnitTests.Security
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        private void should_blockedIp_clientIp_Not_block()
 | 
			
		||||
        public void should_blockedIp_clientIp_Not_block()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.HttpContext.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.2")[0];
 | 
			
		||||
            _httpContext.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.2")[0];
 | 
			
		||||
            this.Given(x => x.GivenSetBlockedIP())
 | 
			
		||||
                .Given(x => x.GivenSetDownstreamReRoute())
 | 
			
		||||
                .When(x => x.WhenTheSecurityPolicy())
 | 
			
		||||
@@ -61,9 +62,9 @@ namespace Ocelot.UnitTests.Security
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        private void should_allowedIp_clientIp_block()
 | 
			
		||||
        public void should_allowedIp_clientIp_block()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.HttpContext.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.1")[0];
 | 
			
		||||
            _httpContext.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.1")[0];
 | 
			
		||||
            this.Given(x => x.GivenSetAllowedIP())
 | 
			
		||||
                .Given(x => x.GivenSetDownstreamReRoute())
 | 
			
		||||
                .When(x => x.WhenTheSecurityPolicy())
 | 
			
		||||
@@ -72,9 +73,9 @@ namespace Ocelot.UnitTests.Security
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        private void should_allowedIp_clientIp_Not_block()
 | 
			
		||||
        public void should_allowedIp_clientIp_Not_block()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.HttpContext.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.2")[0];
 | 
			
		||||
            _httpContext.Connection.RemoteIpAddress = Dns.GetHostAddresses("192.168.1.2")[0];
 | 
			
		||||
            this.Given(x => x.GivenSetAllowedIP())
 | 
			
		||||
                .Given(x => x.GivenSetDownstreamReRoute())
 | 
			
		||||
                .When(x => x.WhenTheSecurityPolicy())
 | 
			
		||||
@@ -94,12 +95,12 @@ namespace Ocelot.UnitTests.Security
 | 
			
		||||
 | 
			
		||||
        private void GivenSetDownstreamReRoute()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.DownstreamReRoute = _downstreamReRouteBuilder.Build();
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamReRoute(_downstreamReRouteBuilder.Build());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenTheSecurityPolicy()
 | 
			
		||||
        {
 | 
			
		||||
            response = this._ipSecurityPolicy.Security(_downstreamContext).GetAwaiter().GetResult();
 | 
			
		||||
            response = _ipSecurityPolicy.Security(_httpContext.Items.DownstreamReRoute(), _httpContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenSecurityPassing()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,106 +1,110 @@
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Errors;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Ocelot.Request.Middleware;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Ocelot.Security;
 | 
			
		||||
using Ocelot.Security.Middleware;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Security
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Errors;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Ocelot.Request.Middleware;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Ocelot.Security;
 | 
			
		||||
using Ocelot.Security.Middleware;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Security
 | 
			
		||||
{
 | 
			
		||||
    public class SecurityMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private List<Mock<ISecurityPolicy>> _securityPolicyList;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private readonly SecurityMiddleware _middleware;
 | 
			
		||||
        private readonly DownstreamContext _downstreamContext;
 | 
			
		||||
        private readonly OcelotRequestDelegate _next;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
    using Ocelot.Infrastructure.RequestData;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
 | 
			
		||||
        public SecurityMiddlewareTests()
 | 
			
		||||
    public class SecurityMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private List<Mock<ISecurityPolicy>> _securityPolicyList;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private readonly SecurityMiddleware _middleware;
 | 
			
		||||
        private readonly RequestDelegate _next;
 | 
			
		||||
        private HttpContext _httpContext;
 | 
			
		||||
 | 
			
		||||
        public SecurityMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext = new DefaultHttpContext();
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<SecurityMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _securityPolicyList = new List<Mock<ISecurityPolicy>>();
 | 
			
		||||
            _securityPolicyList.Add(new Mock<ISecurityPolicy>());
 | 
			
		||||
            _securityPolicyList.Add(new Mock<ISecurityPolicy>());
 | 
			
		||||
            _next = context =>
 | 
			
		||||
            {
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            };
 | 
			
		||||
            _middleware = new SecurityMiddleware(_next, _loggerFactory.Object, _securityPolicyList.Select(f => f.Object).ToList());
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamRequest(new DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "http://test.com")));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_legal_request()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenPassingSecurityVerification())
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheRequestIsPassingSecurity())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_verification_failed_request()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenNotPassingSecurityVerification())
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheRequestIsNotPassingSecurity())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenPassingSecurityVerification()
 | 
			
		||||
        {
 | 
			
		||||
            foreach (var item in _securityPolicyList)
 | 
			
		||||
            {
 | 
			
		||||
                Response response = new OkResponse();
 | 
			
		||||
                item.Setup(x => x.Security(_httpContext.Items.DownstreamReRoute(), _httpContext)).Returns(Task.FromResult(response));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenNotPassingSecurityVerification()
 | 
			
		||||
        {
 | 
			
		||||
            for (int i = 0; i < _securityPolicyList.Count; i++)
 | 
			
		||||
            {
 | 
			
		||||
                Mock<ISecurityPolicy> item = _securityPolicyList[i];
 | 
			
		||||
                if (i == 0)
 | 
			
		||||
                {
 | 
			
		||||
                    Error error = new UnauthenticatedError($"Not passing security verification");
 | 
			
		||||
                    Response response = new ErrorResponse(error);
 | 
			
		||||
                    item.Setup(x => x.Security(_httpContext.Items.DownstreamReRoute(), _httpContext)).Returns(Task.FromResult(response));
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    Response response = new OkResponse();
 | 
			
		||||
                    item.Setup(x => x.Security(_httpContext.Items.DownstreamReRoute(), _httpContext)).Returns(Task.FromResult(response));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_httpContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheRequestIsPassingSecurity()
 | 
			
		||||
        {
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<SecurityMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _securityPolicyList = new List<Mock<ISecurityPolicy>>();
 | 
			
		||||
            _securityPolicyList.Add(new Mock<ISecurityPolicy>());
 | 
			
		||||
            _securityPolicyList.Add(new Mock<ISecurityPolicy>());
 | 
			
		||||
            _next = context =>
 | 
			
		||||
            {
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            };
 | 
			
		||||
            _middleware = new SecurityMiddleware(_loggerFactory.Object, _securityPolicyList.Select(f => f.Object).ToList(), _next);
 | 
			
		||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
            _downstreamContext.DownstreamRequest = new DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "http://test.com"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_legal_request()
 | 
			
		||||
            _httpContext.Items.Errors().Count.ShouldBe(0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheRequestIsNotPassingSecurity()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenPassingSecurityVerification())
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheRequestIsPassingSecurity())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_verification_failed_request()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenNotPassingSecurityVerification())
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheRequestIsNotPassingSecurity())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenPassingSecurityVerification()
 | 
			
		||||
        {
 | 
			
		||||
            foreach (var item in _securityPolicyList)
 | 
			
		||||
            {
 | 
			
		||||
                Response response = new OkResponse();
 | 
			
		||||
                item.Setup(x => x.Security(_downstreamContext)).Returns(Task.FromResult(response));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenNotPassingSecurityVerification()
 | 
			
		||||
        {
 | 
			
		||||
            for (int i = 0; i < _securityPolicyList.Count; i++)
 | 
			
		||||
            {
 | 
			
		||||
                Mock<ISecurityPolicy> item = _securityPolicyList[i];
 | 
			
		||||
                if (i == 0)
 | 
			
		||||
                {
 | 
			
		||||
                    Error error = new UnauthenticatedError($"Not passing security verification");
 | 
			
		||||
                    Response response = new ErrorResponse(error);
 | 
			
		||||
                    item.Setup(x => x.Security(_downstreamContext)).Returns(Task.FromResult(response));
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    Response response = new OkResponse();
 | 
			
		||||
                    item.Setup(x => x.Security(_downstreamContext)).Returns(Task.FromResult(response));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheRequestIsPassingSecurity()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.False(_downstreamContext.IsError);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheRequestIsNotPassingSecurity()
 | 
			
		||||
        {
 | 
			
		||||
            Assert.True(_downstreamContext.IsError);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
            _httpContext.Items.Errors().Count.ShouldBeGreaterThan(0);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user