mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 10:15:27 +08:00 
			
		
		
		
	Feature/transform headers (#204)
* New feature that lets a user do find and replace on an upstream header * can transform downstream and upstream headers, not sure if interface is good * can replace location header with placeholder * added some syntax
This commit is contained in:
		@@ -39,6 +39,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
        private Mock<IRegionCreator> _regionCreator;
 | 
			
		||||
        private Mock<IHttpHandlerOptionsCreator> _httpHandlerOptionsCreator;
 | 
			
		||||
        private Mock<IAdministrationPath> _adminPath;
 | 
			
		||||
        private readonly Mock<IHeaderFindAndReplaceCreator> _headerFindAndReplaceCreator;
 | 
			
		||||
 | 
			
		||||
        public FileConfigurationCreatorTests()
 | 
			
		||||
        {
 | 
			
		||||
@@ -56,6 +57,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
            _regionCreator = new Mock<IRegionCreator>();
 | 
			
		||||
            _httpHandlerOptionsCreator = new Mock<IHttpHandlerOptionsCreator>();
 | 
			
		||||
            _adminPath = new Mock<IAdministrationPath>();
 | 
			
		||||
            _headerFindAndReplaceCreator = new Mock<IHeaderFindAndReplaceCreator>();
 | 
			
		||||
 | 
			
		||||
            _ocelotConfigurationCreator = new FileOcelotConfigurationCreator( 
 | 
			
		||||
                _fileConfig.Object,
 | 
			
		||||
@@ -71,7 +73,8 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                _rateLimitOptions.Object,
 | 
			
		||||
                _regionCreator.Object,
 | 
			
		||||
                _httpHandlerOptionsCreator.Object,
 | 
			
		||||
                _adminPath.Object);
 | 
			
		||||
                _adminPath.Object,
 | 
			
		||||
                _headerFindAndReplaceCreator.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
@@ -91,6 +94,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                }
 | 
			
		||||
            }))
 | 
			
		||||
                .And(x => x.GivenTheFollowingIsReturned(serviceProviderConfig))
 | 
			
		||||
                .And(x => GivenTheHeaderFindAndReplaceCreatorReturns())
 | 
			
		||||
                .And(x => x.GivenTheConfigIsValid())
 | 
			
		||||
                .When(x => x.WhenICreateTheConfig())
 | 
			
		||||
                .Then(x => x.ThenTheServiceProviderCreatorIsCalledCorrectly())
 | 
			
		||||
@@ -121,10 +125,12 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                            },
 | 
			
		||||
            }))
 | 
			
		||||
                .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
 | 
			
		||||
                .And(x => GivenTheHeaderFindAndReplaceCreatorReturns())
 | 
			
		||||
                .And(x => x.GivenTheConfigIsValid())
 | 
			
		||||
                .And(x => x.GivenTheFollowingRegionIsReturned("region"))
 | 
			
		||||
                .When(x => x.WhenICreateTheConfig())
 | 
			
		||||
                .Then(x => x.ThenTheRegionCreatorIsCalledCorrectly("region"))
 | 
			
		||||
                .And(x => x.ThenTheHeaderFindAndReplaceCreatorIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -148,6 +154,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                            },
 | 
			
		||||
            }))
 | 
			
		||||
                .And(x => x.GivenTheConfigIsValid())
 | 
			
		||||
                .And(x => GivenTheHeaderFindAndReplaceCreatorReturns())
 | 
			
		||||
                .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
 | 
			
		||||
                .When(x => x.WhenICreateTheConfig())
 | 
			
		||||
                .Then(x => x.ThenTheRateLimitOptionsCreatorIsCalledCorrectly())
 | 
			
		||||
@@ -187,6 +194,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                },
 | 
			
		||||
            }))
 | 
			
		||||
                .And(x => x.GivenTheConfigIsValid())
 | 
			
		||||
                .And(x => GivenTheHeaderFindAndReplaceCreatorReturns())
 | 
			
		||||
                .And(x => x.GivenTheFollowingOptionsAreReturned(serviceOptions))
 | 
			
		||||
                .And(x => x.GivenTheQosOptionsCreatorReturns(expected))
 | 
			
		||||
                .When(x => x.WhenICreateTheConfig())
 | 
			
		||||
