Feature/downstream aggregation (#248)

* started messing around with this on the train last night

* mega hacking away to change middleware into Ocelot iddleware

* scoped data repo back in

* broken commit getting tests working

* another broken commit farting around with tests

* all unit tests passing again

* mw pipeline for ocelot...still loads of hacks but getting there now to get acceptance tests working, then fix config so you can have aggregate and then imlement multiplexer, then mapping to response...loads to do

* all tests passing before aggregation feature implemented

* removed all the request middleware stuff we dont need it

* updated how errors work...tho i think there could be edge case here when aggregating because one downstream could error and this would effect another

* removed multiplexer so you dont have to send route down, this isnt very thread safe...sigh

* hacking around getting the config for aggregates in, this might change

* refactored builder and unit tests passing now

* Updated a bunch of ports for tests

* plugged in code to create reroutes that are aggregates

* made multiplexer a class

* hacked test to death

* simple aggregator done, initial validation done

* removed request id from context, it is still specific for http request

* now aggregates to json always

* docs for aggregate reroutes

* Updated docs
This commit is contained in:
Tom Pallister
2018-02-27 08:22:47 +00:00
committed by GitHub
parent 2573657ec2
commit d1926268ac
137 changed files with 4032 additions and 2007 deletions

View File

@ -1,4 +1,6 @@
namespace Ocelot.UnitTests.Request
using Ocelot.Middleware;
namespace Ocelot.UnitTests.Request
{
using System.Net.Http;
using Microsoft.AspNetCore.Http;
@ -10,6 +12,8 @@
using TestStack.BDDfy;
using Xunit;
using Ocelot.Responses;
using Ocelot.DownstreamRouteFinder.Middleware;
using Shouldly;
public class DownstreamRequestInitialiserMiddlewareTests
{
@ -19,17 +23,16 @@
readonly Mock<HttpRequest> _httpRequest;
readonly Mock<RequestDelegate> _next;
readonly Mock<OcelotRequestDelegate> _next;
readonly Mock<IRequestMapper> _requestMapper;
readonly Mock<IRequestScopedDataRepository> _repo;
readonly Mock<IOcelotLoggerFactory> _loggerFactory;
readonly Mock<IOcelotLogger> _logger;
Response<HttpRequestMessage> _mappedRequest;
private DownstreamContext _downstreamContext;
public DownstreamRequestInitialiserMiddlewareTests()
{
@ -37,8 +40,7 @@
_httpContext = new Mock<HttpContext>();
_httpRequest = new Mock<HttpRequest>();
_requestMapper = new Mock<IRequestMapper>();
_repo = new Mock<IRequestScopedDataRepository>();
_next = new Mock<RequestDelegate>();
_next = new Mock<OcelotRequestDelegate>();
_logger = new Mock<IOcelotLogger>();
_loggerFactory = new Mock<IOcelotLoggerFactory>();
@ -49,8 +51,9 @@
_middleware = new DownstreamRequestInitialiserMiddleware(
_next.Object,
_loggerFactory.Object,
_repo.Object,
_requestMapper.Object);
_downstreamContext = new DownstreamContext(_httpContext.Object);
}
[Fact]
@ -104,7 +107,7 @@
private void WhenTheMiddlewareIsInvoked()
{
_middleware.Invoke(_httpContext.Object).GetAwaiter().GetResult();
_middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
}
private void ThenTheContexRequestIsMappedToADownstreamRequest()
@ -114,29 +117,28 @@
private void ThenTheDownstreamRequestIsStored()
{
_repo.Verify(r => r.Add("DownstreamRequest", _mappedRequest.Data), Times.Once);
_downstreamContext.DownstreamRequest.ShouldNotBeNull();
}
private void ThenTheDownstreamRequestIsNotStored()
{
_repo.Verify(r => r.Add("DownstreamRequest", It.IsAny<HttpRequestMessage>()), Times.Never);
_downstreamContext.DownstreamRequest.ShouldBeNull();
}
private void ThenAPipelineErrorIsStored()
{
_repo.Verify(r => r.Add("OcelotMiddlewareError", true), Times.Once);
_repo.Verify(r => r.Add("OcelotMiddlewareErrors", _mappedRequest.Errors), Times.Once);
_downstreamContext.IsError.ShouldBeTrue();
_downstreamContext.Errors.ShouldBe(_mappedRequest.Errors);
}
private void ThenTheNextMiddlewareIsInvoked()
{
_next.Verify(n => n(_httpContext.Object), Times.Once);
_next.Verify(n => n(_downstreamContext), Times.Once);
}
private void ThenTheNextMiddlewareIsNotInvoked()
{
_next.Verify(n => n(It.IsAny<HttpContext>()), Times.Never);
_next.Verify(n => n(It.IsAny<DownstreamContext>()), Times.Never);
}
}
}

View File

@ -1,152 +0,0 @@
namespace Ocelot.UnitTests.Request
{
using System.Collections.Generic;
using System.Net.Http;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using Ocelot.Configuration.Builder;
using Ocelot.DownstreamRouteFinder;
using Ocelot.DownstreamRouteFinder.UrlMatcher;
using Ocelot.Infrastructure.RequestData;
using Ocelot.Logging;
using Ocelot.Request.Builder;
using Ocelot.Request.Middleware;
using Ocelot.Responses;
using TestStack.BDDfy;
using Xunit;
using Ocelot.Requester.QoS;
using Ocelot.Configuration;
using Microsoft.AspNetCore.Builder;
using Ocelot.Errors;
public class HttpRequestBuilderMiddlewareTests : ServerHostedMiddlewareTest
{
private readonly Mock<IRequestCreator> _requestBuilder;
private readonly Mock<IRequestScopedDataRepository> _scopedRepository;
private readonly Mock<IQosProviderHouse> _qosProviderHouse;
private readonly HttpRequestMessage _downstreamRequest;
private OkResponse<Ocelot.Request.Request> _request;
private OkResponse<string> _downstreamUrl;
private OkResponse<DownstreamRoute> _downstreamRoute;
public HttpRequestBuilderMiddlewareTests()
{
_qosProviderHouse = new Mock<IQosProviderHouse>();
_requestBuilder = new Mock<IRequestCreator>();
_scopedRepository = new Mock<IRequestScopedDataRepository>();
_downstreamRequest = new HttpRequestMessage();
_scopedRepository
.Setup(sr => sr.Get<HttpRequestMessage>("DownstreamRequest"))
.Returns(new OkResponse<HttpRequestMessage>(_downstreamRequest));
GivenTheTestServerIsConfigured();
}
[Fact]
public void should_call_scoped_data_repository_correctly()
{
var downstreamRoute = new DownstreamRoute(new List<PlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithRequestIdKey("LSRequestId")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.WithHttpHandlerOptions(new HttpHandlerOptions(true, true,false))
.Build());
this.Given(x => x.GivenTheDownStreamUrlIs("any old string"))
.And(x => x.GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(new NoQoSProvider())))
.And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
.And(x => x.GivenTheRequestBuilderReturns(new Ocelot.Request.Request(new HttpRequestMessage(), true, new NoQoSProvider(), false, false, "", false)))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly())
.BDDfy();
}
[Fact]
public void should_call_scoped_data_repository_QosProviderError()
{
var downstreamRoute = new DownstreamRoute(new List<PlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithRequestIdKey("LSRequestId")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true))
.Build());
this.Given(x => x.GivenTheDownStreamUrlIs("any old string"))
.And(x => x.GivenTheQosProviderHouseReturns(new ErrorResponse<IQoSProvider>(It.IsAny<Error>())))
.And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
.And(x => x.GivenTheRequestBuilderReturns(new Ocelot.Request.Request(new HttpRequestMessage(), true, new NoQoSProvider(), false, false, "", false)))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheScopedDataRepositoryQosProviderError())
.BDDfy();
}
protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services)
{
services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
services.AddLogging();
services.AddSingleton(_qosProviderHouse.Object);
services.AddSingleton(_requestBuilder.Object);
services.AddSingleton(_scopedRepository.Object);
}
protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app)
{
app.UseHttpRequestBuilderMiddleware();
}
private void GivenTheDownStreamUrlIs(string downstreamUrl)
{
_downstreamUrl = new OkResponse<string>(downstreamUrl);
_scopedRepository
.Setup(x => x.Get<string>(It.IsAny<string>()))
.Returns(_downstreamUrl);
}
private void GivenTheQosProviderHouseReturns(Response<IQoSProvider> qosProvider)
{
_qosProviderHouse
.Setup(x => x.Get(It.IsAny<ReRoute>()))
.Returns(qosProvider);
}
private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute)
{
_downstreamRoute = new OkResponse<DownstreamRoute>(downstreamRoute);
_scopedRepository
.Setup(x => x.Get<DownstreamRoute>(It.IsAny<string>()))
.Returns(_downstreamRoute);
}
private void GivenTheRequestBuilderReturns(Ocelot.Request.Request request)
{
_request = new OkResponse<Ocelot.Request.Request>(request);
_requestBuilder
.Setup(x => x.Build(It.IsAny<HttpRequestMessage>(),
It.IsAny<bool>(),
It.IsAny<IQoSProvider>(),
It.IsAny<bool>(),
It.IsAny<bool>(),
It.IsAny<string>(),
It.IsAny<bool>()))
.ReturnsAsync(_request);
}
private void ThenTheScopedDataRepositoryIsCalledCorrectly()
{
_scopedRepository
.Verify(x => x.Add("Request", _request.Data), Times.Once());
}
private void ThenTheScopedDataRepositoryQosProviderError()
{
_scopedRepository
.Verify(x => x.Add("OcelotMiddlewareError", true), Times.Once());
}
}
}

