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:
Tom Pallister
2018-01-22 20:21:29 +00:00
committed by GitHub
parent 9c048ba615
commit d0eee70c46
28 changed files with 1028 additions and 9 deletions

View File

@ -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);
}
}
}
}

View File

@ -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();
}
}
}

View File

@ -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);
}
}
}
}