#298 initial hacking around better aggregation (#310)

* #298 initial hacking around better aggregation

* #298 bit more hacking around

* #298 abstraction over httpresponsemessage

* #298 tidying up

* #298 docs

* #298 missed this
This commit is contained in:
Tom Pallister
2018-04-12 17:35:04 +01:00
committed by GitHub
parent 982eebfc74
commit a15f75dda8
63 changed files with 1203 additions and 410 deletions

View File

@ -1,11 +1,17 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using Ocelot.Middleware;
using Ocelot.Middleware.Multiplexer;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
@ -15,6 +21,7 @@ namespace Ocelot.AcceptanceTests
public class AggregateTests : IDisposable
{
private IWebHost _serviceOneBuilder;
private IWebHost _serviceTwoBuilder;
private readonly Steps _steps;
private string _downstreamPathOne;
private string _downstreamPathTwo;
@ -24,6 +31,75 @@ namespace Ocelot.AcceptanceTests
_steps = new Steps();
}
[Fact]
public void should_return_response_200_with_simple_url_user_defined_aggregate()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51885,
}
},
UpstreamPathTemplate = "/laura",
UpstreamHttpMethod = new List<string> { "Get" },
Key = "Laura"
},
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51886,
}
},
UpstreamPathTemplate = "/tom",
UpstreamHttpMethod = new List<string> { "Get" },
Key = "Tom"
}
},
Aggregates = new List<FileAggregateReRoute>
{
new FileAggregateReRoute
{
UpstreamPathTemplate = "/",
UpstreamHost = "localhost",
ReRouteKeys = new List<string>
{
"Tom",
"Laura"
},
Aggregator = "FakeDefinedAggregator"
}
}
};
var expected = "Bye from Laura, Bye from Tom";
this.Given(x => x.GivenServiceOneIsRunning("http://localhost:51885", "/", 200, "{Hello from Laura}"))
.Given(x => x.GivenServiceTwoIsRunning("http://localhost:51886", "/", 200, "{Hello from Tom}"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningWithSpecficAggregatorsRegisteredInDi<FakeDefinedAggregator, FakeDepdendency>())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe(expected))
.And(x => ThenTheDownstreamUrlPathShouldBe("/", "/"))
.BDDfy();
}
[Fact]
public void should_return_response_200_with_simple_url()
{
@ -325,7 +401,7 @@ namespace Ocelot.AcceptanceTests
private void GivenServiceTwoIsRunning(string baseUrl, string basePath, int statusCode, string responseBody)
{
_serviceOneBuilder = new WebHostBuilder()
_serviceTwoBuilder = new WebHostBuilder()
.UseUrls(baseUrl)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
@ -351,7 +427,7 @@ namespace Ocelot.AcceptanceTests
})
.Build();
_serviceOneBuilder.Start();
_serviceTwoBuilder.Start();
}
internal void ThenTheDownstreamUrlPathShouldBe(string expectedDownstreamPathOne, string expectedDownstreamPath)
@ -363,7 +439,33 @@ namespace Ocelot.AcceptanceTests
public void Dispose()
{
_serviceOneBuilder?.Dispose();
_serviceTwoBuilder?.Dispose();
_steps.Dispose();
}
}
public class FakeDepdendency
{
}
public class FakeDefinedAggregator : IDefinedAggregator
{
private readonly FakeDepdendency _dep;
public FakeDefinedAggregator(FakeDepdendency dep)
{
_dep = dep;
}
public async Task<DownstreamResponse> Aggregate(List<DownstreamResponse> responses)
{
var one = await responses[0].Content.ReadAsStringAsync();
var two = await responses[1].Content.ReadAsStringAsync();
var merge = $"{one}, {two}";
merge = merge.Replace("Hello", "Bye").Replace("{", "").Replace("}", "");
var headers = responses.SelectMany(x => x.Headers).ToList();
return new DownstreamResponse(new StringContent(merge), HttpStatusCode.OK, headers);
}
}
}

View File

@ -91,17 +91,17 @@ namespace Ocelot.AcceptanceTests
var butterflyUrl = "http://localhost:9618";
this.Given(x => GivenServiceOneIsRunning("http://localhost:51887", "/api/values", 200, "Hello from Laura", butterflyUrl))
this.Given(x => GivenFakeButterfly(butterflyUrl))
.And(x => GivenServiceOneIsRunning("http://localhost:51887", "/api/values", 200, "Hello from Laura", butterflyUrl))
.And(x => GivenServiceTwoIsRunning("http://localhost:51388", "/api/values", 200, "Hello from Tom", butterflyUrl))
.And(x => GivenFakeButterfly(butterflyUrl))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningUsingButterfly(butterflyUrl))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/api001/values"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/api002/values"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Tom"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/api002/values"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Tom"))
.BDDfy();
var commandOnAllStateMachines = WaitFor(10000).Until(() => _butterflyCalled == 4);
@ -151,8 +151,8 @@ namespace Ocelot.AcceptanceTests
var butterflyUrl = "http://localhost:9618";
this.Given(x => GivenServiceOneIsRunning("http://localhost:51387", "/api/values", 200, "Hello from Laura", butterflyUrl))
.And(x => GivenFakeButterfly(butterflyUrl))
this.Given(x => GivenFakeButterfly(butterflyUrl))
.And(x => GivenServiceOneIsRunning("http://localhost:51387", "/api/values", 200, "Hello from Laura", butterflyUrl))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningUsingButterfly(butterflyUrl))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/api001/values"))

View File

@ -26,6 +26,7 @@ using System.IO.Compression;
using System.Text;
using static Ocelot.AcceptanceTests.HttpDelegatingHandlersTests;
using Ocelot.Requester;
using Ocelot.Middleware.Multiplexer;
namespace Ocelot.AcceptanceTests
{
@ -178,12 +179,6 @@ namespace Ocelot.AcceptanceTests
_ocelotClient = _ocelotServer.CreateClient();
}
/*
public void GivenIHaveAddedXForwardedForHeader(string value)
{
_ocelotClient.DefaultRequestHeaders.TryAddWithoutValidation("X-Forwarded-For", value);
}*/
public void GivenOcelotIsRunningWithMiddleareBeforePipeline<T>(Func<object, Task> callback)
{
_webHostBuilder = new WebHostBuilder();
@ -246,6 +241,39 @@ namespace Ocelot.AcceptanceTests
_ocelotClient = _ocelotServer.CreateClient();
}
public void GivenOcelotIsRunningWithSpecficAggregatorsRegisteredInDi<TAggregator, TDepedency>()
where TAggregator : class, IDefinedAggregator
where TDepedency : class
{
_webHostBuilder = new WebHostBuilder();
_webHostBuilder
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddJsonFile("configuration.json");
config.AddEnvironmentVariables();
})
.ConfigureServices(s =>
{
s.AddSingleton(_webHostBuilder);
s.AddSingleton<TDepedency>();
s.AddOcelot()
.AddSingletonDefinedAggregator<TAggregator>();
})
.Configure(a =>
{
a.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}
public void GivenOcelotIsRunningWithGlobalHandlersRegisteredInDi<TOne, TWo>()
where TOne : DelegatingHandler
where TWo : DelegatingHandler