View File

@ -1,86 +0,0 @@
namespace Ocelot.UnitTests.Request
{
using System.Net.Http;
using Ocelot.Request.Builder;
using Ocelot.Requester.QoS;
using Ocelot.Responses;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
public class HttpRequestCreatorTests
{
private readonly IRequestCreator _requestCreator;
private readonly bool _isQos;
private readonly IQoSProvider _qoSProvider;
private readonly HttpRequestMessage _requestMessage;
private readonly bool _useCookieContainer;
private readonly bool _allowAutoRedirect;
private Response<Ocelot.Request.Request> _response;
private string _reRouteKey;
private readonly bool _useTracing;
public HttpRequestCreatorTests()
{
_requestCreator = new HttpRequestCreator();
_isQos = true;
_qoSProvider = new NoQoSProvider();
_useCookieContainer = false;
_allowAutoRedirect = false;
_requestMessage = new HttpRequestMessage();
}
[Fact]
public void ShouldBuildRequest()
{
this.When(x => x.WhenIBuildARequest())
.Then(x => x.ThenTheRequestContainsTheRequestMessage())
.Then(x => x.ThenTheRequestContainsTheIsQos())
.Then(x => x.ThenTheRequestContainsTheQosProvider())
.Then(x => x.ThenTheRequestContainsUseCookieContainer())
.Then(x => x.ThenTheRequestContainsUseTracing())
.Then(x => x.ThenTheRequestContainsAllowAutoRedirect())
.BDDfy();
}
private void WhenIBuildARequest()
{
_response = _requestCreator.Build(_requestMessage,
_isQos, _qoSProvider, _useCookieContainer, _allowAutoRedirect, _reRouteKey, _useTracing)
.GetAwaiter()
.GetResult();
}
private void ThenTheRequestContainsTheRequestMessage()
{
_response.Data.HttpRequestMessage.ShouldBe(_requestMessage);
}
private void ThenTheRequestContainsTheIsQos()
{
_response.Data.IsQos.ShouldBe(_isQos);
}
private void ThenTheRequestContainsTheQosProvider()
{
_response.Data.QosProvider.ShouldBe(_qoSProvider);
}
private void ThenTheRequestContainsUseCookieContainer()
{
_response.Data.UseCookieContainer.ShouldBe(_useCookieContainer);
}
private void ThenTheRequestContainsUseTracing()
{
_response.Data.IsTracing.ShouldBe(_useTracing);
}
private void ThenTheRequestContainsAllowAutoRedirect()
{
_response.Data.AllowAutoRedirect.ShouldBe(_allowAutoRedirect);
}
}
}