mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-06-19 10:18:17 +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:
190
test/Ocelot.AcceptanceTests/HeaderTests.cs
Normal file
190
test/Ocelot.AcceptanceTests/HeaderTests.cs
Normal file
@ -0,0 +1,190 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Ocelot.Configuration.File;
|
||||
using Shouldly;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
|
||||
namespace Ocelot.AcceptanceTests
|
||||
{
|
||||
public class HeaderTests : IDisposable
|
||||
{
|
||||
private IWebHost _builder;
|
||||
private readonly Steps _steps;
|
||||
private string _downstreamPath;
|
||||
|
||||
public HeaderTests()
|
||||
{
|
||||
_steps = new Steps();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_transform_upstream_header()
|
||||
{
|
||||
var configuration = new FileConfiguration
|
||||
{
|
||||
ReRoutes = new List<FileReRoute>
|
||||
{
|
||||
new FileReRoute
|
||||
{
|
||||
DownstreamPathTemplate = "/",
|
||||
DownstreamScheme = "http",
|
||||
DownstreamHost = "localhost",
|
||||
DownstreamPort = 51879,
|
||||
UpstreamPathTemplate = "/",
|
||||
UpstreamHttpMethod = new List<string> { "Get" },
|
||||
UpstreamHeaderTransform = new Dictionary<string,string>
|
||||
{
|
||||
{"Laz", "D, GP"}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "/", 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",
|
||||
DownstreamHost = "localhost",
|
||||
DownstreamPort = 51879,
|
||||
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:51879", "/", 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",
|
||||
DownstreamHost = "localhost",
|
||||
DownstreamPort = 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();
|
||||
}
|
||||
|
||||
|
||||
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string headerKey)
|
||||
{
|
||||
_builder = new WebHostBuilder()
|
||||
.UseUrls(baseUrl)
|
||||
.UseKestrel()
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.UseIISIntegration()
|
||||
.Configure(app =>
|
||||
{
|
||||
app.UsePathBase(basePath);
|
||||
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();
|
||||
|
||||
_builder.Start();
|
||||
}
|
||||
|
||||
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string headerKey, string headerValue)
|
||||
{
|
||||
_builder = new WebHostBuilder()
|
||||
.UseUrls(baseUrl)
|
||||
.UseKestrel()
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.UseIISIntegration()
|
||||
.Configure(app =>
|
||||
{
|
||||
app.UsePathBase(basePath);
|
||||
app.Run(async context =>
|
||||
{
|
||||
context.Response.OnStarting(() => {
|
||||
context.Response.Headers.Add(headerKey, headerValue);
|
||||
context.Response.StatusCode = statusCode;
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
});
|
||||
})
|
||||
.Build();
|
||||
|
||||
_builder.Start();
|
||||
}
|
||||
|
||||
internal void ThenTheDownstreamUrlPathShouldBe(string expectedDownstreamPath)
|
||||
{
|
||||
_downstreamPath.ShouldBe(expectedDownstreamPath);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_builder?.Dispose();
|
||||
_steps.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
@ -108,6 +108,12 @@ namespace Ocelot.AcceptanceTests
|
||||
_ocelotClient = _ocelotServer.CreateClient();
|
||||
}
|
||||
|
||||
public void ThenTheResponseHeaderIs(string key, string value)
|
||||
{
|
||||
var header = _response.Headers.GetValues(key);
|
||||
header.First().ShouldBe(value);
|
||||
}
|
||||
|
||||
public void GivenOcelotIsRunningUsingJsonSerializedCache()
|
||||
{
|
||||
_webHostBuilder = new WebHostBuilder();
|
||||
@ -326,6 +332,11 @@ namespace Ocelot.AcceptanceTests
|
||||
_response = _ocelotClient.GetAsync(url).Result;
|
||||
}
|
||||
|
||||
public void GivenIAddAHeader(string key, string value)
|
||||
{
|
||||
_ocelotClient.DefaultRequestHeaders.Add(key, value);
|
||||
}
|
||||
|
||||
public void WhenIGetUrlOnTheApiGatewayMultipleTimes(string url, int times)
|
||||
{
|
||||
var tasks = new Task[times];
|
||||
|
@ -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