@@ -214,6 +222,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                            },
 | 
			
		||||
                        }))
 | 
			
		||||
                            .And(x => x.GivenTheConfigIsValid())
 | 
			
		||||
                            .And(x => GivenTheHeaderFindAndReplaceCreatorReturns())
 | 
			
		||||
                            .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
 | 
			
		||||
                            .When(x => x.WhenICreateTheConfig())
 | 
			
		||||
                            .Then(x => x.ThenTheReRoutesAre(new List<ReRoute>
 | 
			
		||||
@@ -248,6 +257,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                                            },
 | 
			
		||||
                                        }))
 | 
			
		||||
                                            .And(x => x.GivenTheConfigIsValid())
 | 
			
		||||
                                            .And(x => GivenTheHeaderFindAndReplaceCreatorReturns())
 | 
			
		||||
                                            .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
 | 
			
		||||
                                            .When(x => x.WhenICreateTheConfig())
 | 
			
		||||
                                            .Then(x => x.ThenTheReRoutesAre(new List<ReRoute>
 | 
			
		||||
@@ -290,6 +300,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                            }
 | 
			
		||||
                        }))
 | 
			
		||||
                            .And(x => x.GivenTheConfigIsValid())
 | 
			
		||||
                            .And(x => GivenTheHeaderFindAndReplaceCreatorReturns())
 | 
			
		||||
                            .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
 | 
			
		||||
                            .When(x => x.WhenICreateTheConfig())
 | 
			
		||||
                            .Then(x => x.ThenTheReRoutesAre(new List<ReRoute>
 | 
			
		||||
@@ -325,6 +336,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                            }
 | 
			
		||||
                        }))
 | 
			
		||||
                            .And(x => x.GivenTheConfigIsValid())
 | 
			
		||||
                            .And(x => GivenTheHeaderFindAndReplaceCreatorReturns())
 | 
			
		||||
                            .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
 | 
			
		||||
                            .When(x => x.WhenICreateTheConfig())
 | 
			
		||||
                            .Then(x => x.ThenTheReRoutesAre(new List<ReRoute>
 | 
			
		||||
@@ -359,6 +371,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                }
 | 
			
		||||
            }))
 | 
			
		||||
                .And(x => x.GivenTheConfigIsValid())
 | 
			
		||||
                .And(x => GivenTheHeaderFindAndReplaceCreatorReturns())
 | 
			
		||||
                .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
 | 
			
		||||
                .And(x => x.GivenTheUpstreamTemplatePatternCreatorReturns("(?i)/api/products/.*/$"))
 | 
			
		||||
                .When(x => x.WhenICreateTheConfig())
 | 
			
		||||
@@ -398,6 +411,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                }
 | 
			
		||||
            }))
 | 
			
		||||
                .And(x => x.GivenTheConfigIsValid())    
 | 
			
		||||
                .And(x => GivenTheHeaderFindAndReplaceCreatorReturns())
 | 
			
		||||
                .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
 | 
			
		||||
                .And(x => x.GivenTheRequestIdCreatorReturns("blahhhh"))
 | 
			
		||||
                .When(x => x.WhenICreateTheConfig())
 | 
			
		||||
@@ -435,6 +449,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                            },
 | 
			
		||||
            }))
 | 
			
		||||
                .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
 | 
			
		||||
                .And(x => GivenTheHeaderFindAndReplaceCreatorReturns())
 | 
			
		||||
                .And(x => x.GivenTheConfigIsValid())
 | 
			
		||||
                .And(x => x.GivenTheFollowingHttpHandlerOptionsAreReturned(httpHandlerOptions))
 | 
			
		||||
                .When(x => x.WhenICreateTheConfig())
 | 
			
		||||
@@ -470,6 +485,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheConfigIs(fileConfig))
 | 
			
		||||
                .And(x => x.GivenTheConfigIsValid())
 | 
			
		||||
                .And(x => GivenTheHeaderFindAndReplaceCreatorReturns())
 | 
			
		||||
                .And(x => x.GivenTheAuthOptionsCreatorReturns(authenticationOptions))
 | 
			
		||||
                .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
 | 
			
		||||
                .And(x => x.GivenTheClaimsToThingCreatorReturns(new List<ClaimToThing> { new ClaimToThing("CustomerId", "CustomerId", "", 0) }))
 | 
			
		||||
@@ -504,6 +520,7 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenTheConfigIs(fileConfig))
 | 
			
		||||
                .And(x => x.GivenTheConfigIsValid())
 | 
			
		||||
                .And(x => GivenTheHeaderFindAndReplaceCreatorReturns())
 | 
			
		||||
                .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
 | 
			
		||||
                .And(x => x.GivenTheAuthOptionsCreatorReturns(authenticationOptions))
 | 
			
		||||
                .When(x => x.WhenICreateTheConfig())
 | 
			
		||||
