mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 15:50:49 +08:00 
			
		
		
		
	Rename all ReRoute to Route to move closer to YARP +semver: breaking
This commit is contained in:
		
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,446 +1,446 @@
 | 
			
		||||
using Microsoft.AspNetCore.Builder;
 | 
			
		||||
using Microsoft.AspNetCore.Hosting;
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Configuration.Builder;
 | 
			
		||||
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)
 | 
			
		||||
        {
 | 
			
		||||
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 route = new DownstreamRouteBuilder()
 | 
			
		||||
                .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(route))
 | 
			
		||||
                .When(x => WhenIBuild())
 | 
			
		||||
                .Then(x => ThenTheHttpClientShouldNotBeNull())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_get_from_cache()
 | 
			
		||||
        {
 | 
			
		||||
            var qosOptions = new QoSOptionsBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var route = new DownstreamRouteBuilder()
 | 
			
		||||
                .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(route))
 | 
			
		||||
                .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 route = new DownstreamRouteBuilder()
 | 
			
		||||
                .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(route, "http://wwww.someawesomewebsite.com/woot?badman=1"))
 | 
			
		||||
                .And(x => WhenIBuildTheFirstTime())
 | 
			
		||||
                .And(x => WhenISave())
 | 
			
		||||
                .And(x => WhenIBuildAgain())
 | 
			
		||||
                .And(x => GivenARequest(route, "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 routeA = new DownstreamRouteBuilder()
 | 
			
		||||
                .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 routeB = new DownstreamRouteBuilder()
 | 
			
		||||
                .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(routeA, "http://wwww.someawesomewebsite.com/woot?badman=1"))
 | 
			
		||||
                .And(x => WhenIBuildTheFirstTime())
 | 
			
		||||
                .And(x => WhenISave())
 | 
			
		||||
                .And(x => WhenIBuildAgain())
 | 
			
		||||
                .And(x => GivenARequest(routeB, "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 route = new DownstreamRouteBuilder()
 | 
			
		||||
                .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(route))
 | 
			
		||||
                .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 route = new DownstreamRouteBuilder()
 | 
			
		||||
                .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(route))
 | 
			
		||||
                .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 route = new DownstreamRouteBuilder()
 | 
			
		||||
                .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(route))
 | 
			
		||||
                .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 route = new DownstreamRouteBuilder()
 | 
			
		||||
                .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(route, 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<DownstreamRoute>()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheDangerousAcceptAnyServerCertificateValidatorWarningIsLogged()
 | 
			
		||||
        {
 | 
			
		||||
            _logger.Verify(x => x.LogWarning($"You have ignored all SSL warnings by using DangerousAcceptAnyServerCertificateValidator for this DownstreamRoute, UpstreamPathTemplate: {_context.Items.DownstreamRoute().UpstreamPathTemplate}, DownstreamPathTemplate: {_context.Items.DownstreamRoute().DownstreamPathTemplate}"), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheClientIsCached()
 | 
			
		||||
        {
 | 
			
		||||
            _cacheHandlers.Setup(x => x.Get(It.IsAny<DownstreamRoute>())).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(DownstreamRoute downstream)
 | 
			
		||||
        {
 | 
			
		||||
            GivenARequest(downstream, "http://localhost:5003");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenARequest(DownstreamRoute downstream, string downstreamUrl)
 | 
			
		||||
        {
 | 
			
		||||
            GivenARequestWithAUrlAndMethod(downstream, downstreamUrl, HttpMethod.Get);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenARequestWithAUrlAndMethod(DownstreamRoute 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();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
            _context.Items.UpsertDownstreamRoute(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<DownstreamRoute>()))
 | 
			
		||||
                .Returns(new OkResponse<List<Func<DelegatingHandler>>>(handlers));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFactoryReturnsNothing()
 | 
			
		||||
        {
 | 
			
		||||
            var handlers = new List<Func<DelegatingHandler>>();
 | 
			
		||||
 | 
			
		||||
            _factory
 | 
			
		||||
                .Setup(x => x.Get(It.IsAny<DownstreamRoute>()))
 | 
			
		||||
                .Returns(new OkResponse<List<Func<DelegatingHandler>>>(handlers));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFactoryReturns(List<Func<DelegatingHandler>> handlers)
 | 
			
		||||
        {
 | 
			
		||||
            _factory
 | 
			
		||||
               .Setup(x => x.Get(It.IsAny<DownstreamRoute>()))
 | 
			
		||||
               .Returns(new OkResponse<List<Func<DelegatingHandler>>>(handlers));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIBuild()
 | 
			
		||||
        {
 | 
			
		||||
            _httpClient = _builder.Create(_context.Items.DownstreamRoute());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIBuildTheFirstTime()
 | 
			
		||||
        {
 | 
			
		||||
            _firstHttpClient = _builder.Create(_context.Items.DownstreamRoute());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIBuildAgain()
 | 
			
		||||
        {
 | 
			
		||||
            _builder = new HttpClientBuilder(_factory.Object, _realCache, _logger.Object);
 | 
			
		||||
            _againHttpClient = _builder.Create(_context.Items.DownstreamRoute());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheHttpClientShouldNotBeNull()
 | 
			
		||||
        {
 | 
			
		||||
            _httpClient.ShouldNotBeNull();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            _response?.Dispose();
 | 
			
		||||
            _host?.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Configuration.Builder;
 | 
			
		||||
using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Ocelot.Request.Middleware;
 | 
			
		||||
@@ -34,7 +34,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
        {
 | 
			
		||||
            _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>>()));
 | 
			
		||||
            _factory.Setup(x => x.Get(It.IsAny<DownstreamRoute>())).Returns(new OkResponse<List<Func<DelegatingHandler>>>(new List<Func<DelegatingHandler>>()));
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _loggerFactory
 | 
			
		||||
@@ -57,18 +57,18 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
            var qosOptions = new QoSOptionsBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
            var route = new DownstreamRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(upstreamTemplate)
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var httpContext = new DefaultHttpContext();
 | 
			
		||||
            httpContext.Items.UpsertDownstreamReRoute(reRoute);
 | 
			
		||||
            httpContext.Items.UpsertDownstreamRequest(new DownstreamRequest(new HttpRequestMessage() { RequestUri = new Uri("http://www.bbc.co.uk") }));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            var httpContext = new DefaultHttpContext();
 | 
			
		||||
            httpContext.Items.UpsertDownstreamRoute(route);
 | 
			
		||||
            httpContext.Items.UpsertDownstreamRequest(new DownstreamRequest(new HttpRequestMessage() { RequestUri = new Uri("http://www.bbc.co.uk") }));
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheRequestIs(httpContext))
 | 
			
		||||
                .And(x => GivenTheHouseReturnsOkHandler())
 | 
			
		||||
                .When(x => x.WhenIGetResponse())
 | 
			
		||||
@@ -84,17 +84,17 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
            var qosOptions = new QoSOptionsBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
            var route = new DownstreamRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(upstreamTemplate)
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var httpContext = new DefaultHttpContext();
 | 
			
		||||
            httpContext.Items.UpsertDownstreamReRoute(reRoute);
 | 
			
		||||
            httpContext.Items.UpsertDownstreamRequest(new DownstreamRequest(new HttpRequestMessage() { RequestUri = new Uri("http://localhost:60080") }));
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var httpContext = new DefaultHttpContext();
 | 
			
		||||
            httpContext.Items.UpsertDownstreamRoute(route);
 | 
			
		||||
            httpContext.Items.UpsertDownstreamRequest(new DownstreamRequest(new HttpRequestMessage() { RequestUri = new Uri("http://localhost:60080") }));
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheRequestIs(httpContext))
 | 
			
		||||
                .When(x => x.WhenIGetResponse())
 | 
			
		||||
@@ -110,17 +110,17 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
            var qosOptions = new QoSOptionsBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
            var route = new DownstreamRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(upstreamTemplate)
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().WithTimeoutValue(1).Build())
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var httpContext = new DefaultHttpContext();
 | 
			
		||||
            httpContext.Items.UpsertDownstreamReRoute(reRoute);
 | 
			
		||||
            httpContext.Items.UpsertDownstreamRequest(new DownstreamRequest(new HttpRequestMessage() { RequestUri = new Uri("http://localhost:60080") }));
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var httpContext = new DefaultHttpContext();
 | 
			
		||||
            httpContext.Items.UpsertDownstreamRoute(route);
 | 
			
		||||
            httpContext.Items.UpsertDownstreamRequest(new DownstreamRequest(new HttpRequestMessage() { RequestUri = new Uri("http://localhost:60080") }));
 | 
			
		||||
 | 
			
		||||
            this.Given(_ => GivenTheRequestIs(httpContext))
 | 
			
		||||
                .And(_ => GivenTheHouseReturnsTimeoutHandler())
 | 
			
		||||
@@ -163,7 +163,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
                () => new OkDelegatingHandler()
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            _factory.Setup(x => x.Get(It.IsAny<DownstreamReRoute>())).Returns(new OkResponse<List<Func<DelegatingHandler>>>(handlers));
 | 
			
		||||
            _factory.Setup(x => x.Get(It.IsAny<DownstreamRoute>())).Returns(new OkResponse<List<Func<DelegatingHandler>>>(handlers));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheHouseReturnsTimeoutHandler()
 | 
			
		||||
@@ -173,7 +173,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
                () => new TimeoutDelegatingHandler()
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            _factory.Setup(x => x.Get(It.IsAny<DownstreamReRoute>())).Returns(new OkResponse<List<Func<DelegatingHandler>>>(handlers));
 | 
			
		||||
            _factory.Setup(x => x.Get(It.IsAny<DownstreamRoute>())).Returns(new OkResponse<List<Func<DelegatingHandler>>>(handlers));
 | 
			
		||||
 | 
			
		||||
            _mapper.Setup(x => x.Map(It.IsAny<Exception>())).Returns(new UnableToCompleteRequestError(new Exception()));
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -17,9 +17,9 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Infrastructure.RequestData;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
 | 
			
		||||
    using Xunit;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
 | 
			
		||||
    public class HttpRequesterMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Mock<IHttpRequester> _requester;
 | 
			
		||||
@@ -84,8 +84,8 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheRequestIs()
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamReRoute(new DownstreamReRouteBuilder().Build());
 | 
			
		||||
        {
 | 
			
		||||
            _httpContext.Items.UpsertDownstreamRoute(new DownstreamRouteBuilder().Build());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheRequesterReturns(Response<HttpResponseMessage> response)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,55 +1,55 @@
 | 
			
		||||
namespace Ocelot.UnitTests.Requester
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Requester;
 | 
			
		||||
    using Ocelot.Requester.QoS;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class QoSFactoryTests
 | 
			
		||||
    {
 | 
			
		||||
        private QoSFactory _factory;
 | 
			
		||||
        private ServiceCollection _services;
 | 
			
		||||
        private readonly Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
 | 
			
		||||
        public QoSFactoryTests()
 | 
			
		||||
        {
 | 
			
		||||
            _services = new ServiceCollection();
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            var provider = _services.BuildServiceProvider();
 | 
			
		||||
            _factory = new QoSFactory(provider, _loggerFactory.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_error()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamReRoute = new DownstreamReRouteBuilder().Build();
 | 
			
		||||
            var handler = _factory.Get(downstreamReRoute);
 | 
			
		||||
            handler.IsError.ShouldBeTrue();
 | 
			
		||||
            handler.Errors[0].ShouldBeOfType<UnableToFindQoSProviderError>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_handler()
 | 
			
		||||
        {
 | 
			
		||||
            _services = new ServiceCollection();
 | 
			
		||||
            DelegatingHandler QosDelegatingHandlerDelegate(DownstreamReRoute a, IOcelotLoggerFactory b) => new FakeDelegatingHandler();
 | 
			
		||||
            _services.AddSingleton<QosDelegatingHandlerDelegate>(QosDelegatingHandlerDelegate);
 | 
			
		||||
            var provider = _services.BuildServiceProvider();
 | 
			
		||||
            _factory = new QoSFactory(provider, _loggerFactory.Object);
 | 
			
		||||
            var downstreamReRoute = new DownstreamReRouteBuilder().Build();
 | 
			
		||||
            var handler = _factory.Get(downstreamReRoute);
 | 
			
		||||
            handler.IsError.ShouldBeFalse();
 | 
			
		||||
            handler.Data.ShouldBeOfType<FakeDelegatingHandler>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private class FakeDelegatingHandler : DelegatingHandler
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
namespace Ocelot.UnitTests.Requester
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Requester;
 | 
			
		||||
    using Ocelot.Requester.QoS;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class QoSFactoryTests
 | 
			
		||||
    {
 | 
			
		||||
        private QoSFactory _factory;
 | 
			
		||||
        private ServiceCollection _services;
 | 
			
		||||
        private readonly Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
 | 
			
		||||
        public QoSFactoryTests()
 | 
			
		||||
        {
 | 
			
		||||
            _services = new ServiceCollection();
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            var provider = _services.BuildServiceProvider();
 | 
			
		||||
            _factory = new QoSFactory(provider, _loggerFactory.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_error()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamRoute = new DownstreamRouteBuilder().Build();
 | 
			
		||||
            var handler = _factory.Get(downstreamRoute);
 | 
			
		||||
            handler.IsError.ShouldBeTrue();
 | 
			
		||||
            handler.Errors[0].ShouldBeOfType<UnableToFindQoSProviderError>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_handler()
 | 
			
		||||
        {
 | 
			
		||||
            _services = new ServiceCollection();
 | 
			
		||||
            DelegatingHandler QosDelegatingHandlerDelegate(DownstreamRoute a, IOcelotLoggerFactory b) => new FakeDelegatingHandler();
 | 
			
		||||
            _services.AddSingleton<QosDelegatingHandlerDelegate>(QosDelegatingHandlerDelegate);
 | 
			
		||||
            var provider = _services.BuildServiceProvider();
 | 
			
		||||
            _factory = new QoSFactory(provider, _loggerFactory.Object);
 | 
			
		||||
            var downstreamRoute = new DownstreamRouteBuilder().Build();
 | 
			
		||||
            var handler = _factory.Get(downstreamRoute);
 | 
			
		||||
            handler.IsError.ShouldBeFalse();
 | 
			
		||||
            handler.Data.ShouldBeOfType<FakeDelegatingHandler>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private class FakeDelegatingHandler : DelegatingHandler
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user