mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 15:50:49 +08:00 
			
		
		
		
	Merge remote-tracking branch 'origin/develop' into feature/603-bad-gateway
This commit is contained in:
		
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,225 +1,225 @@
 | 
			
		||||
namespace Ocelot.AcceptanceTests
 | 
			
		||||
{
 | 
			
		||||
    using Configuration.File;
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Net;
 | 
			
		||||
    using System.Threading;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class CachingTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Steps _steps;
 | 
			
		||||
        private readonly ServiceHandler _serviceHandler;
 | 
			
		||||
 | 
			
		||||
        public CachingTests()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler = new ServiceHandler();
 | 
			
		||||
            _steps = new Steps();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_cached_response()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51899,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            FileCacheOptions = new FileCacheOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                TtlSeconds = 100
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51899", 200, "Hello from Laura", null, null))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .Given(x => x.GivenTheServiceNowReturns("http://localhost:51899", 200, "Hello from Tom"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.ThenTheContentLengthIs(16))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_cached_response_with_expires_header()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 52839,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            FileCacheOptions = new FileCacheOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                TtlSeconds = 100
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:52839", 200, "Hello from Laura", "Expires", "-1"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .Given(x => x.GivenTheServiceNowReturns("http://localhost:52839", 200, "Hello from Tom"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.ThenTheContentLengthIs(16))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyHeaderIs("Expires", "-1"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_cached_response_when_using_jsonserialized_cache()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51899,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            FileCacheOptions = new FileCacheOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                TtlSeconds = 100
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51899", 200, "Hello from Laura", null, null))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunningUsingJsonSerializedCache())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .Given(x => x.GivenTheServiceNowReturns("http://localhost:51899", 200, "Hello from Tom"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_return_cached_response_as_ttl_expires()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51899,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            FileCacheOptions = new FileCacheOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                TtlSeconds = 1
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51899", 200, "Hello from Laura", null, null))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .Given(x => x.GivenTheServiceNowReturns("http://localhost:51899", 200, "Hello from Tom"))
 | 
			
		||||
                .And(x => x.GivenTheCacheExpires())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Tom"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheCacheExpires()
 | 
			
		||||
        {
 | 
			
		||||
            Thread.Sleep(1000);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheServiceNowReturns(string url, int statusCode, string responseBody)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler.Dispose();
 | 
			
		||||
            GivenThereIsAServiceRunningOn(url, statusCode, responseBody, null, null);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody, string key, string value)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler.GivenThereIsAServiceRunningOn(url, async context =>
 | 
			
		||||
            {
 | 
			
		||||
                if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(key))
 | 
			
		||||
                {
 | 
			
		||||
                    context.Response.Headers.Add(key, value);
 | 
			
		||||
                }
 | 
			
		||||
                context.Response.StatusCode = statusCode;
 | 
			
		||||
                await context.Response.WriteAsync(responseBody);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler?.Dispose();
 | 
			
		||||
            _steps.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
namespace Ocelot.AcceptanceTests
 | 
			
		||||
{
 | 
			
		||||
    using Configuration.File;
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Net;
 | 
			
		||||
    using System.Threading;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class CachingTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Steps _steps;
 | 
			
		||||
        private readonly ServiceHandler _serviceHandler;
 | 
			
		||||
 | 
			
		||||
        public CachingTests()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler = new ServiceHandler();
 | 
			
		||||
            _steps = new Steps();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_cached_response()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 57899,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            FileCacheOptions = new FileCacheOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                TtlSeconds = 100
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:57899", 200, "Hello from Laura", null, null))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .Given(x => x.GivenTheServiceNowReturns("http://localhost:57899", 200, "Hello from Tom"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.ThenTheContentLengthIs(16))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_cached_response_with_expires_header()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 52839,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            FileCacheOptions = new FileCacheOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                TtlSeconds = 100
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:52839", 200, "Hello from Laura", "Expires", "-1"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .Given(x => x.GivenTheServiceNowReturns("http://localhost:52839", 200, "Hello from Tom"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.ThenTheContentLengthIs(16))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyHeaderIs("Expires", "-1"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_cached_response_when_using_jsonserialized_cache()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 57879,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            FileCacheOptions = new FileCacheOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                TtlSeconds = 100
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:57879", 200, "Hello from Laura", null, null))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunningUsingJsonSerializedCache())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .Given(x => x.GivenTheServiceNowReturns("http://localhost:57879", 200, "Hello from Tom"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_return_cached_response_as_ttl_expires()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 57873,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            FileCacheOptions = new FileCacheOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                TtlSeconds = 1
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:57873", 200, "Hello from Laura", null, null))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .Given(x => x.GivenTheServiceNowReturns("http://localhost:57873", 200, "Hello from Tom"))
 | 
			
		||||
                .And(x => x.GivenTheCacheExpires())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Tom"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheCacheExpires()
 | 
			
		||||
        {
 | 
			
		||||
            Thread.Sleep(1000);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheServiceNowReturns(string url, int statusCode, string responseBody)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler.Dispose();
 | 
			
		||||
            GivenThereIsAServiceRunningOn(url, statusCode, responseBody, null, null);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody, string key, string value)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler.GivenThereIsAServiceRunningOn(url, async context =>
 | 
			
		||||
            {
 | 
			
		||||
                if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(key))
 | 
			
		||||
                {
 | 
			
		||||
                    context.Response.Headers.Add(key, value);
 | 
			
		||||
                }
 | 
			
		||||
                context.Response.StatusCode = statusCode;
 | 
			
		||||
                await context.Response.WriteAsync(responseBody);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler?.Dispose();
 | 
			
		||||
            _steps.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51879,
 | 
			
		||||
                                    Port = 51179,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
@@ -50,7 +50,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
 | 
			
		||||
            var input = "people";
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "/", 200, "Hello from Laura", "\"people\""))
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51179", "/", 200, "Hello from Laura", "\"people\""))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .And(x => _steps.GivenThePostHasGzipContent(input))
 | 
			
		||||
 
 | 
			
		||||
@@ -1,446 +1,446 @@
 | 
			
		||||