@@ -661,6 +678,17 @@ namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
                .Verify(x => x.Create(_fileConfiguration.GlobalConfiguration), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheHeaderFindAndReplaceCreatorIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _headerFindAndReplaceCreator
 | 
			
		||||
                .Verify(x => x.Create(It.IsAny<FileReRoute>()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheHeaderFindAndReplaceCreatorReturns()
 | 
			
		||||
        {
 | 
			
		||||
            _headerFindAndReplaceCreator.Setup(x => x.Create(It.IsAny<FileReRoute>())).Returns(new HeaderTransformations(new List<HeaderFindAndReplace>(), new List<HeaderFindAndReplace>()));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFollowingIsReturned(ServiceProviderConfiguration serviceProviderConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceProviderConfigCreator
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,158 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Configuration.Builder;
 | 
			
		||||
using Ocelot.Configuration.Creator;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Configuration
 | 
			
		||||
{
 | 
			
		||||
    public class HeaderFindAndReplaceCreatorTests
 | 
			
		||||
    {
 | 
			
		||||
        private HeaderFindAndReplaceCreator _creator;
 | 
			
		||||
        private FileReRoute _reRoute;
 | 
			
		||||
        private HeaderTransformations _result;
 | 
			
		||||
        private Mock<IBaseUrlFinder> _finder;
 | 
			
		||||
 | 
			
		||||
        public HeaderFindAndReplaceCreatorTests()
 | 
			
		||||
        {
 | 
			
		||||
            _finder = new Mock<IBaseUrlFinder>();
 | 
			
		||||
            _creator = new HeaderFindAndReplaceCreator(_finder.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_create()
 | 
			
		||||
        {
 | 
			
		||||
            var reRoute = new FileReRoute
 | 
			
		||||
            {
 | 
			
		||||
                UpstreamHeaderTransform = new Dictionary<string, string>
 | 
			
		||||
                {
 | 
			
		||||
                    {"Test", "Test, Chicken"},
 | 
			
		||||
 | 
			
		||||
                    {"Moop", "o, a"}
 | 
			
		||||
                },
 | 
			
		||||
                 DownstreamHeaderTransform = new Dictionary<string, string>
 | 
			
		||||
                {
 | 
			
		||||
                    {"Pop", "West, East"},
 | 
			
		||||
 | 
			
		||||
                    {"Bop", "e, r"}
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var upstream = new List<HeaderFindAndReplace>
 | 
			
		||||
            {
 | 
			
		||||
                new HeaderFindAndReplace("Test", "Test", "Chicken", 0),
 | 
			
		||||
                new HeaderFindAndReplace("Moop", "o", "a", 0)
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var downstream = new List<HeaderFindAndReplace>
 | 
			
		||||
            {
 | 
			
		||||
                new HeaderFindAndReplace("Pop", "West", "East", 0),
 | 
			
		||||
                new HeaderFindAndReplace("Bop", "e", "r", 0)
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheReRoute(reRoute))
 | 
			
		||||
                .When(x => WhenICreate())
 | 
			
		||||
                .Then(x => ThenTheFollowingUpstreamIsReturned(upstream))
 | 
			
		||||
                .Then(x => ThenTheFollowingDownstreamIsReturned(downstream))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_use_base_url_placeholder()
 | 
			
		||||
        {
 | 
			
		||||
            var reRoute = new FileReRoute
 | 
			
		||||
            {
 | 
			
		||||
                 DownstreamHeaderTransform = new Dictionary<string, string>
 | 
			
		||||
                {
 | 
			
		||||
                    {"Location", "http://www.bbc.co.uk/, {BaseUrl}"},
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var downstream = new List<HeaderFindAndReplace>
 | 
			
		||||
            {
 | 
			
		||||
                new HeaderFindAndReplace("Location", "http://www.bbc.co.uk/", "http://ocelot.com/", 0),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheReRoute(reRoute))
 | 
			
		||||
                .And(x => GivenTheBaseUrlIs("http://ocelot.com/"))
 | 
			
		||||
                .When(x => WhenICreate())
 | 
			
		||||
                .Then(x => ThenTheFollowingDownstreamIsReturned(downstream))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_use_base_url_partial_placeholder()
 | 
			
		||||
        {
 | 
			
		||||
            var reRoute = new FileReRoute
 | 
			
		||||
            {
 | 
			
		||||
                 DownstreamHeaderTransform = new Dictionary<string, string>
 | 
			
		||||
                {
 | 
			
		||||
                    {"Location", "http://www.bbc.co.uk/pay, {BaseUrl}pay"},
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var downstream = new List<HeaderFindAndReplace>
 | 
			
		||||
            {
 | 
			
		||||
                new HeaderFindAndReplace("Location", "http://www.bbc.co.uk/pay", "http://ocelot.com/pay", 0),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheReRoute(reRoute))
 | 
			
		||||
                .And(x => GivenTheBaseUrlIs("http://ocelot.com/"))
 | 
			
		||||
                .When(x => WhenICreate())
 | 
			
		||||
                .Then(x => ThenTheFollowingDownstreamIsReturned(downstream))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheBaseUrlIs(string baseUrl)
 | 
			
		||||
        {
 | 
			
		||||
            _finder.Setup(x => x.Find()).Returns(baseUrl);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheFollowingDownstreamIsReturned(List<HeaderFindAndReplace> downstream)
 | 
			
		||||
        {
 | 
			
		||||
            _result.Downstream.Count.ShouldBe(downstream.Count);
 | 
			
		||||
            
 | 
			
		||||
            for (int i = 0; i < _result.Downstream.Count; i++)
 | 
			
		||||
            {
 | 
			
		||||
                var result = _result.Downstream[i];
 | 
			
		||||
                var expected = downstream[i];
 | 
			
		||||
                result.Find.ShouldBe(expected.Find);
 | 
			
		||||
                result.Index.ShouldBe(expected.Index);
 | 
			
		||||
                result.Key.ShouldBe(expected.Key);
 | 
			
		||||
                result.Replace.ShouldBe(expected.Replace);
 | 
			
		||||
            }        
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheReRoute(FileReRoute reRoute)
 | 
			
		||||
        {
 | 
			
		||||
            _reRoute = reRoute;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICreate()
 | 
			
		||||
        {
 | 
			
		||||
            _result = _creator.Create(_reRoute);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheFollowingUpstreamIsReturned(List<HeaderFindAndReplace> expecteds)
 | 
			
		||||
        {
 | 
			
		||||
            _result.Upstream.Count.ShouldBe(expecteds.Count);
 | 
			
		||||
            
 | 
			
		||||
            for (int i = 0; i < _result.Upstream.Count; i++)
 | 
			
		||||
            {
 | 
			
		||||
                var result = _result.Upstream[i];
 | 
			
		||||
                var expected = expecteds[i];
 | 
			
		||||
                result.Find.ShouldBe(expected.Find);
 | 
			
		||||
                result.Index.ShouldBe(expected.Index);
 | 
			
		||||
                result.Key.ShouldBe(expected.Key);
 | 
			
		||||
                result.Replace.ShouldBe(expected.Replace);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,91 @@
 | 
			
		||||
using Xunit;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Ocelot.Headers.Middleware;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Headers;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Headers
 | 
			
		||||
{
 | 
			
		||||
    public class HttpContextRequestHeaderReplacerTests
 | 
			
		||||
    {
 | 
			
		||||
        private HttpContext _context;
 | 
			
		||||
        private List<HeaderFindAndReplace> _fAndRs;
 | 
			
		||||
        private HttpContextRequestHeaderReplacer _replacer;
 | 
			
		||||
        private Response _result;
 | 
			
		||||
 | 
			
		||||
        public HttpContextRequestHeaderReplacerTests()
 | 
			
		||||
        {
 | 
			
		||||
            _replacer = new HttpContextRequestHeaderReplacer();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_replace_headers()
 | 
			
		||||
        {
 | 
			
		||||
            var context = new DefaultHttpContext();
 | 
			
		||||
            context.Request.Headers.Add("test", "test");
 | 
			
		||||
 | 
			
		||||
            var fAndRs = new List<HeaderFindAndReplace>();
 | 
			
		||||
            fAndRs.Add(new HeaderFindAndReplace("test", "test", "chiken", 0));
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFollowingHttpRequest(context))
 | 
			
		||||
                .And(x => GivenTheFollowingHeaderReplacements(fAndRs))
 | 
			
		||||
                .When(x => WhenICallTheReplacer())
 | 
			
		||||
                .Then(x => ThenTheHeadersAreReplaced())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_replace_headers()
 | 
			
		||||
        {
 | 
			
		||||
            var context = new DefaultHttpContext();
 | 
			
		||||
            context.Request.Headers.Add("test", "test");
 | 
			
		||||
 | 
			
		||||
            var fAndRs = new List<HeaderFindAndReplace>();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheFollowingHttpRequest(context))
 | 
			
		||||
                .And(x => GivenTheFollowingHeaderReplacements(fAndRs))
 | 
			
		||||
                .When(x => WhenICallTheReplacer())
 | 
			
		||||
                .Then(x => ThenTheHeadersAreNotReplaced())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheHeadersAreNotReplaced()
 | 
			
		||||
        {
 | 
			
		||||
             _result.ShouldBeOfType<OkResponse>();
 | 
			
		||||
            foreach (var f in _fAndRs)
 | 
			
		||||
            {
 | 
			
		||||
                _context.Request.Headers.TryGetValue(f.Key, out var values);
 | 
			
		||||
                values[f.Index].ShouldBe("test");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFollowingHttpRequest(HttpContext context)
 | 
			
		||||
        {
 | 
			
		||||
            _context = context;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFollowingHeaderReplacements(List<HeaderFindAndReplace> fAndRs)
 | 
			
		||||
        {
 | 
			
		||||
            _fAndRs = fAndRs;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheReplacer()
 | 
			
		||||
        {
 | 
			
		||||
            _result = _replacer.Replace(_context, _fAndRs);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheHeadersAreReplaced()
 | 
			
		||||
        {
 | 
			
		||||
            _result.ShouldBeOfType<OkResponse>();
 | 
			
		||||
            foreach (var f in _fAndRs)
 | 
			
		||||
            {
 | 
			
		||||
                _context.Request.Headers.TryGetValue(f.Key, out var values);
 | 
			
		||||
                values[f.Index].ShouldBe(f.Replace);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,93 @@
 | 
			
		||||
using Xunit;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using Microsoft.AspNetCore.Builder;
 | 
			
		||||
using Ocelot.Headers.Middleware;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using System;
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.DownstreamRouteFinder;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Ocelot.Configuration.Builder;
 | 
			
		||||
using Ocelot.Headers;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Headers
 | 
			
		||||
{
 | 
			
		||||
    public class HttpHeadersTransformationMiddlewareTests : ServerHostedMiddlewareTest
 | 
			
		||||
    {
 | 
			
		||||
        private Mock<IHttpContextRequestHeaderReplacer> _preReplacer;
 | 
			
		||||
        private Mock<IHttpResponseHeaderReplacer> _postReplacer;
 | 
			
		||||
        
 | 
			
		||||
        public HttpHeadersTransformationMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _preReplacer = new Mock<IHttpContextRequestHeaderReplacer>();
 | 
			
		||||
            _postReplacer = new Mock<IHttpResponseHeaderReplacer>();
 | 
			
		||||
            
 | 
			
		||||
            GivenTheTestServerIsConfigured();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_call_pre_and_post_header_transforms()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => GivenTheFollowingRequest())
 | 
			
		||||
                .And(x => GivenTheReRouteHasPreFindAndReplaceSetUp())
 | 
			
		||||
                .And(x => GivenTheHttpResponseMessageIs())
 | 
			
		||||
                .When(x => WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => ThenTheIHttpContextRequestHeaderReplacerIsCalledCorrectly())
 | 
			
		||||
                .And(x => ThenTheIHttpResponseHeaderReplacerIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheHttpResponseMessageIs()
 | 
			
		||||
        {
 | 
			
		||||
            var httpResponseMessage = new HttpResponseMessage();
 | 
			
		||||
            var response = new OkResponse<HttpResponseMessage>(httpResponseMessage);
 | 
			
		||||
            ScopedRepository.Setup(x => x.Get<HttpResponseMessage>("HttpResponseMessage")).Returns(response);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheReRouteHasPreFindAndReplaceSetUp()
 | 
			
		||||
        {
 | 
			
		||||
            var fAndRs = new List<HeaderFindAndReplace>();
 | 
			
		||||
            var reRoute = new ReRouteBuilder().WithUpstreamHeaderFindAndReplace(fAndRs).WithDownstreamHeaderFindAndReplace(fAndRs).Build();
 | 
			
		||||
            var dR = new DownstreamRoute(null, reRoute);
 | 
			
		||||
            var response = new OkResponse<DownstreamRoute>(dR);
 | 
			
		||||
            ScopedRepository.Setup(x => x.Get<DownstreamRoute>("DownstreamRoute")).Returns(response);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheIHttpContextRequestHeaderReplacerIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _preReplacer.Verify(x => x.Replace(It.IsAny<HttpContext>(), It.IsAny<List<HeaderFindAndReplace>>()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheIHttpResponseHeaderReplacerIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _postReplacer.Verify(x => x.Replace(It.IsAny<HttpResponseMessage>(), It.IsAny<List<HeaderFindAndReplace>>()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFollowingRequest()
 | 
			
		||||
        {
 | 
			
		||||
            Client.DefaultRequestHeaders.Add("test", "test");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services)
 | 
			
		||||
        {
 | 
			
		||||
            services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
 | 
			
		||||
            services.AddLogging();
 | 
			
		||||
            services.AddSingleton(ScopedRepository.Object);
 | 
			
		||||
            services.AddSingleton(_preReplacer.Object);
 | 
			
		||||
            services.AddSingleton(_postReplacer.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app)
 | 
			
		||||
        {
 | 
			
		||||
            app.UseHttpHeadersTransformationMiddleware();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,91 @@
 | 
			
		||||
using Xunit;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using Ocelot.Headers;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Headers
 | 
			
		||||
{
 | 
			
		||||
    public class HttpResponseHeaderReplacerTests
 | 
			
		||||
    {
 | 
			
		||||
        private HttpResponseMessage _response;
 | 
			
		||||
        private HttpResponseHeaderReplacer _replacer;
 | 
			
		||||
        private List<HeaderFindAndReplace> _headerFindAndReplaces;
 | 
			
		||||
        private Response _result;
 | 
			
		||||
 | 
			
		||||
        public HttpResponseHeaderReplacerTests()
 | 
			
		||||
        {
 | 
			
		||||
            _replacer = new HttpResponseHeaderReplacer();
 | 
			
		||||
        }
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_replace_headers()
 | 
			
		||||
        {
 | 
			
		||||
            var response = new HttpResponseMessage();
 | 
			
		||||
            response.Headers.Add("test", "test");
 | 
			
		||||
 | 
			
		||||
            var fAndRs = new List<HeaderFindAndReplace>();
 | 
			
		||||
            fAndRs.Add(new HeaderFindAndReplace("test", "test", "chiken", 0));
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheHttpResponse(response))
 | 
			
		||||
                .And(x => GivenTheFollowingHeaderReplacements(fAndRs))
 | 
			
		||||
                .When(x => WhenICallTheReplacer())
 | 
			
		||||
                .Then(x => ThenTheHeadersAreReplaced())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_replace_headers()
 | 
			
		||||
        {
 | 
			
		||||
            var response = new HttpResponseMessage();
 | 
			
		||||
            response.Headers.Add("test", "test");
 | 
			
		||||
 | 
			
		||||
            var fAndRs = new List<HeaderFindAndReplace>();
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenTheHttpResponse(response))
 | 
			
		||||
                .And(x => GivenTheFollowingHeaderReplacements(fAndRs))
 | 
			
		||||
                .When(x => WhenICallTheReplacer())
 | 
			
		||||
                .Then(x => ThenTheHeadersAreNotReplaced())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        private void ThenTheHeadersAreNotReplaced()
 | 
			
		||||
        {
 | 
			
		||||
             _result.ShouldBeOfType<OkResponse>();
 | 
			
		||||
            foreach (var f in _headerFindAndReplaces)
 | 
			
		||||
            {
 | 
			
		||||
                _response.Headers.TryGetValues(f.Key, out var values);
 | 
			
		||||
                values.ToList()[f.Index].ShouldBe("test");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFollowingHeaderReplacements(List<HeaderFindAndReplace> fAndRs)
 | 
			
		||||
        {
 | 
			
		||||
            _headerFindAndReplaces = fAndRs;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheHttpResponse(HttpResponseMessage response)
 | 
			
		||||
        {
 | 
			
		||||
            _response = response;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheReplacer()
 | 
			
		||||
        {
 | 
			
		||||
            _result = _replacer.Replace(_response, _headerFindAndReplaces);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
         private void ThenTheHeadersAreReplaced()
 | 
			
		||||
        {
 | 
			
		||||
            _result.ShouldBeOfType<OkResponse>();
 | 
			
		||||
            foreach (var f in _headerFindAndReplaces)
 | 
			
		||||
            {
 | 
			
		||||
                _response.Headers.TryGetValues(f.Key, out var values);
 | 
			
		||||
                values.ToList()[f.Index].ShouldBe(f.Replace);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user