namespace Ocelot.AcceptanceTests
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Ocelot.Configuration.File;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Linq;
 | 
			
		||||
    using System.Net;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class HeaderTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private int _count;
 | 
			
		||||
        private readonly Steps _steps;
 | 
			
		||||
        private readonly ServiceHandler _serviceHandler;
 | 
			
		||||
 | 
			
		||||
        public HeaderTests()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler = new ServiceHandler();
 | 
			
		||||
            _steps = new Steps();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_transform_upstream_header()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51871,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            UpstreamHeaderTransform = new Dictionary<string,string>
 | 
			
		||||
                            {
 | 
			
		||||
                                {"Laz", "D, GP"}
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51871", "/", 200, "Laz"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .And(x => _steps.GivenIAddAHeader("Laz", "D"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("GP"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_transform_downstream_header()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51871,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            DownstreamHeaderTransform = new Dictionary<string,string>
 | 
			
		||||
                            {
 | 
			
		||||
                                {"Location", "http://www.bbc.co.uk/, http://ocelot.com/"}
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51871", "/", 200, "Location", "http://www.bbc.co.uk/"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseHeaderIs("Location", "http://ocelot.com/"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_fix_issue_190()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 6773,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            DownstreamHeaderTransform = new Dictionary<string,string>
 | 
			
		||||
                            {
 | 
			
		||||
                                {"Location", "http://localhost:6773, {BaseUrl}"}
 | 
			
		||||
                            },
 | 
			
		||||
                            HttpHandlerOptions = new FileHttpHandlerOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                AllowAutoRedirect = false
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:6773", "/", 302, "Location", "http://localhost:6773/pay/Receive"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Redirect))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseHeaderIs("Location", "http://localhost:5000/pay/Receive"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_fix_issue_205()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 6773,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            DownstreamHeaderTransform = new Dictionary<string,string>
 | 
			
		||||
                            {
 | 
			
		||||
                                {"Location", "{DownstreamBaseUrl}, {BaseUrl}"}
 | 
			
		||||
                            },
 | 
			
		||||
                            HttpHandlerOptions = new FileHttpHandlerOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                AllowAutoRedirect = false
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:6773", "/", 302, "Location", "http://localhost:6773/pay/Receive"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Redirect))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseHeaderIs("Location", "http://localhost:5000/pay/Receive"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_fix_issue_417()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 6773,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            DownstreamHeaderTransform = new Dictionary<string,string>
 | 
			
		||||
                            {
 | 
			
		||||
                                {"Location", "{DownstreamBaseUrl}, {BaseUrl}"}
 | 
			
		||||
                            },
 | 
			
		||||
                            HttpHandlerOptions = new FileHttpHandlerOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                AllowAutoRedirect = false
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                GlobalConfiguration = new FileGlobalConfiguration
 | 
			
		||||
                {
 | 
			
		||||
                    BaseUrl = "http://anotherapp.azurewebsites.net"
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:6773", "/", 302, "Location", "http://localhost:6773/pay/Receive"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Redirect))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseHeaderIs("Location", "http://anotherapp.azurewebsites.net/pay/Receive"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void request_should_reuse_cookies_with_cookie_container()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                {
 | 
			
		||||
                    new FileReRoute
 | 
			
		||||
                    {
 | 
			
		||||
                        DownstreamPathTemplate = "/sso/{everything}",
 | 
			
		||||
                        DownstreamScheme = "http",
 | 
			
		||||
                        DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                        {
 | 
			
		||||
                            new FileHostAndPort
 | 
			
		||||
                            {
 | 
			
		||||
                                Host = "localhost",
 | 
			
		||||
                                Port = 6774,
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        UpstreamPathTemplate = "/sso/{everything}",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "Get", "Post", "Options" },
 | 
			
		||||
                        HttpHandlerOptions = new FileHttpHandlerOptions
 | 
			
		||||
                        {
 | 
			
		||||
                            UseCookieContainer = true
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:6774", "/sso/test", 200))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .And(x => _steps.WhenIGetUrlOnTheApiGateway("/sso/test"))
 | 
			
		||||
                .And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseHeaderIs("Set-Cookie", "test=0; path=/"))
 | 
			
		||||
                .And(x => _steps.GivenIAddCookieToMyRequest("test=1; path=/"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/sso/test"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void request_should_have_own_cookies_no_cookie_container()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                {
 | 
			
		||||
                    new FileReRoute
 | 
			
		||||
                    {
 | 
			
		||||
                        DownstreamPathTemplate = "/sso/{everything}",
 | 
			
		||||
                        DownstreamScheme = "http",
 | 
			
		||||
                        DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                        {
 | 
			
		||||
                            new FileHostAndPort
 | 
			
		||||
                            {
 | 
			
		||||
                                Host = "localhost",
 | 
			
		||||
                                Port = 6775,
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        UpstreamPathTemplate = "/sso/{everything}",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "Get", "Post", "Options" },
 | 
			
		||||
                        HttpHandlerOptions = new FileHttpHandlerOptions
 | 
			
		||||
                        {
 | 
			
		||||
                            UseCookieContainer = false
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:6775", "/sso/test", 200))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .And(x => _steps.WhenIGetUrlOnTheApiGateway("/sso/test"))
 | 
			
		||||
                .And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseHeaderIs("Set-Cookie", "test=0; path=/"))
 | 
			
		||||
                .And(x => _steps.GivenIAddCookieToMyRequest("test=1; path=/"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/sso/test"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void issue_474_should_not_put_spaces_in_header()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51879,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "/", 200, "Accept"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .And(x => _steps.GivenIAddAHeader("Accept", "text/html,application/xhtml+xml,application/xml;"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("text/html,application/xhtml+xml,application/xml;"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void issue_474_should_put_spaces_in_header()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51879,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "/", 200, "Accept"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .And(x => _steps.GivenIAddAHeader("Accept", "text/html"))
 | 
			
		||||
                .And(x => _steps.GivenIAddAHeader("Accept", "application/xhtml+xml"))
 | 
			
		||||
                .And(x => _steps.GivenIAddAHeader("Accept", "application/xml"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("text/html, application/xhtml+xml, application/xml"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, context =>
 | 
			
		||||
            {
 | 
			
		||||
                if (_count == 0)
 | 
			
		||||
                {
 | 
			
		||||
                    context.Response.Cookies.Append("test", "0");
 | 
			
		||||
                    _count++;
 | 
			
		||||
                    context.Response.StatusCode = statusCode;
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (context.Request.Cookies.TryGetValue("test", out var cookieValue) || context.Request.Headers.TryGetValue("Set-Cookie", out var headerValue))
 | 
			
		||||
                {
 | 
			
		||||
                    if (cookieValue == "0" || headerValue == "test=1; path=/")
 | 
			
		||||
                    {
 | 
			
		||||
                        context.Response.StatusCode = statusCode;
 | 
			
		||||
                        return Task.CompletedTask;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                context.Response.StatusCode = 500;
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string headerKey)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
 | 
			
		||||
            {
 | 
			
		||||
                if (context.Request.Headers.TryGetValue(headerKey, out var values))
 | 
			
		||||
                {
 | 
			
		||||
                    var result = values.First();
 | 
			
		||||
                    context.Response.StatusCode = statusCode;
 | 
			
		||||
                    await context.Response.WriteAsync(result);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string headerKey, string headerValue)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, context =>
 | 
			
		||||
            {
 | 
			
		||||
                context.Response.OnStarting(() =>
 | 
			
		||||
                {
 | 
			
		||||
                    context.Response.Headers.Add(headerKey, headerValue);
 | 
			
		||||
                    context.Response.StatusCode = statusCode;
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler?.Dispose();
 | 
			
		||||
            _steps.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
namespace Ocelot.AcceptanceTests
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Ocelot.Configuration.File;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Linq;
 | 
			
		||||
    using System.Net;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class HeaderTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private int _count;
 | 
			
		||||
        private readonly Steps _steps;
 | 
			
		||||
        private readonly ServiceHandler _serviceHandler;
 | 
			
		||||
 | 
			
		||||
        public HeaderTests()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler = new ServiceHandler();
 | 
			
		||||
            _steps = new Steps();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_transform_upstream_header()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51871,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            UpstreamHeaderTransform = new Dictionary<string,string>
 | 
			
		||||
                            {
 | 
			
		||||
                                {"Laz", "D, GP"}
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51871", "/", 200, "Laz"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .And(x => _steps.GivenIAddAHeader("Laz", "D"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("GP"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_transform_downstream_header()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51871,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            DownstreamHeaderTransform = new Dictionary<string,string>
 | 
			
		||||
                            {
 | 
			
		||||
                                {"Location", "http://www.bbc.co.uk/, http://ocelot.com/"}
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51871", "/", 200, "Location", "http://www.bbc.co.uk/"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseHeaderIs("Location", "http://ocelot.com/"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_fix_issue_190()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 6773,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            DownstreamHeaderTransform = new Dictionary<string,string>
 | 
			
		||||
                            {
 | 
			
		||||
                                {"Location", "http://localhost:6773, {BaseUrl}"}
 | 
			
		||||
                            },
 | 
			
		||||
                            HttpHandlerOptions = new FileHttpHandlerOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                AllowAutoRedirect = false
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:6773", "/", 302, "Location", "http://localhost:6773/pay/Receive"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Redirect))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseHeaderIs("Location", "http://localhost:5000/pay/Receive"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_fix_issue_205()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 6773,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            DownstreamHeaderTransform = new Dictionary<string,string>
 | 
			
		||||
                            {
 | 
			
		||||
                                {"Location", "{DownstreamBaseUrl}, {BaseUrl}"}
 | 
			
		||||
                            },
 | 
			
		||||
                            HttpHandlerOptions = new FileHttpHandlerOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                AllowAutoRedirect = false
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:6773", "/", 302, "Location", "http://localhost:6773/pay/Receive"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Redirect))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseHeaderIs("Location", "http://localhost:5000/pay/Receive"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_fix_issue_417()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 6773,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            DownstreamHeaderTransform = new Dictionary<string,string>
 | 
			
		||||
                            {
 | 
			
		||||
                                {"Location", "{DownstreamBaseUrl}, {BaseUrl}"}
 | 
			
		||||
                            },
 | 
			
		||||
                            HttpHandlerOptions = new FileHttpHandlerOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                AllowAutoRedirect = false
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                GlobalConfiguration = new FileGlobalConfiguration
 | 
			
		||||
                {
 | 
			
		||||
                    BaseUrl = "http://anotherapp.azurewebsites.net"
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:6773", "/", 302, "Location", "http://localhost:6773/pay/Receive"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Redirect))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseHeaderIs("Location", "http://anotherapp.azurewebsites.net/pay/Receive"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void request_should_reuse_cookies_with_cookie_container()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                {
 | 
			
		||||
                    new FileReRoute
 | 
			
		||||
                    {
 | 
			
		||||
                        DownstreamPathTemplate = "/sso/{everything}",
 | 
			
		||||
                        DownstreamScheme = "http",
 | 
			
		||||
                        DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                        {
 | 
			
		||||
                            new FileHostAndPort
 | 
			
		||||
                            {
 | 
			
		||||
                                Host = "localhost",
 | 
			
		||||
                                Port = 6774,
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        UpstreamPathTemplate = "/sso/{everything}",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "Get", "Post", "Options" },
 | 
			
		||||
                        HttpHandlerOptions = new FileHttpHandlerOptions
 | 
			
		||||
                        {
 | 
			
		||||
                            UseCookieContainer = true
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:6774", "/sso/test", 200))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .And(x => _steps.WhenIGetUrlOnTheApiGateway("/sso/test"))
 | 
			
		||||
                .And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseHeaderIs("Set-Cookie", "test=0; path=/"))
 | 
			
		||||
                .And(x => _steps.GivenIAddCookieToMyRequest("test=1; path=/"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/sso/test"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void request_should_have_own_cookies_no_cookie_container()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                {
 | 
			
		||||
                    new FileReRoute
 | 
			
		||||
                    {
 | 
			
		||||
                        DownstreamPathTemplate = "/sso/{everything}",
 | 
			
		||||
                        DownstreamScheme = "http",
 | 
			
		||||
                        DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                        {
 | 
			
		||||
                            new FileHostAndPort
 | 
			
		||||
                            {
 | 
			
		||||
                                Host = "localhost",
 | 
			
		||||
                                Port = 6775,
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        UpstreamPathTemplate = "/sso/{everything}",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "Get", "Post", "Options" },
 | 
			
		||||
                        HttpHandlerOptions = new FileHttpHandlerOptions
 | 
			
		||||
                        {
 | 
			
		||||
                            UseCookieContainer = false
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:6775", "/sso/test", 200))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .And(x => _steps.WhenIGetUrlOnTheApiGateway("/sso/test"))
 | 
			
		||||
                .And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseHeaderIs("Set-Cookie", "test=0; path=/"))
 | 
			
		||||
                .And(x => _steps.GivenIAddCookieToMyRequest("test=1; path=/"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/sso/test"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void issue_474_should_not_put_spaces_in_header()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 52866,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:52866", "/", 200, "Accept"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .And(x => _steps.GivenIAddAHeader("Accept", "text/html,application/xhtml+xml,application/xml;"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("text/html,application/xhtml+xml,application/xml;"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void issue_474_should_put_spaces_in_header()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51874,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51874", "/", 200, "Accept"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .And(x => _steps.GivenIAddAHeader("Accept", "text/html"))
 | 
			
		||||
                .And(x => _steps.GivenIAddAHeader("Accept", "application/xhtml+xml"))
 | 
			
		||||
                .And(x => _steps.GivenIAddAHeader("Accept", "application/xml"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("text/html, application/xhtml+xml, application/xml"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, context =>
 | 
			
		||||
            {
 | 
			
		||||
                if (_count == 0)
 | 
			
		||||
                {
 | 
			
		||||
                    context.Response.Cookies.Append("test", "0");
 | 
			
		||||
                    _count++;
 | 
			
		||||
                    context.Response.StatusCode = statusCode;
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (context.Request.Cookies.TryGetValue("test", out var cookieValue) || context.Request.Headers.TryGetValue("Set-Cookie", out var headerValue))
 | 
			
		||||
                {
 | 
			
		||||
                    if (cookieValue == "0" || headerValue == "test=1; path=/")
 | 
			
		||||
                    {
 | 
			
		||||
                        context.Response.StatusCode = statusCode;
 | 
			
		||||
                        return Task.CompletedTask;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                context.Response.StatusCode = 500;
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string headerKey)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
 | 
			
		||||
            {
 | 
			
		||||
                if (context.Request.Headers.TryGetValue(headerKey, out var values))
 | 
			
		||||
                {
 | 
			
		||||
                    var result = values.First();
 | 
			
		||||
                    context.Response.StatusCode = statusCode;
 | 
			
		||||
                    await context.Response.WriteAsync(result);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string headerKey, string headerValue)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, context =>
 | 
			
		||||
            {
 | 
			
		||||
                context.Response.OnStarting(() =>
 | 
			
		||||
                {
 | 
			
		||||
                    context.Response.Headers.Add(headerKey, headerValue);
 | 
			
		||||
                    context.Response.StatusCode = statusCode;
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler?.Dispose();
 | 
			
		||||
            _steps.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,163 +1,163 @@
 | 
			
		||||
namespace Ocelot.AcceptanceTests
 | 
			
		||||
{
 | 
			
		||||
    using Configuration;
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Ocelot.Configuration.File;
 | 
			
		||||
    using Requester;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Concurrent;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Net;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class HttpClientCachingTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Steps _steps;
 | 
			
		||||
        private string _downstreamPath;
 | 
			
		||||
        private readonly ServiceHandler _serviceHandler;
 | 
			
		||||
 | 
			
		||||
        public HttpClientCachingTests()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler = new ServiceHandler();
 | 
			
		||||
            _steps = new Steps();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_cache_one_http_client_same_re_route()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51879,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var cache = new FakeHttpClientCache();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", 200, "Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunningWithFakeHttpClientCache(cache))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .And(x => cache.Count.ShouldBe(1))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_cache_two_http_client_different_re_route()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                {
 | 
			
		||||
                    new FileReRoute
 | 
			
		||||
                    {
 | 
			
		||||
                        DownstreamPathTemplate = "/",
 | 
			
		||||
                        DownstreamScheme = "http",
 | 
			
		||||
                        DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                        {
 | 
			
		||||
                            new FileHostAndPort
 | 
			
		||||
                            {
 | 
			
		||||
                                Host = "localhost",
 | 
			
		||||
                                Port = 51879,
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        UpstreamPathTemplate = "/",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                    },
 | 
			
		||||
                    new FileReRoute
 | 
			
		||||
                    {
 | 
			
		||||
                        DownstreamPathTemplate = "/two",
 | 
			
		||||
                        DownstreamScheme = "http",
 | 
			
		||||
                        DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                        {
 | 
			
		||||
                            new FileHostAndPort
 | 
			
		||||
                            {
 | 
			
		||||
                                Host = "localhost",
 | 
			
		||||
                                Port = 51879,
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        UpstreamPathTemplate = "/two",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var cache = new FakeHttpClientCache();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", 200, "Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunningWithFakeHttpClientCache(cache))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/two"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/two"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/two"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .And(x => cache.Count.ShouldBe(2))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAServiceRunningOn(string baseUrl, int statusCode, string responseBody)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, async context =>
 | 
			
		||||
            {
 | 
			
		||||
                context.Response.StatusCode = statusCode;
 | 
			
		||||
                await context.Response.WriteAsync(responseBody);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler.Dispose();
 | 
			
		||||
            _steps.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public class FakeHttpClientCache : IHttpClientCache
 | 
			
		||||
        {
 | 
			
		||||
            private readonly ConcurrentDictionary<DownstreamReRoute, IHttpClient> _httpClientsCache;
 | 
			
		||||
 | 
			
		||||
            public FakeHttpClientCache()
 | 
			
		||||
            {
 | 
			
		||||
                _httpClientsCache = new ConcurrentDictionary<DownstreamReRoute, IHttpClient>();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public void Set(DownstreamReRoute key, IHttpClient client, TimeSpan expirationTime)
 | 
			
		||||
            {
 | 
			
		||||
                _httpClientsCache.AddOrUpdate(key, client, (k, oldValue) => client);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public IHttpClient Get(DownstreamReRoute key)
 | 
			
		||||
            {
 | 
			
		||||
                //todo handle error?
 | 
			
		||||
                return _httpClientsCache.TryGetValue(key, out var client) ? client : null;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public int Count => _httpClientsCache.Count;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
namespace Ocelot.AcceptanceTests
 | 
			
		||||
{
 | 
			
		||||
    using Configuration;
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Ocelot.Configuration.File;
 | 
			
		||||
    using Requester;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Concurrent;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Net;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class HttpClientCachingTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Steps _steps;
 | 
			
		||||
        private string _downstreamPath;
 | 
			
		||||
        private readonly ServiceHandler _serviceHandler;
 | 
			
		||||
 | 
			
		||||
        public HttpClientCachingTests()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler = new ServiceHandler();
 | 
			
		||||
            _steps = new Steps();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_cache_one_http_client_same_re_route()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 58814,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var cache = new FakeHttpClientCache();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:58814", 200, "Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunningWithFakeHttpClientCache(cache))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .And(x => cache.Count.ShouldBe(1))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_cache_two_http_client_different_re_route()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                {
 | 
			
		||||
                    new FileReRoute
 | 
			
		||||
                    {
 | 
			
		||||
                        DownstreamPathTemplate = "/",
 | 
			
		||||
                        DownstreamScheme = "http",
 | 
			
		||||
                        DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                        {
 | 
			
		||||
                            new FileHostAndPort
 | 
			
		||||
                            {
 | 
			
		||||
                                Host = "localhost",
 | 
			
		||||
                                Port = 58817,
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        UpstreamPathTemplate = "/",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                    },
 | 
			
		||||
                    new FileReRoute
 | 
			
		||||
                    {
 | 
			
		||||
                        DownstreamPathTemplate = "/two",
 | 
			
		||||
                        DownstreamScheme = "http",
 | 
			
		||||
                        DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                        {
 | 
			
		||||
                            new FileHostAndPort
 | 
			
		||||
                            {
 | 
			
		||||
                                Host = "localhost",
 | 
			
		||||
                                Port = 58817,
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        UpstreamPathTemplate = "/two",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var cache = new FakeHttpClientCache();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:58817", 200, "Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunningWithFakeHttpClientCache(cache))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/two"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/two"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/two"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .And(x => cache.Count.ShouldBe(2))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAServiceRunningOn(string baseUrl, int statusCode, string responseBody)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, async context =>
 | 
			
		||||
            {
 | 
			
		||||
                context.Response.StatusCode = statusCode;
 | 
			
		||||
                await context.Response.WriteAsync(responseBody);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler.Dispose();
 | 
			
		||||
            _steps.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public class FakeHttpClientCache : IHttpClientCache
 | 
			
		||||
        {
 | 
			
		||||
            private readonly ConcurrentDictionary<DownstreamReRoute, IHttpClient> _httpClientsCache;
 | 
			
		||||
 | 
			
		||||
            public FakeHttpClientCache()
 | 
			
		||||
            {
 | 
			
		||||
                _httpClientsCache = new ConcurrentDictionary<DownstreamReRoute, IHttpClient>();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public void Set(DownstreamReRoute key, IHttpClient client, TimeSpan expirationTime)
 | 
			
		||||
            {
 | 
			
		||||
                _httpClientsCache.AddOrUpdate(key, client, (k, oldValue) => client);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public IHttpClient Get(DownstreamReRoute key)
 | 
			
		||||
            {
 | 
			
		||||
                //todo handle error?
 | 
			
		||||
                return _httpClientsCache.TryGetValue(key, out var client) ? client : null;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public int Count => _httpClientsCache.Count;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <VersionPrefix>0.0.0-dev</VersionPrefix>
 | 
			
		||||
    <TargetFramework>netcoreapp3.0</TargetFramework>
 | 
			
		||||
    <TargetFramework>netcoreapp3.1</TargetFramework>
 | 
			
		||||
    <AssemblyName>Ocelot.AcceptanceTests</AssemblyName>
 | 
			
		||||
    <OutputType>Exe</OutputType>
 | 
			
		||||
    <PackageId>Ocelot.AcceptanceTests</PackageId>
 | 
			
		||||
@@ -40,6 +40,7 @@
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
 | 
			
		||||
    <PackageReference Include="Moq" Version="4.13.0" />
 | 
			
		||||
    <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.66">
 | 
			
		||||
      <PrivateAssets>all</PrivateAssets>
 | 
			
		||||
    </PackageReference>
 | 
			
		||||
@@ -69,6 +70,6 @@
 | 
			
		||||
    <PackageReference Include="Pivotal.Discovery.ClientCore" Version="2.2.0" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-19367-01" />
 | 
			
		||||
    <PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.0.0" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
</Project>
 | 
			
		||||
@@ -1,274 +1,274 @@
 | 
			
		||||
namespace Ocelot.AcceptanceTests
 | 
			
		||||
{
 | 
			
		||||
    using Configuration.File;
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Net;
 | 
			
		||||
    using System.Threading;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class PollyQoSTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Steps _steps;
 | 
			
		||||
        private int _requestCount;
 | 
			
		||||
        private readonly ServiceHandler _serviceHandler;
 | 
			
		||||
 | 
			
		||||
        public PollyQoSTests()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler = new ServiceHandler();
 | 
			
		||||
            _steps = new Steps();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_timeout()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                {
 | 
			
		||||
                    new FileReRoute
 | 
			
		||||
                    {
 | 
			
		||||
                        DownstreamPathTemplate = "/",
 | 
			
		||||
                        DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                        {
 | 
			
		||||
                            new FileHostAndPort
 | 
			
		||||
                            {
 | 
			
		||||
                                Host = "localhost",
 | 
			
		||||
                                Port = 51569,
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        DownstreamScheme = "http",
 | 
			
		||||
                        UpstreamPathTemplate = "/",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "Post" },
 | 
			
		||||
                        QoSOptions = new FileQoSOptions
 | 
			
		||||
                        {
 | 
			
		||||
                            TimeoutValue = 1000,
 | 
			
		||||
                            ExceptionsAllowedBeforeBreaking = 10
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51569", 200, string.Empty, 10))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunningWithPolly())
 | 
			
		||||
                .And(x => _steps.GivenThePostHasContent("postContent"))
 | 
			
		||||
                .When(x => _steps.WhenIPostUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_timeout()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                {
 | 
			
		||||
                    new FileReRoute
 | 
			
		||||
                    {
 | 
			
		||||
                        DownstreamPathTemplate = "/",
 | 
			
		||||
                        DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                        {
 | 
			
		||||
                            new FileHostAndPort
 | 
			
		||||
                            {
 | 
			
		||||
                                Host = "localhost",
 | 
			
		||||
                                Port = 51579,
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        DownstreamScheme = "http",
 | 
			
		||||
                        UpstreamPathTemplate = "/",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "Post" },
 | 
			
		||||
                        QoSOptions = new FileQoSOptions
 | 
			
		||||
                        {
 | 
			
		||||
                            TimeoutValue = 10,
 | 
			
		||||
                            ExceptionsAllowedBeforeBreaking = 10
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51579", 201, string.Empty, 1000))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunningWithPolly())
 | 
			
		||||
                .And(x => _steps.GivenThePostHasContent("postContent"))
 | 
			
		||||
                .When(x => _steps.WhenIPostUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_open_circuit_breaker_then_close()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                {
 | 
			
		||||
                    new FileReRoute
 | 
			
		||||
                    {
 | 
			
		||||
                        DownstreamPathTemplate = "/",
 | 
			
		||||
                        DownstreamScheme = "http",
 | 
			
		||||
                        DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                        {
 | 
			
		||||
                            new FileHostAndPort
 | 
			
		||||
                            {
 | 
			
		||||
                                Host = "localhost",
 | 
			
		||||
                                Port = 51892,
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        UpstreamPathTemplate = "/",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        QoSOptions = new FileQoSOptions
 | 
			
		||||
                        {
 | 
			
		||||
                            ExceptionsAllowedBeforeBreaking = 1,
 | 
			
		||||
                            TimeoutValue = 500,
 | 
			
		||||
                            DurationOfBreak = 1000
 | 
			
		||||
                        },
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAPossiblyBrokenServiceRunningOn("http://localhost:51892", "Hello from Laura"))
 | 
			
		||||
                .Given(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .Given(x => _steps.GivenOcelotIsRunningWithPolly())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .Given(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Given(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
 | 
			
		||||
                .Given(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Given(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
 | 
			
		||||
                .Given(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Given(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
 | 
			
		||||
                .Given(x => x.GivenIWaitMilliseconds(3000))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void open_circuit_should_not_effect_different_reRoute()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                {
 | 
			
		||||
                    new FileReRoute
 | 
			
		||||
                    {
 | 
			
		||||
                        DownstreamPathTemplate = "/",
 | 
			
		||||
                        DownstreamScheme = "http",
 | 
			
		||||
                        DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                        {
 | 
			
		||||
                            new FileHostAndPort
 | 
			
		||||
                            {
 | 
			
		||||
                                Host = "localhost",
 | 
			
		||||
                                Port = 51872,
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        UpstreamPathTemplate = "/",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        QoSOptions = new FileQoSOptions
 | 
			
		||||
                        {
 | 
			
		||||
                            ExceptionsAllowedBeforeBreaking = 1,
 | 
			
		||||
                            TimeoutValue = 500,
 | 
			
		||||
                            DurationOfBreak = 1000
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    new FileReRoute
 | 
			
		||||
                    {
 | 
			
		||||
                        DownstreamPathTemplate = "/",
 | 
			
		||||
                        DownstreamScheme = "http",
 | 
			
		||||
                        DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                        {
 | 
			
		||||
                            new FileHostAndPort
 | 
			
		||||
                            {
 | 
			
		||||
                                Host = "localhost",
 | 
			
		||||
                                Port = 51880,
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        UpstreamPathTemplate = "/working",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAPossiblyBrokenServiceRunningOn("http://localhost:51872", "Hello from Laura"))
 | 
			
		||||
                .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51880/", 200, "Hello from Tom", 0))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunningWithPolly())
 | 
			
		||||
                .And(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
 | 
			
		||||
                .And(x => _steps.WhenIGetUrlOnTheApiGateway("/working"))
 | 
			
		||||
                .And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Tom"))
 | 
			
		||||
                .And(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
 | 
			
		||||
                .And(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
 | 
			
		||||
                .And(x => x.GivenIWaitMilliseconds(3000))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenIWaitMilliseconds(int ms)
 | 
			
		||||
        {
 | 
			
		||||
            Thread.Sleep(ms);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAPossiblyBrokenServiceRunningOn(string url, string responseBody)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler.GivenThereIsAServiceRunningOn(url, async context =>
 | 
			
		||||
            {
 | 
			
		||||
                //circuit starts closed
 | 
			
		||||
                if (_requestCount == 0)
 | 
			
		||||
                {
 | 
			
		||||
                    _requestCount++;
 | 
			
		||||
                    context.Response.StatusCode = 200;
 | 
			
		||||
                    await context.Response.WriteAsync(responseBody);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                //request one times out and polly throws exception, circuit opens
 | 
			
		||||
                if (_requestCount == 1)
 | 
			
		||||
                {
 | 
			
		||||
                    _requestCount++;
 | 
			
		||||
                    await Task.Delay(1000);
 | 
			
		||||
                    context.Response.StatusCode = 200;
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                //after break closes we return 200 OK
 | 
			
		||||
                if (_requestCount == 2)
 | 
			
		||||
                {
 | 
			
		||||
                    context.Response.StatusCode = 200;
 | 
			
		||||
                    await context.Response.WriteAsync(responseBody);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody, int timeout)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler.GivenThereIsAServiceRunningOn(url, async context =>
 | 
			
		||||
            {
 | 
			
		||||
                Thread.Sleep(timeout);
 | 
			
		||||
                context.Response.StatusCode = statusCode;
 | 
			
		||||
                await context.Response.WriteAsync(responseBody);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler?.Dispose();
 | 
			
		||||
            _steps.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
namespace Ocelot.AcceptanceTests
 | 
			
		||||
{
 | 
			
		||||
    using Configuration.File;
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Net;
 | 
			
		||||
    using System.Threading;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class PollyQoSTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Steps _steps;
 | 
			
		||||
        private int _requestCount;
 | 
			
		||||
        private readonly ServiceHandler _serviceHandler;
 | 
			
		||||
 | 
			
		||||
        public PollyQoSTests()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler = new ServiceHandler();
 | 
			
		||||
            _steps = new Steps();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_timeout()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                {
 | 
			
		||||
                    new FileReRoute
 | 
			
		||||
                    {
 | 
			
		||||
                        DownstreamPathTemplate = "/",
 | 
			
		||||
                        DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                        {
 | 
			
		||||
                            new FileHostAndPort
 | 
			
		||||
                            {
 | 
			
		||||
                                Host = "localhost",
 | 
			
		||||
                                Port = 51569,
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        DownstreamScheme = "http",
 | 
			
		||||
                        UpstreamPathTemplate = "/",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "Post" },
 | 
			
		||||
                        QoSOptions = new FileQoSOptions
 | 
			
		||||
                        {
 | 
			
		||||
                            TimeoutValue = 1000,
 | 
			
		||||
                            ExceptionsAllowedBeforeBreaking = 10
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51569", 200, string.Empty, 10))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunningWithPolly())
 | 
			
		||||
                .And(x => _steps.GivenThePostHasContent("postContent"))
 | 
			
		||||
                .When(x => _steps.WhenIPostUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_timeout()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                {
 | 
			
		||||
                    new FileReRoute
 | 
			
		||||
                    {
 | 
			
		||||
                        DownstreamPathTemplate = "/",
 | 
			
		||||
                        DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                        {
 | 
			
		||||
                            new FileHostAndPort
 | 
			
		||||
                            {
 | 
			
		||||
                                Host = "localhost",
 | 
			
		||||
                                Port = 51579,
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        DownstreamScheme = "http",
 | 
			
		||||
                        UpstreamPathTemplate = "/",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "Post" },
 | 
			
		||||
                        QoSOptions = new FileQoSOptions
 | 
			
		||||
                        {
 | 
			
		||||
                            TimeoutValue = 10,
 | 
			
		||||
                            ExceptionsAllowedBeforeBreaking = 10
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51579", 201, string.Empty, 1000))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunningWithPolly())
 | 
			
		||||
                .And(x => _steps.GivenThePostHasContent("postContent"))
 | 
			
		||||
                .When(x => _steps.WhenIPostUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_open_circuit_breaker_then_close()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                {
 | 
			
		||||
                    new FileReRoute
 | 
			
		||||
                    {
 | 
			
		||||
                        DownstreamPathTemplate = "/",
 | 
			
		||||
                        DownstreamScheme = "http",
 | 
			
		||||
                        DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                        {
 | 
			
		||||
                            new FileHostAndPort
 | 
			
		||||
                            {
 | 
			
		||||
                                Host = "localhost",
 | 
			
		||||
                                Port = 51892,
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        UpstreamPathTemplate = "/",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        QoSOptions = new FileQoSOptions
 | 
			
		||||
                        {
 | 
			
		||||
                            ExceptionsAllowedBeforeBreaking = 1,
 | 
			
		||||
                            TimeoutValue = 500,
 | 
			
		||||
                            DurationOfBreak = 1000
 | 
			
		||||
                        },
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAPossiblyBrokenServiceRunningOn("http://localhost:51892", "Hello from Laura"))
 | 
			
		||||
                .Given(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .Given(x => _steps.GivenOcelotIsRunningWithPolly())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .Given(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Given(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
 | 
			
		||||
                .Given(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Given(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
 | 
			
		||||
                .Given(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Given(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
 | 
			
		||||
                .Given(x => x.GivenIWaitMilliseconds(3000))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void open_circuit_should_not_effect_different_reRoute()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                {
 | 
			
		||||
                    new FileReRoute
 | 
			
		||||
                    {
 | 
			
		||||
                        DownstreamPathTemplate = "/",
 | 
			
		||||
                        DownstreamScheme = "http",
 | 
			
		||||
                        DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                        {
 | 
			
		||||
                            new FileHostAndPort
 | 
			
		||||
                            {
 | 
			
		||||
                                Host = "localhost",
 | 
			
		||||
                                Port = 51870,
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        UpstreamPathTemplate = "/",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        QoSOptions = new FileQoSOptions
 | 
			
		||||
                        {
 | 
			
		||||
                            ExceptionsAllowedBeforeBreaking = 1,
 | 
			
		||||
                            TimeoutValue = 500,
 | 
			
		||||
                            DurationOfBreak = 1000
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    new FileReRoute
 | 
			
		||||
                    {
 | 
			
		||||
                        DownstreamPathTemplate = "/",
 | 
			
		||||
                        DownstreamScheme = "http",
 | 
			
		||||
                        DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                        {
 | 
			
		||||
                            new FileHostAndPort
 | 
			
		||||
                            {
 | 
			
		||||
                                Host = "localhost",
 | 
			
		||||
                                Port = 51880,
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        UpstreamPathTemplate = "/working",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAPossiblyBrokenServiceRunningOn("http://localhost:51870", "Hello from Laura"))
 | 
			
		||||
                .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51880/", 200, "Hello from Tom", 0))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunningWithPolly())
 | 
			
		||||
                .And(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
 | 
			
		||||
                .And(x => _steps.WhenIGetUrlOnTheApiGateway("/working"))
 | 
			
		||||
                .And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Tom"))
 | 
			
		||||
                .And(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
 | 
			
		||||
                .And(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
 | 
			
		||||
                .And(x => x.GivenIWaitMilliseconds(3000))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenIWaitMilliseconds(int ms)
 | 
			
		||||
        {
 | 
			
		||||
            Thread.Sleep(ms);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAPossiblyBrokenServiceRunningOn(string url, string responseBody)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler.GivenThereIsAServiceRunningOn(url, async context =>
 | 
			
		||||
            {
 | 
			
		||||
                //circuit starts closed
 | 
			
		||||
                if (_requestCount == 0)
 | 
			
		||||
                {
 | 
			
		||||
                    _requestCount++;
 | 
			
		||||
                    context.Response.StatusCode = 200;
 | 
			
		||||
                    await context.Response.WriteAsync(responseBody);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                //request one times out and polly throws exception, circuit opens
 | 
			
		||||
                if (_requestCount == 1)
 | 
			
		||||
                {
 | 
			
		||||
                    _requestCount++;
 | 
			
		||||
                    await Task.Delay(1000);
 | 
			
		||||
                    context.Response.StatusCode = 200;
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                //after break closes we return 200 OK
 | 
			
		||||
                if (_requestCount == 2)
 | 
			
		||||
                {
 | 
			
		||||
                    context.Response.StatusCode = 200;
 | 
			
		||||
                    await context.Response.WriteAsync(responseBody);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody, int timeout)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler.GivenThereIsAServiceRunningOn(url, async context =>
 | 
			
		||||
            {
 | 
			
		||||
                Thread.Sleep(timeout);
 | 
			
		||||
                context.Response.StatusCode = statusCode;
 | 
			
		||||
                await context.Response.WriteAsync(responseBody);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler?.Dispose();
 | 
			
		||||
            _steps.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,68 +1,68 @@
 | 
			
		||||
namespace Ocelot.AcceptanceTests
 | 
			
		||||
{
 | 
			
		||||
    using Ocelot.Configuration.File;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Net;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class ResponseCodeTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Steps _steps;
 | 
			
		||||
        private readonly ServiceHandler _serviceHandler;
 | 
			
		||||
 | 
			
		||||
        public ResponseCodeTests()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler = new ServiceHandler();
 | 
			
		||||
            _steps = new Steps();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_response_304_when_service_returns_304()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/{everything}",
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51879,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/{everything}",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "/inline.132.bundle.js", 304))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/inline.132.bundle.js"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.NotModified))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
 | 
			
		||||
            {
 | 
			
		||||
                context.Response.StatusCode = statusCode;
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler?.Dispose();
 | 
			
		||||
            _steps.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
namespace Ocelot.AcceptanceTests
 | 
			
		||||
{
 | 
			
		||||
    using Ocelot.Configuration.File;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Net;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class ResponseCodeTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Steps _steps;
 | 
			
		||||
        private readonly ServiceHandler _serviceHandler;
 | 
			
		||||
 | 
			
		||||
        public ResponseCodeTests()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler = new ServiceHandler();
 | 
			
		||||
            _steps = new Steps();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_response_304_when_service_returns_304()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/{everything}",
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51092,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/{everything}",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51092", "/inline.132.bundle.js", 304))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/inline.132.bundle.js"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.NotModified))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
 | 
			
		||||
            {
 | 
			
		||||
                context.Response.StatusCode = statusCode;
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler?.Dispose();
 | 
			
		||||
            _steps.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -52,7 +52,8 @@
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_internal_server_error_if_downstream_service_returns_internal_server_error()
 | 
			
		||||
        {
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
@@ -81,6 +82,39 @@
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.InternalServerError))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_log_warning_if_downstream_service_returns_internal_server_error()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 53876,
 | 
			
		||||
                                },
 | 
			
		||||
                            },
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                        },
 | 
			
		||||
                    },
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:53876"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunningWithLogger())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenWarningShouldBeLogged())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAServiceRunningOn(string url)
 | 
			
		||||
 
 | 
			
		||||
@@ -84,14 +84,14 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51879,
 | 
			
		||||
                                    Port = 57873,
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/", "/", 200, "Hello from Laura"))
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:57873/", "/", 200, "Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
@@ -131,7 +131,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51879,
 | 
			
		||||
                                    Port = 50810,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
@@ -180,7 +180,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51879,
 | 
			
		||||
                                    Port = 50810,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
@@ -189,7 +189,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/", "/", 200, "Hello from Laura"))
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:50810/", "/", 200, "Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
@@ -263,7 +263,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51879,
 | 
			
		||||
                                    Port = 51005,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/{url}",
 | 
			
		||||
@@ -272,7 +272,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "/", 200, "Hello from Laura"))
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51005", "/", 200, "Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway(""))
 | 
			
		||||
@@ -297,7 +297,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51879,
 | 
			
		||||
                                    Port = 58589,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
@@ -306,7 +306,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "/", 200, "Hello from Laura"))
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:58589", "/", 200, "Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
@@ -382,7 +382,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51879,
 | 
			
		||||
                                    Port = 51206,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
@@ -391,7 +391,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "/api/products", 200, "Hello from Laura"))
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51206", "/api/products", 200, "Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
@@ -416,7 +416,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51879,
 | 
			
		||||
                                    Port = 51990,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
@@ -425,7 +425,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "/api/products", 200, "Hello from Laura"))
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51990", "/api/products", 200, "Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
@@ -450,7 +450,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51879,
 | 
			
		||||
                                    Port = 58804,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/products/",
 | 
			
		||||
@@ -459,7 +459,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "/products", 200, "Hello from Laura"))
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:58804", "/products", 200, "Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/products"))
 | 
			
		||||
@@ -484,7 +484,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51879,
 | 
			
		||||
                                    Port = 54015,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/products",
 | 
			
		||||
@@ -493,7 +493,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "/products", 200, "Hello from Laura"))
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:54015", "/products", 200, "Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/products/"))
 | 
			
		||||
@@ -517,7 +517,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            new FileHostAndPort
 | 
			
		||||
                            {
 | 
			
		||||
                                Host = "localhost",
 | 
			
		||||
                                Port = 51879,
 | 
			
		||||
                                Port = 54072,
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        UpstreamPathTemplate = "/products/{productId}",
 | 
			
		||||
@@ -526,7 +526,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "/products", 200, "Hello from Laura"))
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:54072", "/products", 200, "Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/products/"))
 | 
			
		||||
@@ -550,7 +550,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51879,
 | 
			
		||||
                                    Port = 55961,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/products/{productId}",
 | 
			
		||||
@@ -559,7 +559,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "/api/products/1", 200, "Some Product"))
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:55961", "/api/products/1", 200, "Some Product"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/products/1"))
 | 
			
		||||
@@ -584,7 +584,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51879,
 | 
			
		||||
                                    Port = 51116,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/{variantId}/products/{productId}",
 | 
			
		||||
@@ -593,7 +593,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "/api/23/products/1", 200, "Some Product"))
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51116", "/api/23/products/1", 200, "Some Product"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("23/products/1"))
 | 
			
		||||
@@ -618,7 +618,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51879,
 | 
			
		||||
                                    Port = 51809,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/products/{productId}",
 | 
			
		||||
@@ -627,7 +627,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenThereIsAServiceRunningOn("http://localhost:51879", "/api/products/1", 200, "Some Product"))
 | 
			
		||||
            this.Given(x => GivenThereIsAServiceRunningOn("http://localhost:51809", "/api/products/1", 200, "Some Product"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/products/1"))
 | 
			
		||||
@@ -650,7 +650,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51879,
 | 
			
		||||
                                    Port = 56615,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
@@ -660,7 +660,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "/", 201, string.Empty))
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:56615", "/", 201, string.Empty))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .And(x => _steps.GivenThePostHasContent("postContent"))
 | 
			
		||||
@@ -686,7 +686,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51879,
 | 
			
		||||
                                    Port = 57771,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
@@ -694,7 +694,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "/newThing", 200, "Hello from Laura"))
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:57771", "/newThing", 200, "Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/newThing?DeviceType=IphoneApp&Browser=moonpigIphone&BrowserString=-&CountryCode=123&DeviceName=iPhone 5 (GSM+CDMA)&OperatingSystem=iPhone OS 7.1.2&BrowserVersion=3708AdHoc&ipAddress=-"))
 | 
			
		||||
@@ -719,7 +719,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51879,
 | 
			
		||||
                                    Port = 55609,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/myApp1Name/api/{urlPath}",
 | 
			
		||||
@@ -728,7 +728,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "/api/products/1", 200, "Some Product"))
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:55609", "/api/products/1", 200, "Some Product"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/myApp1Name/api/products/1"))
 | 
			
		||||
@@ -752,7 +752,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51879,
 | 
			
		||||
                                    Port = 59911,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
@@ -762,7 +762,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "", 201, string.Empty))
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:59911", "", 201, string.Empty))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .And(x => _steps.GivenThePostHasContent("postContent"))
 | 
			
		||||
@@ -786,7 +786,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51879,
 | 
			
		||||
                                    Port = 59187,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
@@ -796,7 +796,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "/", 200, "Hello from Laura"))
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:59187", "/", 200, "Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
@@ -821,7 +821,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            new FileHostAndPort
 | 
			
		||||
                            {
 | 
			
		||||
                                Host = "localhost",
 | 
			
		||||
                                Port = 51879,
 | 
			
		||||
                                Port = 54079,
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        UpstreamPathTemplate = "/vacancy/",
 | 
			
		||||
@@ -837,7 +837,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                            new FileHostAndPort
 | 
			
		||||
                            {
 | 
			
		||||
                                Host = "localhost",
 | 
			
		||||
                                Port = 51879,
 | 
			
		||||
                                Port = 54079,
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        UpstreamPathTemplate = "/vacancy/{vacancyId}",
 | 
			
		||||
@@ -847,7 +847,7 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "/api/v1/vacancy/1", 200, "Hello from Laura"))
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:54079", "/api/v1/vacancy/1", 200, "Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("api/vacancy/1"))
 | 
			
		||||
 
 | 
			
		||||
@@ -10,12 +10,14 @@
 | 
			
		||||
    using Microsoft.Extensions.Configuration;
 | 
			
		||||
    using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
    using Microsoft.Extensions.Logging;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Newtonsoft.Json;
 | 
			
		||||
    using Ocelot.Cache.CacheManager;
 | 
			
		||||
    using Ocelot.Configuration.Creator;
 | 
			
		||||
    using Ocelot.Configuration.File;
 | 
			
		||||
    using Ocelot.DependencyInjection;
 | 
			
		||||
    using Ocelot.Infrastructure;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Ocelot.Middleware.Multiplexer;
 | 
			
		||||
    using Ocelot.Provider.Consul;
 | 
			
		||||
@@ -1120,5 +1122,60 @@
 | 
			
		||||
 | 
			
		||||
            _ocelotClient = _ocelotServer.CreateClient();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void GivenOcelotIsRunningWithLogger()
 | 
			
		||||
        {
 | 
			
		||||
            _webHostBuilder = new WebHostBuilder();
 | 
			
		||||
 | 
			
		||||
            _webHostBuilder
 | 
			
		||||
                .ConfigureAppConfiguration((hostingContext, config) =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
 | 
			
		||||
                    var env = hostingContext.HostingEnvironment;
 | 
			
		||||
                    config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
 | 
			
		||||
                        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: false);
 | 
			
		||||
                    config.AddJsonFile("ocelot.json", false, false);
 | 
			
		||||
                    config.AddEnvironmentVariables();
 | 
			
		||||
                })
 | 
			
		||||
                .ConfigureServices(s =>
 | 
			
		||||
                {
 | 
			
		||||
                    s.AddOcelot();
 | 
			
		||||
                    s.AddSingleton<IOcelotLoggerFactory, MockLoggerFactory>();
 | 
			
		||||
                })
 | 
			
		||||
                .Configure(app =>
 | 
			
		||||
                {
 | 
			
		||||
                    app.UseOcelot().Wait();
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            _ocelotServer = new TestServer(_webHostBuilder);
 | 
			
		||||
 | 
			
		||||
            _ocelotClient = _ocelotServer.CreateClient();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void ThenWarningShouldBeLogged()
 | 
			
		||||
        {
 | 
			
		||||
            MockLoggerFactory loggerFactory = (MockLoggerFactory)_ocelotServer.Host.Services.GetService<IOcelotLoggerFactory>();
 | 
			
		||||
            loggerFactory.Verify();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        internal class MockLoggerFactory : IOcelotLoggerFactory
 | 
			
		||||
        {
 | 
			
		||||
            private Mock<IOcelotLogger> _logger;
 | 
			
		||||
 | 
			
		||||
            public IOcelotLogger CreateLogger<T>()
 | 
			
		||||
            {
 | 
			
		||||
                if (_logger == null)
 | 
			
		||||
                {
 | 
			
		||||
                    _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
                    _logger.Setup(x => x.LogWarning(It.IsAny<string>())).Verifiable();
 | 
			
		||||
                }
 | 
			
		||||
                return _logger.Object;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public void Verify()
 | 
			
		||||
            {
 | 
			
		||||
                _logger.Verify(x => x.LogWarning(It.IsAny<string>()), Times.Once);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <VersionPrefix>0.0.0-dev</VersionPrefix>
 | 
			
		||||
    <TargetFramework>netcoreapp3.0</TargetFramework>
 | 
			
		||||
    <TargetFramework>netcoreapp3.1</TargetFramework>
 | 
			
		||||
    <AssemblyName>Ocelot.Benchmarks</AssemblyName>
 | 
			
		||||
    <OutputType>Exe</OutputType>
 | 
			
		||||
    <PackageId>Ocelot.Benchmarks</PackageId>
 | 
			
		||||
@@ -25,6 +25,6 @@
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-19367-01" />
 | 
			
		||||
    <PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.0.0" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
</Project>
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,199 +1,199 @@
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
[assembly: CollectionBehavior(DisableTestParallelization = true)]
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.IntegrationTests
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Builder;
 | 
			
		||||
    using Microsoft.AspNetCore.Hosting;
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Microsoft.Extensions.Configuration;
 | 
			
		||||
    using Newtonsoft.Json;
 | 
			
		||||
    using Ocelot.Configuration.File;
 | 
			
		||||
    using Ocelot.DependencyInjection;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.IO;
 | 
			
		||||
    using System.Linq;
 | 
			
		||||
    using System.Net;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
 | 
			
		||||
    public class HeaderTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private readonly HttpClient _httpClient;
 | 
			
		||||
        private IWebHost _builder;
 | 
			
		||||
        private IWebHostBuilder _webHostBuilder;
 | 
			
		||||
        private readonly string _ocelotBaseUrl;
 | 
			
		||||
        private IWebHost _downstreamBuilder;
 | 
			
		||||
        private HttpResponseMessage _response;
 | 
			
		||||
 | 
			
		||||
        public HeaderTests()
 | 
			
		||||
        {
 | 
			
		||||
            _httpClient = new HttpClient();
 | 
			
		||||
            _ocelotBaseUrl = "http://localhost:5005";
 | 
			
		||||
            _httpClient.BaseAddress = new Uri(_ocelotBaseUrl);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_pass_remote_ip_address_if_as_x_forwarded_for_header()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                {
 | 
			
		||||
                    new FileReRoute
 | 
			
		||||
                    {
 | 
			
		||||
                        DownstreamPathTemplate = "/",
 | 
			
		||||
                        DownstreamScheme = "http",
 | 
			
		||||
                        DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                        {
 | 
			
		||||
                            new FileHostAndPort
 | 
			
		||||
                            {
 | 
			
		||||
                                Host = "localhost",
 | 
			
		||||
                                Port = 6773,
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        UpstreamPathTemplate = "/",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        UpstreamHeaderTransform = new Dictionary<string,string>
 | 
			
		||||
                        {
 | 
			
		||||
                            {"X-Forwarded-For", "{RemoteIpAddress}"}
 | 
			
		||||
                        },
 | 
			
		||||
                        HttpHandlerOptions = new FileHttpHandlerOptions
 | 
			
		||||
                        {
 | 
			
		||||
                            AllowAutoRedirect = false
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenThereIsAServiceRunningOn("http://localhost:6773", 200, "X-Forwarded-For"))
 | 
			
		||||
                .And(x => GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => ThenXForwardedForIsSet())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAServiceRunningOn(string url, int statusCode, string headerKey)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamBuilder = new WebHostBuilder()
 | 
			
		||||
                .UseUrls(url)
 | 
			
		||||
                .UseKestrel()
 | 
			
		||||
                .UseContentRoot(Directory.GetCurrentDirectory())
 | 
			
		||||
                .UseIISIntegration()
 | 
			
		||||
                .UseUrls(url)
 | 
			
		||||
                .Configure(app =>
 | 
			
		||||
                {
 | 
			
		||||
                    app.Run(async context =>
 | 
			
		||||
                    {
 | 
			
		||||
                        if (context.Request.Headers.TryGetValue(headerKey, out var values))
 | 
			
		||||
                        {
 | 
			
		||||
                            var result = values.First();
 | 
			
		||||
                            context.Response.StatusCode = statusCode;
 | 
			
		||||
                            await context.Response.WriteAsync(result);
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
                })
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            _downstreamBuilder.Start();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenOcelotIsRunning()
 | 
			
		||||
        {
 | 
			
		||||
            _webHostBuilder = new WebHostBuilder()
 | 
			
		||||
                .UseUrls(_ocelotBaseUrl)
 | 
			
		||||
                .UseKestrel()
 | 
			
		||||
                .UseContentRoot(Directory.GetCurrentDirectory())
 | 
			
		||||
                .ConfigureAppConfiguration((hostingContext, config) =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
 | 
			
		||||
                    var env = hostingContext.HostingEnvironment;
 | 
			
		||||
                    config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
 | 
			
		||||
                        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: false);
 | 
			
		||||
                    config.AddJsonFile("ocelot.json", false, false);
 | 
			
		||||
                    config.AddEnvironmentVariables();
 | 
			
		||||
                })
 | 
			
		||||
                .ConfigureServices(x =>
 | 
			
		||||
                {
 | 
			
		||||
                    x.AddOcelot();
 | 
			
		||||
                })
 | 
			
		||||
                .Configure(app =>
 | 
			
		||||
                {
 | 
			
		||||
                    app.UseOcelot().Wait();
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            _builder = _webHostBuilder.Build();
 | 
			
		||||
 | 
			
		||||
            _builder.Start();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAConfiguration(FileConfiguration fileConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            var configurationPath = $"{Directory.GetCurrentDirectory()}/ocelot.json";
 | 
			
		||||
 | 
			
		||||
            var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration);
 | 
			
		||||
 | 
			
		||||
            if (File.Exists(configurationPath))
 | 
			
		||||
            {
 | 
			
		||||
                File.Delete(configurationPath);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            File.WriteAllText(configurationPath, jsonConfiguration);
 | 
			
		||||
 | 
			
		||||
            var text = File.ReadAllText(configurationPath);
 | 
			
		||||
 | 
			
		||||
            configurationPath = $"{AppContext.BaseDirectory}/ocelot.json";
 | 
			
		||||
 | 
			
		||||
            if (File.Exists(configurationPath))
 | 
			
		||||
            {
 | 
			
		||||
                File.Delete(configurationPath);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            File.WriteAllText(configurationPath, jsonConfiguration);
 | 
			
		||||
 | 
			
		||||
            text = File.ReadAllText(configurationPath);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task WhenIGetUrlOnTheApiGateway(string url)
 | 
			
		||||
        {
 | 
			
		||||
            var request = new HttpRequestMessage(HttpMethod.Get, url);
 | 
			
		||||
            _response = await _httpClient.SendAsync(request);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheStatusCodeShouldBe(HttpStatusCode code)
 | 
			
		||||
        {
 | 
			
		||||
            _response.StatusCode.ShouldBe(code);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenXForwardedForIsSet()
 | 
			
		||||
        {
 | 
			
		||||
            var windowsOrMac = "::1";
 | 
			
		||||
            var linux = "127.0.0.1";
 | 
			
		||||
 | 
			
		||||
            var header = _response.Content.ReadAsStringAsync().Result;
 | 
			
		||||
 | 
			
		||||
            bool passed = false;
 | 
			
		||||
 | 
			
		||||
            if (header == windowsOrMac || header == linux)
 | 
			
		||||
            {
 | 
			
		||||
                passed = true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            passed.ShouldBeTrue();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            _builder?.Dispose();
 | 
			
		||||
            _httpClient?.Dispose();
 | 
			
		||||
            _downstreamBuilder?.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
[assembly: CollectionBehavior(DisableTestParallelization = true)]
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.IntegrationTests
 | 
			
		||||
{
 | 
			
		||||
    using Microsoft.AspNetCore.Builder;
 | 
			
		||||
    using Microsoft.AspNetCore.Hosting;
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Microsoft.Extensions.Configuration;
 | 
			
		||||
    using Newtonsoft.Json;
 | 
			
		||||
    using Ocelot.Configuration.File;
 | 
			
		||||
    using Ocelot.DependencyInjection;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.IO;
 | 
			
		||||
    using System.Linq;
 | 
			
		||||
    using System.Net;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
 | 
			
		||||
    public class HeaderTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private readonly HttpClient _httpClient;
 | 
			
		||||
        private IWebHost _builder;
 | 
			
		||||
        private IWebHostBuilder _webHostBuilder;
 | 
			
		||||
        private readonly string _ocelotBaseUrl;
 | 
			
		||||
        private IWebHost _downstreamBuilder;
 | 
			
		||||
        private HttpResponseMessage _response;
 | 
			
		||||
 | 
			
		||||
        public HeaderTests()
 | 
			
		||||
        {
 | 
			
		||||
            _httpClient = new HttpClient();
 | 
			
		||||
            _ocelotBaseUrl = "http://localhost:5010";
 | 
			
		||||
            _httpClient.BaseAddress = new Uri(_ocelotBaseUrl);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_pass_remote_ip_address_if_as_x_forwarded_for_header()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                {
 | 
			
		||||
                    new FileReRoute
 | 
			
		||||
                    {
 | 
			
		||||
                        DownstreamPathTemplate = "/",
 | 
			
		||||
                        DownstreamScheme = "http",
 | 
			
		||||
                        DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                        {
 | 
			
		||||
                            new FileHostAndPort
 | 
			
		||||
                            {
 | 
			
		||||
                                Host = "localhost",
 | 
			
		||||
                                Port = 6773,
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        UpstreamPathTemplate = "/",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        UpstreamHeaderTransform = new Dictionary<string,string>
 | 
			
		||||
                        {
 | 
			
		||||
                            {"X-Forwarded-For", "{RemoteIpAddress}"}
 | 
			
		||||
                        },
 | 
			
		||||
                        HttpHandlerOptions = new FileHttpHandlerOptions
 | 
			
		||||
                        {
 | 
			
		||||
                            AllowAutoRedirect = false
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenThereIsAServiceRunningOn("http://localhost:6773", 200, "X-Forwarded-For"))
 | 
			
		||||
                .And(x => GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => ThenXForwardedForIsSet())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAServiceRunningOn(string url, int statusCode, string headerKey)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamBuilder = new WebHostBuilder()
 | 
			
		||||
                .UseUrls(url)
 | 
			
		||||
                .UseKestrel()
 | 
			
		||||
                .UseContentRoot(Directory.GetCurrentDirectory())
 | 
			
		||||
                .UseIISIntegration()
 | 
			
		||||
                .UseUrls(url)
 | 
			
		||||
                .Configure(app =>
 | 
			
		||||
                {
 | 
			
		||||
                    app.Run(async context =>
 | 
			
		||||
                    {
 | 
			
		||||
                        if (context.Request.Headers.TryGetValue(headerKey, out var values))
 | 
			
		||||
                        {
 | 
			
		||||
                            var result = values.First();
 | 
			
		||||
                            context.Response.StatusCode = statusCode;
 | 
			
		||||
                            await context.Response.WriteAsync(result);
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
                })
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            _downstreamBuilder.Start();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenOcelotIsRunning()
 | 
			
		||||
        {
 | 
			
		||||
            _webHostBuilder = new WebHostBuilder()
 | 
			
		||||
                .UseUrls(_ocelotBaseUrl)
 | 
			
		||||
                .UseKestrel()
 | 
			
		||||
                .UseContentRoot(Directory.GetCurrentDirectory())
 | 
			
		||||
                .ConfigureAppConfiguration((hostingContext, config) =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
 | 
			
		||||
                    var env = hostingContext.HostingEnvironment;
 | 
			
		||||
                    config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
 | 
			
		||||
                        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: false);
 | 
			
		||||
                    config.AddJsonFile("ocelot.json", false, false);
 | 
			
		||||
                    config.AddEnvironmentVariables();
 | 
			
		||||
                })
 | 
			
		||||
                .ConfigureServices(x =>
 | 
			
		||||
                {
 | 
			
		||||
                    x.AddOcelot();
 | 
			
		||||
                })
 | 
			
		||||
                .Configure(app =>
 | 
			
		||||
                {
 | 
			
		||||
                    app.UseOcelot().Wait();
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            _builder = _webHostBuilder.Build();
 | 
			
		||||
 | 
			
		||||
            _builder.Start();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAConfiguration(FileConfiguration fileConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            var configurationPath = $"{Directory.GetCurrentDirectory()}/ocelot.json";
 | 
			
		||||
 | 
			
		||||
            var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration);
 | 
			
		||||
 | 
			
		||||
            if (File.Exists(configurationPath))
 | 
			
		||||
            {
 | 
			
		||||
                File.Delete(configurationPath);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            File.WriteAllText(configurationPath, jsonConfiguration);
 | 
			
		||||
 | 
			
		||||
            var text = File.ReadAllText(configurationPath);
 | 
			
		||||
 | 
			
		||||
            configurationPath = $"{AppContext.BaseDirectory}/ocelot.json";
 | 
			
		||||
 | 
			
		||||
            if (File.Exists(configurationPath))
 | 
			
		||||
            {
 | 
			
		||||
                File.Delete(configurationPath);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            File.WriteAllText(configurationPath, jsonConfiguration);
 | 
			
		||||
 | 
			
		||||
            text = File.ReadAllText(configurationPath);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task WhenIGetUrlOnTheApiGateway(string url)
 | 
			
		||||
        {
 | 
			
		||||
            var request = new HttpRequestMessage(HttpMethod.Get, url);
 | 
			
		||||
            _response = await _httpClient.SendAsync(request);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheStatusCodeShouldBe(HttpStatusCode code)
 | 
			
		||||
        {
 | 
			
		||||
            _response.StatusCode.ShouldBe(code);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenXForwardedForIsSet()
 | 
			
		||||
        {
 | 
			
		||||
            var windowsOrMac = "::1";
 | 
			
		||||
            var linux = "127.0.0.1";
 | 
			
		||||
 | 
			
		||||
            var header = _response.Content.ReadAsStringAsync().Result;
 | 
			
		||||
 | 
			
		||||
            bool passed = false;
 | 
			
		||||
 | 
			
		||||
            if (header == windowsOrMac || header == linux)
 | 
			
		||||
            {
 | 
			
		||||
                passed = true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            passed.ShouldBeTrue();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            _builder?.Dispose();
 | 
			
		||||
            _httpClient?.Dispose();
 | 
			
		||||
            _downstreamBuilder?.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,61 +1,61 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <VersionPrefix>0.0.0-dev</VersionPrefix>
 | 
			
		||||
    <TargetFramework>netcoreapp3.0</TargetFramework>
 | 
			
		||||
    <AssemblyName>Ocelot.IntegrationTests</AssemblyName>
 | 
			
		||||
    <OutputType>Exe</OutputType>
 | 
			
		||||
    <PackageId>Ocelot.IntegrationTests</PackageId>
 | 
			
		||||
    <GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
 | 
			
		||||
    <RuntimeIdentifiers>win10-x64;osx.10.11-x64;osx.10.12-x64;win7-x64</RuntimeIdentifiers>
 | 
			
		||||
    <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
 | 
			
		||||
    <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
 | 
			
		||||
    <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
 | 
			
		||||
    <CodeAnalysisRuleSet>..\..\codeanalysis.ruleset</CodeAnalysisRuleSet>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <None Update="peers.json;appsettings.json;idsrv3test.pfx">
 | 
			
		||||
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 | 
			
		||||
    </None>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot\Ocelot.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Administration\Ocelot.Administration.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Cache.CacheManager\Ocelot.Cache.CacheManager.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Provider.Consul\Ocelot.Provider.Consul.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Provider.Eureka\Ocelot.Provider.Eureka.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Provider.Polly\Ocelot.Provider.Polly.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Provider.Rafty\Ocelot.Provider.Rafty.csproj" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Data.SQLite" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.66">
 | 
			
		||||
      <PrivateAssets>all</PrivateAssets>
 | 
			
		||||
    </PackageReference>
 | 
			
		||||
    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
 | 
			
		||||
      <PrivateAssets>all</PrivateAssets>
 | 
			
		||||
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
 | 
			
		||||
    </PackageReference>
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Logging" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.DotNet.InternalAbstractions" Version="1.0.500-preview2-1-003177" />
 | 
			
		||||
    <PackageReference Include="xunit" Version="2.4.1" />
 | 
			
		||||
    <PackageReference Include="Shouldly" Version="4.0.0-beta0002" />
 | 
			
		||||
    <PackageReference Include="TestStack.BDDfy" Version="4.3.2" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Data.SQLite" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="IdentityServer4.AccessTokenValidation" Version="3.0.1" />
 | 
			
		||||
    <PackageReference Include="IdentityServer4" Version="3.0.1" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-19367-01" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <VersionPrefix>0.0.0-dev</VersionPrefix>
 | 
			
		||||
    <TargetFramework>netcoreapp3.1</TargetFramework>
 | 
			
		||||
    <AssemblyName>Ocelot.IntegrationTests</AssemblyName>
 | 
			
		||||
    <OutputType>Exe</OutputType>
 | 
			
		||||
    <PackageId>Ocelot.IntegrationTests</PackageId>
 | 
			
		||||
    <GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
 | 
			
		||||
    <RuntimeIdentifiers>win10-x64;osx.10.11-x64;osx.10.12-x64;win7-x64</RuntimeIdentifiers>
 | 
			
		||||
    <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
 | 
			
		||||
    <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
 | 
			
		||||
    <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
 | 
			
		||||
    <CodeAnalysisRuleSet>..\..\codeanalysis.ruleset</CodeAnalysisRuleSet>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <None Update="peers.json;appsettings.json;idsrv3test.pfx">
 | 
			
		||||
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 | 
			
		||||
    </None>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot\Ocelot.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Administration\Ocelot.Administration.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Cache.CacheManager\Ocelot.Cache.CacheManager.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Provider.Consul\Ocelot.Provider.Consul.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Provider.Eureka\Ocelot.Provider.Eureka.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Provider.Polly\Ocelot.Provider.Polly.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Provider.Rafty\Ocelot.Provider.Rafty.csproj" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Data.SQLite" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.66">
 | 
			
		||||
      <PrivateAssets>all</PrivateAssets>
 | 
			
		||||
    </PackageReference>
 | 
			
		||||
    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
 | 
			
		||||
      <PrivateAssets>all</PrivateAssets>
 | 
			
		||||
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
 | 
			
		||||
    </PackageReference>
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Logging" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.DotNet.InternalAbstractions" Version="1.0.500-preview2-1-003177" />
 | 
			
		||||
    <PackageReference Include="xunit" Version="2.4.1" />
 | 
			
		||||
    <PackageReference Include="Shouldly" Version="4.0.0-beta0002" />
 | 
			
		||||
    <PackageReference Include="TestStack.BDDfy" Version="4.3.2" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Data.SQLite" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="IdentityServer4.AccessTokenValidation" Version="3.0.1" />
 | 
			
		||||
    <PackageReference Include="IdentityServer4" Version="3.0.1" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.0.0" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
</Project>
 | 
			
		||||
@@ -1,204 +1,204 @@
 | 
			
		||||
using Microsoft.AspNetCore.Builder;
 | 
			
		||||
using Microsoft.AspNetCore.Hosting;
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Microsoft.Extensions.Configuration;
 | 
			
		||||
using Newtonsoft.Json;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using Ocelot.DependencyInjection;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.IntegrationTests
 | 
			
		||||
{
 | 
			
		||||
    public class ThreadSafeHeadersTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private readonly HttpClient _httpClient;
 | 
			
		||||
        private IWebHost _builder;
 | 
			
		||||
        private IWebHostBuilder _webHostBuilder;
 | 
			
		||||
        private readonly string _ocelotBaseUrl;
 | 
			
		||||
        private IWebHost _downstreamBuilder;
 | 
			
		||||
        private readonly Random _random;
 | 
			
		||||
        private readonly ConcurrentBag<ThreadSafeHeadersTestResult> _results;
 | 
			
		||||
 | 
			
		||||
        public ThreadSafeHeadersTests()
 | 
			
		||||
        {
 | 
			
		||||
            _results = new ConcurrentBag<ThreadSafeHeadersTestResult>();
 | 
			
		||||
            _random = new Random();
 | 
			
		||||
            _httpClient = new HttpClient();
 | 
			
		||||
            _ocelotBaseUrl = "http://localhost:5001";
 | 
			
		||||
            _httpClient.BaseAddress = new Uri(_ocelotBaseUrl);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_same_response_for_each_different_header_under_load_to_downsteam_service()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51879,
 | 
			
		||||
                                },
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        },
 | 
			
		||||
                    },
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => GivenThereIsAServiceRunningOn("http://localhost:51879"))
 | 
			
		||||
                .And(x => GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => WhenIGetUrlOnTheApiGatewayMultipleTimesWithDifferentHeaderValues("/", 300))
 | 
			
		||||
                .Then(x => ThenTheSameHeaderValuesAreReturnedByTheDownstreamService())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAServiceRunningOn(string url)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamBuilder = new WebHostBuilder()
 | 
			
		||||
                .UseUrls(url)
 | 
			
		||||
                .UseKestrel()
 | 
			
		||||
                .UseContentRoot(Directory.GetCurrentDirectory())
 | 
			
		||||
                .UseIISIntegration()
 | 
			
		||||
                .UseUrls(url)
 | 
			
		||||
                .Configure(app =>
 | 
			
		||||
                {
 | 
			
		||||
                    app.Run(async context =>
 | 
			
		||||
                    {
 | 
			
		||||
                        var header = context.Request.Headers["ThreadSafeHeadersTest"];
 | 
			
		||||
 | 
			
		||||
                        context.Response.StatusCode = 200;
 | 
			
		||||
                        await context.Response.WriteAsync(header[0]);
 | 
			
		||||
                    });
 | 
			
		||||
                })
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            _downstreamBuilder.Start();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenOcelotIsRunning()
 | 
			
		||||
        {
 | 
			
		||||
            _webHostBuilder = new WebHostBuilder()
 | 
			
		||||
                .UseUrls(_ocelotBaseUrl)
 | 
			
		||||
                .UseKestrel()
 | 
			
		||||
                .UseContentRoot(Directory.GetCurrentDirectory())
 | 
			
		||||
                .ConfigureAppConfiguration((hostingContext, config) =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
 | 
			
		||||
                    var env = hostingContext.HostingEnvironment;
 | 
			
		||||
                    config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
 | 
			
		||||
                        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: false);
 | 
			
		||||
                    config.AddJsonFile("ocelot.json", false, false);
 | 
			
		||||
                    config.AddEnvironmentVariables();
 | 
			
		||||
                })
 | 
			
		||||
                .ConfigureServices(x =>
 | 
			
		||||
                {
 | 
			
		||||
                    x.AddOcelot();
 | 
			
		||||
                })
 | 
			
		||||
                .Configure(app =>
 | 
			
		||||
                {
 | 
			
		||||
                    app.UseOcelot().Wait();
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            _builder = _webHostBuilder.Build();
 | 
			
		||||
 | 
			
		||||
            _builder.Start();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAConfiguration(FileConfiguration fileConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            var configurationPath = $"{Directory.GetCurrentDirectory()}/ocelot.json";
 | 
			
		||||
 | 
			
		||||
            var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration);
 | 
			
		||||
 | 
			
		||||
            if (File.Exists(configurationPath))
 | 
			
		||||
            {
 | 
			
		||||
                File.Delete(configurationPath);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            File.WriteAllText(configurationPath, jsonConfiguration);
 | 
			
		||||
 | 
			
		||||
            var text = File.ReadAllText(configurationPath);
 | 
			
		||||
 | 
			
		||||
            configurationPath = $"{AppContext.BaseDirectory}/ocelot.json";
 | 
			
		||||
 | 
			
		||||
            if (File.Exists(configurationPath))
 | 
			
		||||
            {
 | 
			
		||||
                File.Delete(configurationPath);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            File.WriteAllText(configurationPath, jsonConfiguration);
 | 
			
		||||
 | 
			
		||||
            text = File.ReadAllText(configurationPath);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIGetUrlOnTheApiGatewayMultipleTimesWithDifferentHeaderValues(string url, int times)
 | 
			
		||||
        {
 | 
			
		||||
            var tasks = new Task[times];
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < times; i++)
 | 
			
		||||
            {
 | 
			
		||||
                var urlCopy = url;
 | 
			
		||||
                var random = _random.Next(0, 50);
 | 
			
		||||
                tasks[i] = GetForThreadSafeHeadersTest(urlCopy, random);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Task.WaitAll(tasks);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task GetForThreadSafeHeadersTest(string url, int random)
 | 
			
		||||
        {
 | 
			
		||||
            var request = new HttpRequestMessage(HttpMethod.Get, url);
 | 
			
		||||
            request.Headers.Add("ThreadSafeHeadersTest", new List<string> { random.ToString() });
 | 
			
		||||
            var response = await _httpClient.SendAsync(request);
 | 
			
		||||
            var content = await response.Content.ReadAsStringAsync();
 | 
			
		||||
            int result = int.Parse(content);
 | 
			
		||||
            var tshtr = new ThreadSafeHeadersTestResult(result, random);
 | 
			
		||||
            _results.Add(tshtr);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheSameHeaderValuesAreReturnedByTheDownstreamService()
 | 
			
		||||
        {
 | 
			
		||||
            foreach (var result in _results)
 | 
			
		||||
            {
 | 
			
		||||
                result.Result.ShouldBe(result.Random);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            _builder?.Dispose();
 | 
			
		||||
            _httpClient?.Dispose();
 | 
			
		||||
            _downstreamBuilder?.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private class ThreadSafeHeadersTestResult
 | 
			
		||||
        {
 | 
			
		||||
            public ThreadSafeHeadersTestResult(int result, int random)
 | 
			
		||||
            {
 | 
			
		||||
                Result = result;
 | 
			
		||||
                Random = random;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public int Result { get; private set; }
 | 
			
		||||
            public int Random { get; private set; }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
using Microsoft.AspNetCore.Builder;
 | 
			
		||||
using Microsoft.AspNetCore.Hosting;
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Microsoft.Extensions.Configuration;
 | 
			
		||||
using Newtonsoft.Json;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using Ocelot.DependencyInjection;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.IntegrationTests
 | 
			
		||||
{
 | 
			
		||||
    public class ThreadSafeHeadersTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private readonly HttpClient _httpClient;
 | 
			
		||||
        private IWebHost _builder;
 | 
			
		||||
        private IWebHostBuilder _webHostBuilder;
 | 
			
		||||
        private readonly string _ocelotBaseUrl;
 | 
			
		||||
        private IWebHost _downstreamBuilder;
 | 
			
		||||
        private readonly Random _random;
 | 
			
		||||
        private readonly ConcurrentBag<ThreadSafeHeadersTestResult> _results;
 | 
			
		||||
 | 
			
		||||
        public ThreadSafeHeadersTests()
 | 
			
		||||
        {
 | 
			
		||||
            _results = new ConcurrentBag<ThreadSafeHeadersTestResult>();
 | 
			
		||||
            _random = new Random();
 | 
			
		||||
            _httpClient = new HttpClient();
 | 
			
		||||
            _ocelotBaseUrl = "http://localhost:5001";
 | 
			
		||||
            _httpClient.BaseAddress = new Uri(_ocelotBaseUrl);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_same_response_for_each_different_header_under_load_to_downsteam_service()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51611,
 | 
			
		||||
                                },
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        },
 | 
			
		||||
                    },
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => GivenThereIsAServiceRunningOn("http://localhost:51611"))
 | 
			
		||||
                .And(x => GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => WhenIGetUrlOnTheApiGatewayMultipleTimesWithDifferentHeaderValues("/", 300))
 | 
			
		||||
                .Then(x => ThenTheSameHeaderValuesAreReturnedByTheDownstreamService())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAServiceRunningOn(string url)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamBuilder = new WebHostBuilder()
 | 
			
		||||
                .UseUrls(url)
 | 
			
		||||
                .UseKestrel()
 | 
			
		||||
                .UseContentRoot(Directory.GetCurrentDirectory())
 | 
			
		||||
                .UseIISIntegration()
 | 
			
		||||
                .UseUrls(url)
 | 
			
		||||
                .Configure(app =>
 | 
			
		||||
                {
 | 
			
		||||
                    app.Run(async context =>
 | 
			
		||||
                    {
 | 
			
		||||
                        var header = context.Request.Headers["ThreadSafeHeadersTest"];
 | 
			
		||||
 | 
			
		||||
                        context.Response.StatusCode = 200;
 | 
			
		||||
                        await context.Response.WriteAsync(header[0]);
 | 
			
		||||
                    });
 | 
			
		||||
                })
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            _downstreamBuilder.Start();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenOcelotIsRunning()
 | 
			
		||||
        {
 | 
			
		||||
            _webHostBuilder = new WebHostBuilder()
 | 
			
		||||
                .UseUrls(_ocelotBaseUrl)
 | 
			
		||||
                .UseKestrel()
 | 
			
		||||
                .UseContentRoot(Directory.GetCurrentDirectory())
 | 
			
		||||
                .ConfigureAppConfiguration((hostingContext, config) =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
 | 
			
		||||
                    var env = hostingContext.HostingEnvironment;
 | 
			
		||||
                    config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
 | 
			
		||||
                        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: false);
 | 
			
		||||
                    config.AddJsonFile("ocelot.json", false, false);
 | 
			
		||||
                    config.AddEnvironmentVariables();
 | 
			
		||||
                })
 | 
			
		||||
                .ConfigureServices(x =>
 | 
			
		||||
                {
 | 
			
		||||
                    x.AddOcelot();
 | 
			
		||||
                })
 | 
			
		||||
                .Configure(app =>
 | 
			
		||||
                {
 | 
			
		||||
                    app.UseOcelot().Wait();
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            _builder = _webHostBuilder.Build();
 | 
			
		||||
 | 
			
		||||
            _builder.Start();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAConfiguration(FileConfiguration fileConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            var configurationPath = $"{Directory.GetCurrentDirectory()}/ocelot.json";
 | 
			
		||||
 | 
			
		||||
            var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration);
 | 
			
		||||
 | 
			
		||||
            if (File.Exists(configurationPath))
 | 
			
		||||
            {
 | 
			
		||||
                File.Delete(configurationPath);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            File.WriteAllText(configurationPath, jsonConfiguration);
 | 
			
		||||
 | 
			
		||||
            var text = File.ReadAllText(configurationPath);
 | 
			
		||||
 | 
			
		||||
            configurationPath = $"{AppContext.BaseDirectory}/ocelot.json";
 | 
			
		||||
 | 
			
		||||
            if (File.Exists(configurationPath))
 | 
			
		||||
            {
 | 
			
		||||
                File.Delete(configurationPath);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            File.WriteAllText(configurationPath, jsonConfiguration);
 | 
			
		||||
 | 
			
		||||
            text = File.ReadAllText(configurationPath);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIGetUrlOnTheApiGatewayMultipleTimesWithDifferentHeaderValues(string url, int times)
 | 
			
		||||
        {
 | 
			
		||||
            var tasks = new Task[times];
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < times; i++)
 | 
			
		||||
            {
 | 
			
		||||
                var urlCopy = url;
 | 
			
		||||
                var random = _random.Next(0, 50);
 | 
			
		||||
                tasks[i] = GetForThreadSafeHeadersTest(urlCopy, random);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Task.WaitAll(tasks);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task GetForThreadSafeHeadersTest(string url, int random)
 | 
			
		||||
        {
 | 
			
		||||
            var request = new HttpRequestMessage(HttpMethod.Get, url);
 | 
			
		||||
            request.Headers.Add("ThreadSafeHeadersTest", new List<string> { random.ToString() });
 | 
			
		||||
            var response = await _httpClient.SendAsync(request);
 | 
			
		||||
            var content = await response.Content.ReadAsStringAsync();
 | 
			
		||||
            int result = int.Parse(content);
 | 
			
		||||
            var tshtr = new ThreadSafeHeadersTestResult(result, random);
 | 
			
		||||
            _results.Add(tshtr);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheSameHeaderValuesAreReturnedByTheDownstreamService()
 | 
			
		||||
        {
 | 
			
		||||
            foreach (var result in _results)
 | 
			
		||||
            {
 | 
			
		||||
                result.Result.ShouldBe(result.Random);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            _builder?.Dispose();
 | 
			
		||||
            _httpClient?.Dispose();
 | 
			
		||||
            _downstreamBuilder?.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private class ThreadSafeHeadersTestResult
 | 
			
		||||
        {
 | 
			
		||||
            public ThreadSafeHeadersTestResult(int result, int random)
 | 
			
		||||
            {
 | 
			
		||||
                Result = result;
 | 
			
		||||
                Random = random;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public int Result { get; private set; }
 | 
			
		||||
            public int Random { get; private set; }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,45 +1,45 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk.Web">
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <VersionPrefix>0.0.0-dev</VersionPrefix>
 | 
			
		||||
    <TargetFramework>netcoreapp3.0</TargetFramework>
 | 
			
		||||
    <PreserveCompilationContext>true</PreserveCompilationContext>
 | 
			
		||||
    <AssemblyName>Ocelot.ManualTest</AssemblyName>
 | 
			
		||||
    <OutputType>Exe</OutputType>
 | 
			
		||||
    <PackageId>Ocelot.ManualTest</PackageId>
 | 
			
		||||
    <RuntimeIdentifiers>osx.10.11-x64;osx.10.12-x64;win7-x64;win10-x64</RuntimeIdentifiers>
 | 
			
		||||
    <CodeAnalysisRuleSet>..\..\codeanalysis.ruleset</CodeAnalysisRuleSet>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <None Update="Views;Areas\**\Views">
 | 
			
		||||
      <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
 | 
			
		||||
    </None>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <None Update="ocelot.json">
 | 
			
		||||
      <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
 | 
			
		||||
    </None>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <None Update="ocelot.json;appsettings.json;idsrv3test.pfx">
 | 
			
		||||
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 | 
			
		||||
    </None>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot\Ocelot.csproj" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Logging" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.66">
 | 
			
		||||
      <PrivateAssets>all</PrivateAssets>
 | 
			
		||||
    </PackageReference>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-19367-01" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk.Web">
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <VersionPrefix>0.0.0-dev</VersionPrefix>
 | 
			
		||||
    <TargetFramework>netcoreapp3.1</TargetFramework>
 | 
			
		||||
    <PreserveCompilationContext>true</PreserveCompilationContext>
 | 
			
		||||
    <AssemblyName>Ocelot.ManualTest</AssemblyName>
 | 
			
		||||
    <OutputType>Exe</OutputType>
 | 
			
		||||
    <PackageId>Ocelot.ManualTest</PackageId>
 | 
			
		||||
    <RuntimeIdentifiers>osx.10.11-x64;osx.10.12-x64;win7-x64;win10-x64</RuntimeIdentifiers>
 | 
			
		||||
    <CodeAnalysisRuleSet>..\..\codeanalysis.ruleset</CodeAnalysisRuleSet>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <None Update="Views;Areas\**\Views">
 | 
			
		||||
      <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
 | 
			
		||||
    </None>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <None Update="ocelot.json">
 | 
			
		||||
      <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
 | 
			
		||||
    </None>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <None Update="ocelot.json;appsettings.json;idsrv3test.pfx">
 | 
			
		||||
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 | 
			
		||||
    </None>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot\Ocelot.csproj" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Logging" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.66">
 | 
			
		||||
      <PrivateAssets>all</PrivateAssets>
 | 
			
		||||
    </PackageReference>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.0.0" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
</Project>
 | 
			
		||||
@@ -41,14 +41,14 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
            _internalConfigCreator = new Mock<IInternalConfigurationCreator>();
 | 
			
		||||
            _internalConfigCreator.Setup(x => x.Create(It.IsAny<FileConfiguration>())).ReturnsAsync(new OkResponse<IInternalConfiguration>(_internalConfig));
 | 
			
		||||
            _poller = new FileConfigurationPoller(_factory.Object, _repo.Object, _config.Object, _internalConfigRepo.Object, _internalConfigCreator.Object);
 | 
			
		||||
            _poller.StartAsync(new CancellationToken());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_start()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => ThenTheSetterIsCalled(_fileConfig, 1))
 | 
			
		||||
                 .BDDfy();
 | 
			
		||||
            this.Given(x => GivenPollerHasStarted())
 | 
			
		||||
                .Given(x => ThenTheSetterIsCalled(_fileConfig, 1))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
@@ -71,7 +71,8 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => WhenTheConfigIsChanged(newConfig, 0))
 | 
			
		||||
            this.Given(x => GivenPollerHasStarted())
 | 
			
		||||
                .Given(x => WhenTheConfigIsChanged(newConfig, 0))
 | 
			
		||||
                .Then(x => ThenTheSetterIsCalledAtLeast(newConfig, 1))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
@@ -96,7 +97,8 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => WhenTheConfigIsChanged(newConfig, 10))
 | 
			
		||||
            this.Given(x => GivenPollerHasStarted())
 | 
			
		||||
                .Given(x => WhenTheConfigIsChanged(newConfig, 10))
 | 
			
		||||
                .Then(x => ThenTheSetterIsCalled(newConfig, 1))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
@@ -121,11 +123,24 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => WhenProviderErrors())
 | 
			
		||||
            this.Given(x => GivenPollerHasStarted())
 | 
			
		||||
                .Given(x => WhenProviderErrors())
 | 
			
		||||
                .Then(x => ThenTheSetterIsCalled(newConfig, 0))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_dispose_cleanly_without_starting()
 | 
			
		||||
        {
 | 
			
		||||
            this.When(x => WhenPollerIsDisposed())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenPollerHasStarted()
 | 
			
		||||
        {
 | 
			
		||||
            _poller.StartAsync(CancellationToken.None);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenProviderErrors()
 | 
			
		||||
        {
 | 
			
		||||
            _repo
 | 
			
		||||
@@ -141,6 +156,11 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                .ReturnsAsync(new OkResponse<FileConfiguration>(newConfig));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenPollerIsDisposed()
 | 
			
		||||
        {
 | 
			
		||||
            _poller.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheSetterIsCalled(FileConfiguration fileConfig, int times)
 | 
			
		||||
        {
 | 
			
		||||
            var result = WaitFor(4000).Until(() =>
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var expectedOptions = new HttpHandlerOptions(false, false, false, true);
 | 
			
		||||
            var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue);
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFollowing(fileReRoute))
 | 
			
		||||
                .When(x => WhenICreateHttpHandlerOptions())
 | 
			
		||||
@@ -60,7 +60,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var expectedOptions = new HttpHandlerOptions(false, false, true, true);
 | 
			
		||||
            var expectedOptions = new HttpHandlerOptions(false, false, true, true, int.MaxValue);
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFollowing(fileReRoute))
 | 
			
		||||
                .And(x => GivenARealTracer())
 | 
			
		||||
@@ -73,7 +73,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
        public void should_create_options_with_useCookie_false_and_allowAutoRedirect_true_as_default()
 | 
			
		||||
        {
 | 
			
		||||
            var fileReRoute = new FileReRoute();
 | 
			
		||||
            var expectedOptions = new HttpHandlerOptions(false, false, false, true);
 | 
			
		||||
            var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue);
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFollowing(fileReRoute))
 | 
			
		||||
                .When(x => WhenICreateHttpHandlerOptions())
 | 
			
		||||
@@ -94,7 +94,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var expectedOptions = new HttpHandlerOptions(false, false, false, true);
 | 
			
		||||
            var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue);
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFollowing(fileReRoute))
 | 
			
		||||
                .When(x => WhenICreateHttpHandlerOptions())
 | 
			
		||||
@@ -110,7 +110,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                HttpHandlerOptions = new FileHttpHandlerOptions()
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var expectedOptions = new HttpHandlerOptions(false, false, false, true);
 | 
			
		||||
            var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue);
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFollowing(fileReRoute))
 | 
			
		||||
                .When(x => WhenICreateHttpHandlerOptions())
 | 
			
		||||
@@ -129,7 +129,64 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var expectedOptions = new HttpHandlerOptions(false, false, false, false);
 | 
			
		||||
            var expectedOptions = new HttpHandlerOptions(false, false, false, false, int.MaxValue);
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFollowing(fileReRoute))
 | 
			
		||||
                .When(x => WhenICreateHttpHandlerOptions())
 | 
			
		||||
                .Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_create_options_with_specified_MaxConnectionsPerServer()
 | 
			
		||||
        {
 | 
			
		||||
            var fileReRoute = new FileReRoute
 | 
			
		||||
            {
 | 
			
		||||
                HttpHandlerOptions = new FileHttpHandlerOptions
 | 
			
		||||
                {
 | 
			
		||||
                    MaxConnectionsPerServer = 10
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var expectedOptions = new HttpHandlerOptions(false, false, false, true, 10);
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFollowing(fileReRoute))
 | 
			
		||||
                .When(x => WhenICreateHttpHandlerOptions())
 | 
			
		||||
                .Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_create_options_fixing_specified_MaxConnectionsPerServer_range()
 | 
			
		||||
        {
 | 
			
		||||
            var fileReRoute = new FileReRoute
 | 
			
		||||
            {
 | 
			
		||||
                HttpHandlerOptions = new FileHttpHandlerOptions
 | 
			
		||||
                {
 | 
			
		||||
                    MaxConnectionsPerServer = -1
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue);
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFollowing(fileReRoute))
 | 
			
		||||
                .When(x => WhenICreateHttpHandlerOptions())
 | 
			
		||||
                .Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_create_options_fixing_specified_MaxConnectionsPerServer_range_when_zero()
 | 
			
		||||
        {
 | 
			
		||||
            var fileReRoute = new FileReRoute
 | 
			
		||||
            {
 | 
			
		||||
                HttpHandlerOptions = new FileHttpHandlerOptions
 | 
			
		||||
                {
 | 
			
		||||
                    MaxConnectionsPerServer = 0
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue);
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFollowing(fileReRoute))
 | 
			
		||||
                .When(x => WhenICreateHttpHandlerOptions())
 | 
			
		||||
@@ -154,6 +211,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
            _httpHandlerOptions.UseCookieContainer.ShouldBe(expected.UseCookieContainer);
 | 
			
		||||
            _httpHandlerOptions.UseTracing.ShouldBe(expected.UseTracing);
 | 
			
		||||
            _httpHandlerOptions.UseProxy.ShouldBe(expected.UseProxy);
 | 
			
		||||
            _httpHandlerOptions.MaxConnectionsPerServer.ShouldBe(expected.MaxConnectionsPerServer);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenARealTracer()
 | 
			
		||||
 
 | 
			
		||||
@@ -50,7 +50,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
            };
 | 
			
		||||
            var expected = new RateLimitOptionsBuilder()
 | 
			
		||||
                .WithClientIdHeader("ClientIdHeader")
 | 
			
		||||
                .WithClientWhiteList(fileReRoute.RateLimitOptions.ClientWhitelist)
 | 
			
		||||
                .WithClientWhiteList(() => fileReRoute.RateLimitOptions.ClientWhitelist)
 | 
			
		||||
                .WithDisableRateLimitHeaders(true)
 | 
			
		||||
                .WithEnableRateLimiting(true)
 | 
			
		||||
                .WithHttpStatusCode(200)
 | 
			
		||||
 
 | 
			
		||||
@@ -1341,6 +1341,32 @@
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void configuration_is_invalid_when_placeholder_is_used_twice_in_upstream_path_template()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenAConfiguration(new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                {
 | 
			
		||||
                    new FileReRoute
 | 
			
		||||
                    {
 | 
			
		||||
                        DownstreamPathTemplate = "/bar/{everything}",
 | 
			
		||||
                        DownstreamScheme = "http",
 | 
			
		||||
                        DownstreamHostAndPorts = new List<FileHostAndPort> 
 | 
			
		||||
                        { 
 | 
			
		||||
                            new FileHostAndPort() { Host = "a.b.cd" },
 | 
			
		||||
                        },
 | 
			
		||||
                        UpstreamPathTemplate = "/foo/bar/{everything}/{everything}",
 | 
			
		||||
                        UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
            }))
 | 
			
		||||
                .When(x => x.WhenIValidateTheConfiguration())
 | 
			
		||||
                .Then(x => x.ThenTheResultIsNotValid())
 | 
			
		||||
                .And(x => x.ThenTheErrorMessageAtPositionIs(0, "reRoute /foo/bar/{everything}/{everything} has duplicated placeholder"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenAConfiguration(FileConfiguration fileConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            _fileConfiguration = fileConfiguration;
 | 
			
		||||
 
 | 
			
		||||
@@ -350,6 +350,36 @@
 | 
			
		||||
                .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);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,5 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Linq.Expressions;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
@@ -108,6 +110,26 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_set_scheme()
 | 
			
		||||
        {
 | 
			
		||||
            var downstreamRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var serviceProviderConfig = new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123"))
 | 
			
		||||
                .And(x => GivenTheConfigurationIs(serviceProviderConfig))
 | 
			
		||||
                .And(x => x.GivenTheDownStreamRouteIs(downstreamRoute, new List<Ocelot.DownstreamRouteFinder.UrlMatcher.PlaceholderNameAndValue>()))
 | 
			
		||||
                .And(x => x.GivenTheLoadBalancerHouseReturns())
 | 
			
		||||
                .And(x => x.GivenTheLoadBalancerReturnsOk())
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenAnHostAndPortIsSetOnPipeline())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware = new LoadBalancingMiddleware(_next, _loggerFactory.Object, _loadBalancerHouse.Object);
 | 
			
		||||
@@ -135,6 +157,13 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
               .ReturnsAsync(_getHostAndPortError);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheLoadBalancerReturnsOk()
 | 
			
		||||
        {
 | 
			
		||||
            _loadBalancer
 | 
			
		||||
                .Setup(x => x.Lease(It.IsAny<DownstreamContext>()))
 | 
			
		||||
                .ReturnsAsync(new OkResponse<ServiceHostAndPort>(new ServiceHostAndPort("abc", 123, "https")));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheLoadBalancerReturns()
 | 
			
		||||
        {
 | 
			
		||||
            _hostAndPort = new ServiceHostAndPort("127.0.0.1", 80);
 | 
			
		||||
@@ -186,6 +215,13 @@ namespace Ocelot.UnitTests.LoadBalancer
 | 
			
		||||
            _downstreamContext.Errors.ShouldBe(_getHostAndPortError.Errors);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenAnHostAndPortIsSetOnPipeline()
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.DownstreamRequest.Host.ShouldBeEquivalentTo("abc");
 | 
			
		||||
            _downstreamContext.DownstreamRequest.Port.ShouldBeEquivalentTo(123);
 | 
			
		||||
            _downstreamContext.DownstreamRequest.Scheme.ShouldBeEquivalentTo("https");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheDownstreamUrlIsReplacedWith(string expectedUri)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.DownstreamRequest.ToHttpRequestMessage().RequestUri.OriginalString.ShouldBe(expectedUri);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,97 +1,97 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <VersionPrefix>0.0.0-dev</VersionPrefix>
 | 
			
		||||
    <TargetFramework>netcoreapp3.0</TargetFramework>
 | 
			
		||||
    <AssemblyName>Ocelot.UnitTests</AssemblyName>
 | 
			
		||||
    <PackageId>Ocelot.UnitTests</PackageId>
 | 
			
		||||
    <OutputType>Exe</OutputType>
 | 
			
		||||
    <GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
 | 
			
		||||
    <RuntimeIdentifiers>osx.10.11-x64;osx.10.12-x64;win7-x64;win10-x64</RuntimeIdentifiers>
 | 
			
		||||
    <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
 | 
			
		||||
    <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
 | 
			
		||||
    <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
 | 
			
		||||
    <CodeAnalysisRuleSet>..\..\codeanalysis.ruleset</CodeAnalysisRuleSet>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
 | 
			
		||||
    <DebugType>full</DebugType>
 | 
			
		||||
    <DebugSymbols>True</DebugSymbols>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Compile Remove="Kubernetes\KubeProviderFactoryTests.cs" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Provider.Kubernetes\Ocelot.Provider.Kubernetes.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot\Ocelot.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Administration\Ocelot.Administration.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Cache.CacheManager\Ocelot.Cache.CacheManager.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Provider.Consul\Ocelot.Provider.Consul.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Provider.Eureka\Ocelot.Provider.Eureka.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Provider.Polly\Ocelot.Provider.Polly.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Provider.Rafty\Ocelot.Provider.Rafty.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Tracing.Butterfly\Ocelot.Tracing.Butterfly.csproj" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <None Update="appsettings.json">
 | 
			
		||||
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 | 
			
		||||
    </None>
 | 
			
		||||
    <None Update="idsrv3test.pfx">
 | 
			
		||||
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 | 
			
		||||
    </None>
 | 
			
		||||
  </ItemGroup>  
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
 | 
			
		||||
    <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.66">
 | 
			
		||||
      <PrivateAssets>all</PrivateAssets>
 | 
			
		||||
    </PackageReference>
 | 
			
		||||
    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
 | 
			
		||||
      <PrivateAssets>all</PrivateAssets>
 | 
			
		||||
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
 | 
			
		||||
    </PackageReference>
 | 
			
		||||
    <PackageReference Include="Microsoft.DotNet.InternalAbstractions" Version="1.0.500-preview2-1-003177" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Logging" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Moq" Version="4.13.0" />
 | 
			
		||||
    <PackageReference Include="Shouldly" Version="4.0.0-beta0002" />
 | 
			
		||||
    <PackageReference Include="TestStack.BDDfy" Version="4.3.2" />
 | 
			
		||||
    <PackageReference Include="xunit" Version="2.4.1" />
 | 
			
		||||
    <PackageReference Include="Butterfly.Client.AspNetCore" Version="0.0.8" />
 | 
			
		||||
    <PackageReference Include="IdentityServer4.AccessTokenValidation" Version="3.0.1" />
 | 
			
		||||
    <PackageReference Include="IdentityServer4" Version="3.0.1" />
 | 
			
		||||
    <PackageReference Include="Pivotal.Discovery.ClientCore" Version="2.2.0" />
 | 
			
		||||
    <PackageReference Include="Consul" Version="0.7.2.6" />
 | 
			
		||||
    <PackageReference Include="CacheManager.Core" Version="2.0.0-beta-1629" />
 | 
			
		||||
    <PackageReference Include="CacheManager.Microsoft.Extensions.Configuration" Version="2.0.0-beta-1629" />
 | 
			
		||||
    <PackageReference Include="CacheManager.Microsoft.Extensions.Logging" Version="2.0.0-beta-1629" />
 | 
			
		||||
    <PackageReference Include="Polly" Version="7.1.1" />
 | 
			
		||||
    <PackageReference Include="Rafty" Version="0.4.4" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Folder Include="WebSockets\" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-19367-01" />
 | 
			
		||||
    <PackageReference Include="coverlet.collector" Version="1.1.0">
 | 
			
		||||
      <PrivateAssets>all</PrivateAssets>
 | 
			
		||||
      <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
 | 
			
		||||
    </PackageReference>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk">
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <VersionPrefix>0.0.0-dev</VersionPrefix>
 | 
			
		||||
    <TargetFramework>netcoreapp3.1</TargetFramework>
 | 
			
		||||
    <AssemblyName>Ocelot.UnitTests</AssemblyName>
 | 
			
		||||
    <PackageId>Ocelot.UnitTests</PackageId>
 | 
			
		||||
    <OutputType>Exe</OutputType>
 | 
			
		||||
    <GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
 | 
			
		||||
    <RuntimeIdentifiers>osx.10.11-x64;osx.10.12-x64;win7-x64;win10-x64</RuntimeIdentifiers>
 | 
			
		||||
    <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
 | 
			
		||||
    <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
 | 
			
		||||
    <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
 | 
			
		||||
    <CodeAnalysisRuleSet>..\..\codeanalysis.ruleset</CodeAnalysisRuleSet>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
 | 
			
		||||
    <DebugType>full</DebugType>
 | 
			
		||||
    <DebugSymbols>True</DebugSymbols>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Compile Remove="Kubernetes\KubeProviderFactoryTests.cs" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Provider.Kubernetes\Ocelot.Provider.Kubernetes.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot\Ocelot.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Administration\Ocelot.Administration.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Cache.CacheManager\Ocelot.Cache.CacheManager.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Provider.Consul\Ocelot.Provider.Consul.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Provider.Eureka\Ocelot.Provider.Eureka.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Provider.Polly\Ocelot.Provider.Polly.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Provider.Rafty\Ocelot.Provider.Rafty.csproj" />
 | 
			
		||||
    <ProjectReference Include="..\..\src\Ocelot.Tracing.Butterfly\Ocelot.Tracing.Butterfly.csproj" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <None Update="appsettings.json">
 | 
			
		||||
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 | 
			
		||||
    </None>
 | 
			
		||||
    <None Update="idsrv3test.pfx">
 | 
			
		||||
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 | 
			
		||||
    </None>
 | 
			
		||||
  </ItemGroup>  
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
 | 
			
		||||
    <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.66">
 | 
			
		||||
      <PrivateAssets>all</PrivateAssets>
 | 
			
		||||
    </PackageReference>
 | 
			
		||||
    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
 | 
			
		||||
      <PrivateAssets>all</PrivateAssets>
 | 
			
		||||
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
 | 
			
		||||
    </PackageReference>
 | 
			
		||||
    <PackageReference Include="Microsoft.DotNet.InternalAbstractions" Version="1.0.500-preview2-1-003177" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Logging" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="3.0.0" />
 | 
			
		||||
    <PackageReference Include="Moq" Version="4.13.0" />
 | 
			
		||||
    <PackageReference Include="Shouldly" Version="4.0.0-beta0002" />
 | 
			
		||||
    <PackageReference Include="TestStack.BDDfy" Version="4.3.2" />
 | 
			
		||||
    <PackageReference Include="xunit" Version="2.4.1" />
 | 
			
		||||
    <PackageReference Include="Butterfly.Client.AspNetCore" Version="0.0.8" />
 | 
			
		||||
    <PackageReference Include="IdentityServer4.AccessTokenValidation" Version="3.0.1" />
 | 
			
		||||
    <PackageReference Include="IdentityServer4" Version="3.0.1" />
 | 
			
		||||
    <PackageReference Include="Pivotal.Discovery.ClientCore" Version="2.2.0" />
 | 
			
		||||
    <PackageReference Include="Consul" Version="0.7.2.6" />
 | 
			
		||||
    <PackageReference Include="CacheManager.Core" Version="2.0.0-beta-1629" />
 | 
			
		||||
    <PackageReference Include="CacheManager.Microsoft.Extensions.Configuration" Version="2.0.0-beta-1629" />
 | 
			
		||||
    <PackageReference Include="CacheManager.Microsoft.Extensions.Logging" Version="2.0.0-beta-1629" />
 | 
			
		||||
    <PackageReference Include="Polly" Version="7.1.1" />
 | 
			
		||||
    <PackageReference Include="Rafty" Version="0.4.4" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Folder Include="WebSockets\" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.0.0" />
 | 
			
		||||
    <PackageReference Include="coverlet.collector" Version="1.1.0">
 | 
			
		||||
      <PrivateAssets>all</PrivateAssets>
 | 
			
		||||
      <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
 | 
			
		||||
    </PackageReference>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
</Project>
 | 
			
		||||
@@ -49,15 +49,15 @@ namespace Ocelot.UnitTests.RateLimit
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_middleware_and_ratelimiting()
 | 
			
		||||
        {
 | 
			
		||||
            var upstreamTemplate = new UpstreamPathTemplateBuilder().Build();
 | 
			
		||||
        {
 | 
			
		||||
            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))
 | 
			
		||||
                .WithRateLimitOptions(new RateLimitOptions(true, "ClientId", () => new List<string>(), false, "", "", new RateLimitRule("1s", 100, 3), 429))
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                .WithUpstreamPathTemplate(upstreamTemplate)
 | 
			
		||||
                .Build();
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            var reRoute = new ReRouteBuilder()
 | 
			
		||||
                .WithDownstreamReRoute(downstreamReRoute)
 | 
			
		||||
@@ -82,7 +82,7 @@ namespace Ocelot.UnitTests.RateLimit
 | 
			
		||||
                     .WithDownstreamReRoute(new DownstreamReRouteBuilder()
 | 
			
		||||
                         .WithEnableRateLimiting(true)
 | 
			
		||||
                         .WithRateLimitOptions(
 | 
			
		||||
                             new Ocelot.Configuration.RateLimitOptions(true, "ClientId", new List<string>() { "ocelotclient2" }, false, "", "", new RateLimitRule("1s", 100, 3), 429))
 | 
			
		||||
                             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" })
 | 
			
		||||
@@ -102,8 +102,8 @@ namespace Ocelot.UnitTests.RateLimit
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddlewareMultipleTime(int times)
 | 
			
		||||
        {
 | 
			
		||||
            var clientId = "ocelotclient1";
 | 
			
		||||
 | 
			
		||||
            var clientId = "ocelotclient1";
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < times; i++)
 | 
			
		||||
            {
 | 
			
		||||
                var request = new HttpRequestMessage(new HttpMethod("GET"), _url);
 | 
			
		||||
@@ -117,8 +117,8 @@ namespace Ocelot.UnitTests.RateLimit
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddlewareWithWhiteClient()
 | 
			
		||||
        {
 | 
			
		||||
            var clientId = "ocelotclient2";
 | 
			
		||||
 | 
			
		||||
            var clientId = "ocelotclient2";
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < 10; i++)
 | 
			
		||||
            {
 | 
			
		||||
                var request = new HttpRequestMessage(new HttpMethod("GET"), _url);
 | 
			
		||||
@@ -127,10 +127,10 @@ namespace Ocelot.UnitTests.RateLimit
 | 
			
		||||
                _downstreamContext.HttpContext.Request.Headers.TryAdd("ClientId", clientId);
 | 
			
		||||
 | 
			
		||||
                _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
 | 
			
		||||
                _responseStatusCode = (int)_downstreamContext.HttpContext.Response.StatusCode;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
                _responseStatusCode = (int)_downstreamContext.HttpContext.Response.StatusCode;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenresponseStatusCodeIs429()
 | 
			
		||||
        {
 | 
			
		||||
            _responseStatusCode.ShouldBe(429);
 | 
			
		||||
@@ -145,7 +145,7 @@ namespace Ocelot.UnitTests.RateLimit
 | 
			
		||||
    internal class FakeStream : Stream
 | 
			
		||||
    {
 | 
			
		||||
        public override void Flush()
 | 
			
		||||
        {
 | 
			
		||||
        {
 | 
			
		||||
            //do nothing
 | 
			
		||||
            //throw new System.NotImplementedException();
 | 
			
		||||
        }
 | 
			
		||||
@@ -176,4 +176,4 @@ namespace Ocelot.UnitTests.RateLimit
 | 
			
		||||
        public override long Length { get; }
 | 
			
		||||
        public override long Position { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -52,7 +52,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true))
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true, int.MaxValue))
 | 
			
		||||
                .WithDelegatingHandlers(new List<string>
 | 
			
		||||
                {
 | 
			
		||||
                    "FakeDelegatingHandler",
 | 
			
		||||
@@ -88,7 +88,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true))
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true, int.MaxValue))
 | 
			
		||||
                .WithDelegatingHandlers(new List<string>
 | 
			
		||||
                {
 | 
			
		||||
                    "FakeDelegatingHandlerTwo",
 | 
			
		||||
@@ -125,7 +125,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true))
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true, int.MaxValue))
 | 
			
		||||
                .WithDelegatingHandlers(new List<string>
 | 
			
		||||
                {
 | 
			
		||||
                    "FakeDelegatingHandlerTwo",
 | 
			
		||||
@@ -161,7 +161,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true))
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true, int.MaxValue))
 | 
			
		||||
                .WithDelegatingHandlers(new List<string>
 | 
			
		||||
                {
 | 
			
		||||
                    "FakeDelegatingHandler",
 | 
			
		||||
@@ -195,7 +195,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true))
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
@@ -221,7 +221,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true))
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true, int.MaxValue))
 | 
			
		||||
                .WithDelegatingHandlers(new List<string>
 | 
			
		||||
                {
 | 
			
		||||
                    "FakeDelegatingHandler",
 | 
			
		||||
@@ -249,7 +249,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true)).WithLoadBalancerKey("").Build();
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true, int.MaxValue)).WithLoadBalancerKey("").Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFollowingRequest(reRoute))
 | 
			
		||||
                .And(x => GivenTheQosFactoryReturns(new FakeQoSHandler()))
 | 
			
		||||
@@ -269,7 +269,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true)).WithLoadBalancerKey("").Build();
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true, int.MaxValue)).WithLoadBalancerKey("").Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFollowingRequest(reRoute))
 | 
			
		||||
                .And(x => GivenTheServiceProviderReturnsNothing())
 | 
			
		||||
@@ -289,7 +289,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true)).WithLoadBalancerKey("").Build();
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true, int.MaxValue)).WithLoadBalancerKey("").Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFollowingRequest(reRoute))
 | 
			
		||||
                .And(x => GivenTheQosFactoryReturns(new FakeQoSHandler()))
 | 
			
		||||
@@ -309,7 +309,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true)).WithLoadBalancerKey("").Build();
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true, int.MaxValue)).WithLoadBalancerKey("").Build();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFollowingRequest(reRoute))
 | 
			
		||||
                .And(x => GivenTheQosFactoryReturns(new FakeQoSHandler()))
 | 
			
		||||
@@ -331,7 +331,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true))
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
@@ -361,7 +361,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true))
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -52,7 +52,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true))
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
@@ -73,7 +73,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true))
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
@@ -99,7 +99,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true))
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
@@ -126,7 +126,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
 | 
			
		||||
            var reRouteA = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true))
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithContainsQueryString(true).WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
@@ -134,7 +134,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
 | 
			
		||||
            var reRouteB = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true))
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithContainsQueryString(true).WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
@@ -161,7 +161,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true))
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
@@ -184,7 +184,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true))
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
@@ -216,7 +216,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, true, false, true))
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, true, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
@@ -252,7 +252,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true))
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("").Build())
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
 
 | 
			
		||||
@@ -57,7 +57,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true))
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(upstreamTemplate)
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
@@ -86,7 +86,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true))
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(upstreamTemplate)
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().Build())
 | 
			
		||||
@@ -114,7 +114,7 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true))
 | 
			
		||||
                .WithHttpHandlerOptions(new HttpHandlerOptions(false, false, false, true, int.MaxValue))
 | 
			
		||||
                .WithLoadBalancerKey("")
 | 
			
		||||
                .WithUpstreamPathTemplate(upstreamTemplate)
 | 
			
		||||
                .WithQosOptions(new QoSOptionsBuilder().WithTimeoutValue(1).Build())
 | 
			
		||||
 
 | 
			
		||||
@@ -38,6 +38,14 @@
 | 
			
		||||
            error.ShouldBeOfType<RequestCanceledError>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_request_canceled_for_subtype()
 | 
			
		||||
        {
 | 
			
		||||
            var error = _mapper.Map(new SomeException());
 | 
			
		||||
 | 
			
		||||
            error.ShouldBeOfType<RequestCanceledError>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_error_from_mapper()
 | 
			
		||||
        {
 | 
			
		||||
@@ -56,5 +64,8 @@
 | 
			
		||||
 | 
			
		||||
            error.ShouldBeOfType<AnyError>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private class SomeException : OperationCanceledException
 | 
			
		||||
        { }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -41,9 +41,10 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
        public void should_call_services_correctly()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenTheRequestIs())
 | 
			
		||||
                .And(x => x.GivenTheRequesterReturns(new OkResponse<HttpResponseMessage>(new HttpResponseMessage())))
 | 
			
		||||
                .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();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -57,6 +58,17 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
                .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();
 | 
			
		||||
@@ -98,5 +110,23 @@ namespace Ocelot.UnitTests.Requester
 | 
			
		||||
            _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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user