#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

View File

@ -1,7 +1,4 @@
using Ocelot.Errors;
using Ocelot.Middleware;
namespace Ocelot.UnitTests.Cache
namespace Ocelot.UnitTests.Cache
{
using System.Linq;
using System.Net;
@ -17,15 +14,17 @@ namespace Ocelot.UnitTests.Cache
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Logging;
using Ocelot.Middleware;
using TestStack.BDDfy;
using Xunit;
using Microsoft.AspNetCore.Http;
using Ocelot.Middleware.Multiplexer;
public class OutputCacheMiddlewareRealCacheTests
{
private IOcelotCache<CachedResponse> _cacheManager;
private OutputCacheMiddleware _middleware;
private DownstreamContext _downstreamContext;
private readonly IOcelotCache<CachedResponse> _cacheManager;
private readonly OutputCacheMiddleware _middleware;
private readonly DownstreamContext _downstreamContext;
private OcelotRequestDelegate _next;
private Mock<IOcelotLoggerFactory> _loggerFactory;
private IRegionCreator _regionCreator;
@ -56,14 +55,10 @@ namespace Ocelot.UnitTests.Cache
Headers = { ContentType = new MediaTypeHeaderValue("application/json")}
};
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = content,
};
var response = new DownstreamResponse(content, HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>());
this.Given(x => x.GivenResponseIsNotCached(response))
.And(x => x.GivenTheDownstreamRouteIs())
.And(x => x.GivenThereAreNoErrors())
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheContentTypeHeaderIsCached())
.BDDfy();
@ -81,9 +76,9 @@ namespace Ocelot.UnitTests.Cache
header.First().ShouldBe("application/json");
}
private void GivenResponseIsNotCached(HttpResponseMessage message)
private void GivenResponseIsNotCached(DownstreamResponse response)
{
_downstreamContext.DownstreamResponse = message;
_downstreamContext.DownstreamResponse = response;
}
private void GivenTheDownstreamRouteIs()
@ -96,10 +91,5 @@ namespace Ocelot.UnitTests.Cache
_downstreamContext.DownstreamReRoute = reRoute;
}
private void GivenThereAreNoErrors()
{
_downstreamContext.Errors = new List<Error>();
}
}
}

View File

@ -1,8 +1,4 @@
using System.Net;
using Ocelot.Errors;
using Ocelot.Middleware;
namespace Ocelot.UnitTests.Cache
namespace Ocelot.UnitTests.Cache
{
using System;
using System.Collections.Generic;
@ -19,17 +15,20 @@ namespace Ocelot.UnitTests.Cache
using Ocelot.Logging;
using TestStack.BDDfy;
using Xunit;
using System.Net;
using Ocelot.Middleware;
using Ocelot.Middleware.Multiplexer;
public class OutputCacheMiddlewareTests
{
private readonly Mock<IOcelotCache<CachedResponse>> _cacheManager;
private Mock<IOcelotLoggerFactory> _loggerFactory;
private readonly Mock<IOcelotLoggerFactory> _loggerFactory;
private Mock<IOcelotLogger> _logger;
private OutputCacheMiddleware _middleware;
private DownstreamContext _downstreamContext;
private OcelotRequestDelegate _next;
private readonly DownstreamContext _downstreamContext;
private readonly OcelotRequestDelegate _next;
private CachedResponse _response;
private IRegionCreator _regionCreator;
private readonly IRegionCreator _regionCreator;
public OutputCacheMiddlewareTests()
{
@ -46,7 +45,17 @@ namespace Ocelot.UnitTests.Cache
[Fact]
public void should_returned_cached_item_when_it_is_in_cache()
{
var cachedResponse = new CachedResponse(HttpStatusCode.OK, new Dictionary<string, IEnumerable<string>>(), "", new Dictionary<string, IEnumerable<string>>());
var headers = new Dictionary<string, IEnumerable<string>>
{
{ "test", new List<string> { "test" } }
};
var contentHeaders = new Dictionary<string, IEnumerable<string>>
{
{ "content-type", new List<string> { "application/json" } }
};
var cachedResponse = new CachedResponse(HttpStatusCode.OK, headers, "", contentHeaders);
this.Given(x => x.GivenThereIsACachedResponse(cachedResponse))
.And(x => x.GivenTheDownstreamRouteIs())
.When(x => x.WhenICallTheMiddleware())
@ -59,7 +68,6 @@ namespace Ocelot.UnitTests.Cache
{
this.Given(x => x.GivenResponseIsNotCached())
.And(x => x.GivenTheDownstreamRouteIs())
.And(x => x.GivenThereAreNoErrors())
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheCacheAddIsCalledCorrectly())
.BDDfy();
@ -81,7 +89,7 @@ namespace Ocelot.UnitTests.Cache
private void GivenResponseIsNotCached()
{
_downstreamContext.DownstreamResponse = new HttpResponseMessage();
_downstreamContext.DownstreamResponse = new DownstreamResponse(new HttpResponseMessage());
}
private void GivenTheDownstreamRouteIs()
@ -101,11 +109,6 @@ namespace Ocelot.UnitTests.Cache
_downstreamContext.DownstreamReRoute = downstreamRoute.ReRoute.DownstreamReRoute[0];
}
private void GivenThereAreNoErrors()
{
_downstreamContext.Errors = new List<Error>();
}
private void ThenTheCacheGetIsCalledCorrectly()
{
_cacheManager

View File

@ -134,7 +134,8 @@ namespace Ocelot.UnitTests.Configuration
{
"Tom",
"Laura"
}
},
Aggregator = "asdf"
}
}
};

View File

@ -149,7 +149,6 @@ namespace Ocelot.UnitTests.Configuration
.Then(x => ThenTheFollowingDownstreamIsReturned(downstream))
.BDDfy();
}
[Fact]
public void should_add_trace_id_header()

View File

@ -18,6 +18,8 @@ using Shouldly;
using IdentityServer4.AccessTokenValidation;
using TestStack.BDDfy;
using Xunit;
using static Ocelot.UnitTests.Middleware.UserDefinedResponseAggregatorTests;
using Ocelot.Middleware.Multiplexer;
namespace Ocelot.UnitTests.DependencyInjection
{
@ -177,6 +179,40 @@ namespace Ocelot.UnitTests.DependencyInjection
.BDDfy();
}
[Fact]
public void should_add_singleton_defined_aggregators()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => AddSingletonDefinedAggregator<TestDefinedAggregator>())
.When(x => AddSingletonDefinedAggregator<TestDefinedAggregator>())
.Then(x => ThenTheProviderIsRegisteredAndReturnsSpecificAggregators<TestDefinedAggregator, TestDefinedAggregator>())
.And(x => ThenTheAggregatorsAreSingleton<TestDefinedAggregator, TestDefinedAggregator>())
.BDDfy();
}
[Fact]
public void should_add_transient_defined_aggregators()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => AddTransientDefinedAggregator<TestDefinedAggregator>())
.When(x => AddTransientDefinedAggregator<TestDefinedAggregator>())
.Then(x => ThenTheProviderIsRegisteredAndReturnsSpecificAggregators<TestDefinedAggregator, TestDefinedAggregator>())
.And(x => ThenTheAggregatorsAreTransient<TestDefinedAggregator, TestDefinedAggregator>())
.BDDfy();
}
private void AddSingletonDefinedAggregator<T>()
where T : class, IDefinedAggregator
{
_ocelotBuilder.AddSingletonDefinedAggregator<T>();
}
private void AddTransientDefinedAggregator<T>()
where T : class, IDefinedAggregator
{
_ocelotBuilder.AddTransientDefinedAggregator<T>();
}
private void ThenTheSpecificHandlersAreSingleton()
{
var handlers = _serviceProvider.GetServices<DelegatingHandler>().ToList();
@ -258,6 +294,32 @@ namespace Ocelot.UnitTests.DependencyInjection
handlers[1].ShouldBeOfType<TWo>();
}
private void ThenTheProviderIsRegisteredAndReturnsSpecificAggregators<TOne, TWo>()
{
_serviceProvider = _services.BuildServiceProvider();
var handlers = _serviceProvider.GetServices<IDefinedAggregator>().ToList();
handlers[0].ShouldBeOfType<TOne>();
handlers[1].ShouldBeOfType<TWo>();
}
private void ThenTheAggregatorsAreTransient<TOne, TWo>()
{
var aggregators = _serviceProvider.GetServices<IDefinedAggregator>().ToList();
var first = aggregators[0];
aggregators = _serviceProvider.GetServices<IDefinedAggregator>().ToList();
var second = aggregators[0];
first.ShouldNotBe(second);
}
private void ThenTheAggregatorsAreSingleton<TOne, TWo>()
{
var aggregators = _serviceProvider.GetServices<IDefinedAggregator>().ToList();
var first = aggregators[0];
aggregators = _serviceProvider.GetServices<IDefinedAggregator>().ToList();
var second = aggregators[0];
first.ShouldBe(second);
}
private void OnlyOneVersionOfEachCacheIsRegistered()
{
var outputCache = _services.Single(x => x.ServiceType == typeof(IOcelotCache<CachedResponse>));

View File

@ -1,7 +1,4 @@
using Ocelot.Configuration;
using Ocelot.Middleware;
namespace Ocelot.UnitTests.DownstreamUrlCreator
namespace Ocelot.UnitTests.DownstreamUrlCreator
{
using System;
using System.Collections.Generic;
@ -21,17 +18,19 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator
using Shouldly;
using Microsoft.AspNetCore.Http;
using Ocelot.Request.Middleware;
using Ocelot.Configuration;
using Ocelot.Middleware;
public class DownstreamUrlCreatorMiddlewareTests
{
private readonly Mock<IDownstreamPathPlaceholderReplacer> _downstreamUrlTemplateVariableReplacer;
private OkResponse<DownstreamPath> _downstreamPath;
private Mock<IOcelotLoggerFactory> _loggerFactory;
private readonly Mock<IOcelotLoggerFactory> _loggerFactory;
private Mock<IOcelotLogger> _logger;
private DownstreamUrlCreatorMiddleware _middleware;
private DownstreamContext _downstreamContext;
private OcelotRequestDelegate _next;
private HttpRequestMessage _request;
private readonly DownstreamContext _downstreamContext;
private readonly OcelotRequestDelegate _next;
private readonly HttpRequestMessage _request;
public DownstreamUrlCreatorMiddlewareTests()
{
@ -212,7 +211,6 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator
private void GivenTheDownstreamRequestUriIs(string uri)
{
_request.RequestUri = new Uri(uri);
//todo - not sure if needed
_downstreamContext.DownstreamRequest = new DownstreamRequest(_request);
}

View File

@ -1,29 +1,29 @@
using Xunit;
using Shouldly;
using TestStack.BDDfy;
using Ocelot.Headers;
using System.Net.Http;
using System.Collections.Generic;
using Ocelot.Configuration.Creator;
using System.Linq;
using Ocelot.Configuration.Creator;
using Moq;
using Ocelot.Infrastructure.RequestData;
using Ocelot.Responses;
using Ocelot.Infrastructure;
using Ocelot.UnitTests.Responder;
using System;
using Ocelot.Logging;
using Ocelot.Middleware;
using Ocelot.Middleware.Multiplexer;
using Shouldly;
namespace Ocelot.UnitTests.Headers
{
public class AddHeadersToResponseTests
{
private IAddHeadersToResponse _adder;
private Mock<IPlaceholders> _placeholders;
private HttpResponseMessage _response;
private readonly IAddHeadersToResponse _adder;
private readonly Mock<IPlaceholders> _placeholders;
private DownstreamResponse _response;
private List<AddHeader> _addHeaders;
private Mock<IOcelotLoggerFactory> _factory;
private Mock<IOcelotLogger> _logger;
private readonly Mock<IOcelotLogger> _logger;
public AddHeadersToResponseTests()
{
@ -111,7 +111,7 @@ namespace Ocelot.UnitTests.Headers
private void ThenTheHeaderIsNotAdded(string key)
{
_response.Headers.TryGetValues(key, out var values).ShouldBeFalse();
_response.Headers.Any(x => x.Key == key).ShouldBeFalse();
}
private void GivenTheTraceIdIs(string traceId)
@ -126,8 +126,8 @@ namespace Ocelot.UnitTests.Headers
private void ThenTheHeaderIsReturned(string key, string value)
{
var values = _response.Headers.GetValues(key);
values.First().ShouldBe(value);
var values = _response.Headers.First(x => x.Key == key);
values.Values.First().ShouldBe(value);
}
private void WhenIAdd()
@ -137,7 +137,7 @@ namespace Ocelot.UnitTests.Headers
private void GivenAResponseMessage()
{
_response = new HttpResponseMessage();
_response = new DownstreamResponse(new HttpResponseMessage());
}
private void GivenTheAddHeaders(List<AddHeader> addHeaders)

View File

@ -1,33 +1,33 @@
using Xunit;
using Ocelot.Logging;
using Ocelot.Headers.Middleware;
using TestStack.BDDfy;
using Microsoft.AspNetCore.Http;
using System.Collections.Generic;
using Moq;
using Ocelot.Configuration;
using Ocelot.DownstreamRouteFinder;
using Ocelot.Configuration.Builder;
using Ocelot.Headers;
using System.Net.Http;
using Ocelot.Authorisation.Middleware;
using Ocelot.Middleware;
namespace Ocelot.UnitTests.Headers
{
using Xunit;
using Ocelot.Logging;
using Ocelot.Headers.Middleware;
using TestStack.BDDfy;
using Microsoft.AspNetCore.Http;
using System.Collections.Generic;
using Moq;
using Ocelot.Configuration;
using Ocelot.DownstreamRouteFinder;
using Ocelot.Configuration.Builder;
using Ocelot.Headers;
using System.Net.Http;
using Ocelot.Authorisation.Middleware;
using Ocelot.Middleware;
using Ocelot.Middleware.Multiplexer;
using System.Threading.Tasks;
using Ocelot.Request.Middleware;
public class HttpHeadersTransformationMiddlewareTests
{
private Mock<IHttpContextRequestHeaderReplacer> _preReplacer;
private Mock<IHttpResponseHeaderReplacer> _postReplacer;
private readonly Mock<IHttpContextRequestHeaderReplacer> _preReplacer;
private readonly Mock<IHttpResponseHeaderReplacer> _postReplacer;
private Mock<IOcelotLoggerFactory> _loggerFactory;
private Mock<IOcelotLogger> _logger;
private HttpHeadersTransformationMiddleware _middleware;
private DownstreamContext _downstreamContext;
private readonly HttpHeadersTransformationMiddleware _middleware;
private readonly DownstreamContext _downstreamContext;
private OcelotRequestDelegate _next;
private Mock<IAddHeadersToResponse> _addHeaders;
private readonly Mock<IAddHeadersToResponse> _addHeaders;
public HttpHeadersTransformationMiddlewareTests()
{
@ -74,7 +74,7 @@ namespace Ocelot.UnitTests.Headers
private void GivenTheHttpResponseMessageIs()
{
_downstreamContext.DownstreamResponse = new HttpResponseMessage();
_downstreamContext.DownstreamResponse = new DownstreamResponse(new HttpResponseMessage());
}
private void GivenTheReRouteHasPreFindAndReplaceSetUp()
@ -98,7 +98,7 @@ namespace Ocelot.UnitTests.Headers
private void ThenTheIHttpResponseHeaderReplacerIsCalledCorrectly()
{
_postReplacer.Verify(x => x.Replace(It.IsAny<HttpResponseMessage>(), It.IsAny<List<HeaderFindAndReplace>>(), It.IsAny<DownstreamRequest>()), Times.Once);
_postReplacer.Verify(x => x.Replace(It.IsAny<DownstreamResponse>(), It.IsAny<List<HeaderFindAndReplace>>(), It.IsAny<DownstreamRequest>()), Times.Once);
}
private void GivenTheFollowingRequest()

View File

@ -7,19 +7,21 @@ using Ocelot.Configuration;
using System.Collections.Generic;
using Ocelot.Responses;
using System.Linq;
using System.Net;
using Moq;
using Ocelot.Infrastructure;
using Ocelot.Middleware;
using Ocelot.Infrastructure.RequestData;
using Ocelot.Middleware.Multiplexer;
using Ocelot.Request.Middleware;
namespace Ocelot.UnitTests.Headers
{
public class HttpResponseHeaderReplacerTests
{
private HttpResponseMessage _response;
private DownstreamResponse _response;
private Placeholders _placeholders;
private HttpResponseHeaderReplacer _replacer;
private readonly HttpResponseHeaderReplacer _replacer;
private List<HeaderFindAndReplace> _headerFindAndReplaces;
private Response _result;
private DownstreamRequest _request;
@ -37,11 +39,13 @@ namespace Ocelot.UnitTests.Headers
[Fact]
public void should_replace_headers()
{
var response = new HttpResponseMessage();
response.Headers.Add("test", "test");
var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted,
new List<KeyValuePair<string, IEnumerable<string>>>()
{
new KeyValuePair<string, IEnumerable<string>>("test", new List<string> {"test"})
});
var fAndRs = new List<HeaderFindAndReplace>();
fAndRs.Add(new HeaderFindAndReplace("test", "test", "chiken", 0));
var fAndRs = new List<HeaderFindAndReplace> {new HeaderFindAndReplace("test", "test", "chiken", 0)};
this.Given(x => GivenTheHttpResponse(response))
.And(x => GivenTheFollowingHeaderReplacements(fAndRs))
@ -53,8 +57,11 @@ namespace Ocelot.UnitTests.Headers
[Fact]
public void should_not_replace_headers()
{
var response = new HttpResponseMessage();
response.Headers.Add("test", "test");
var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted,
new List<KeyValuePair<string, IEnumerable<string>>>()
{
new KeyValuePair<string, IEnumerable<string>>("test", new List<string> {"test"})
});
var fAndRs = new List<HeaderFindAndReplace>();
@ -68,16 +75,21 @@ namespace Ocelot.UnitTests.Headers
[Fact]
public void should_replace_downstream_base_url_with_ocelot_base_url()
{
var downstreamUrl = "http://downstream.com/";
const string downstreamUrl = "http://downstream.com/";
var request = new HttpRequestMessage(HttpMethod.Get, "http://test.com");
request.RequestUri = new System.Uri(downstreamUrl);
var request =
new HttpRequestMessage(HttpMethod.Get, "http://test.com") {RequestUri = new System.Uri(downstreamUrl)};
var response = new HttpResponseMessage();
response.Headers.Add("Location", downstreamUrl);
var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted,
new List<KeyValuePair<string, IEnumerable<string>>>()
{
new KeyValuePair<string, IEnumerable<string>>("Location", new List<string> {downstreamUrl})
});
var fAndRs = new List<HeaderFindAndReplace>();
fAndRs.Add(new HeaderFindAndReplace("Location", "{DownstreamBaseUrl}", "http://ocelot.com/", 0));
var fAndRs = new List<HeaderFindAndReplace>
{
new HeaderFindAndReplace("Location", "{DownstreamBaseUrl}", "http://ocelot.com/", 0)
};
this.Given(x => GivenTheHttpResponse(response))
.And(x => GivenTheRequestIs(request))
@ -90,16 +102,21 @@ namespace Ocelot.UnitTests.Headers
[Fact]
public void should_replace_downstream_base_url_with_ocelot_base_url_with_port()
{
var downstreamUrl = "http://downstream.com/";
const string downstreamUrl = "http://downstream.com/";
var request = new HttpRequestMessage(HttpMethod.Get, "http://test.com");
request.RequestUri = new System.Uri(downstreamUrl);
var request =
new HttpRequestMessage(HttpMethod.Get, "http://test.com") {RequestUri = new System.Uri(downstreamUrl)};
var response = new HttpResponseMessage();
response.Headers.Add("Location", downstreamUrl);
var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted,
new List<KeyValuePair<string, IEnumerable<string>>>()
{
new KeyValuePair<string, IEnumerable<string>>("Location", new List<string> {downstreamUrl})
});
var fAndRs = new List<HeaderFindAndReplace>();
fAndRs.Add(new HeaderFindAndReplace("Location", "{DownstreamBaseUrl}", "http://ocelot.com:123/", 0));
var fAndRs = new List<HeaderFindAndReplace>
{
new HeaderFindAndReplace("Location", "{DownstreamBaseUrl}", "http://ocelot.com:123/", 0)
};
this.Given(x => GivenTheHttpResponse(response))
.And(x => GivenTheRequestIs(request))
@ -112,16 +129,21 @@ namespace Ocelot.UnitTests.Headers
[Fact]
public void should_replace_downstream_base_url_with_ocelot_base_url_and_path()
{
var downstreamUrl = "http://downstream.com/test/product";
const string downstreamUrl = "http://downstream.com/test/product";
var request = new HttpRequestMessage(HttpMethod.Get, "http://test.com");
request.RequestUri = new System.Uri(downstreamUrl);
var request =
new HttpRequestMessage(HttpMethod.Get, "http://test.com") {RequestUri = new System.Uri(downstreamUrl)};
var response = new HttpResponseMessage();
response.Headers.Add("Location", downstreamUrl);
var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted,
new List<KeyValuePair<string, IEnumerable<string>>>()
{
new KeyValuePair<string, IEnumerable<string>>("Location", new List<string> {downstreamUrl})
});
var fAndRs = new List<HeaderFindAndReplace>();
fAndRs.Add(new HeaderFindAndReplace("Location", "{DownstreamBaseUrl}", "http://ocelot.com/", 0));
var fAndRs = new List<HeaderFindAndReplace>
{
new HeaderFindAndReplace("Location", "{DownstreamBaseUrl}", "http://ocelot.com/", 0)
};
this.Given(x => GivenTheHttpResponse(response))
.And(x => GivenTheRequestIs(request))
@ -134,16 +156,21 @@ namespace Ocelot.UnitTests.Headers
[Fact]
public void should_replace_downstream_base_url_with_ocelot_base_url_with_path_and_port()
{
var downstreamUrl = "http://downstream.com/test/product";
const string downstreamUrl = "http://downstream.com/test/product";
var request = new HttpRequestMessage(HttpMethod.Get, "http://test.com");
request.RequestUri = new System.Uri(downstreamUrl);
var request =
new HttpRequestMessage(HttpMethod.Get, "http://test.com") {RequestUri = new System.Uri(downstreamUrl)};
var response = new HttpResponseMessage();
response.Headers.Add("Location", downstreamUrl);
var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted,
new List<KeyValuePair<string, IEnumerable<string>>>()
{
new KeyValuePair<string, IEnumerable<string>>("Location", new List<string> {downstreamUrl})
});
var fAndRs = new List<HeaderFindAndReplace>();
fAndRs.Add(new HeaderFindAndReplace("Location", "{DownstreamBaseUrl}", "http://ocelot.com:123/", 0));
var fAndRs = new List<HeaderFindAndReplace>
{
new HeaderFindAndReplace("Location", "{DownstreamBaseUrl}", "http://ocelot.com:123/", 0)
};
this.Given(x => GivenTheHttpResponse(response))
.And(x => GivenTheRequestIs(request))
@ -156,16 +183,21 @@ namespace Ocelot.UnitTests.Headers
[Fact]
public void should_replace_downstream_base_url_and_port_with_ocelot_base_url()
{
var downstreamUrl = "http://downstream.com:123/test/product";
const string downstreamUrl = "http://downstream.com:123/test/product";
var request = new HttpRequestMessage(HttpMethod.Get, "http://test.com");
request.RequestUri = new System.Uri(downstreamUrl);
var request =
new HttpRequestMessage(HttpMethod.Get, "http://test.com") {RequestUri = new System.Uri(downstreamUrl)};
var response = new HttpResponseMessage();
response.Headers.Add("Location", downstreamUrl);
var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted,
new List<KeyValuePair<string, IEnumerable<string>>>()
{
new KeyValuePair<string, IEnumerable<string>>("Location", new List<string> {downstreamUrl})
});
var fAndRs = new List<HeaderFindAndReplace>();
fAndRs.Add(new HeaderFindAndReplace("Location", "{DownstreamBaseUrl}", "http://ocelot.com/", 0));
var fAndRs = new List<HeaderFindAndReplace>
{
new HeaderFindAndReplace("Location", "{DownstreamBaseUrl}", "http://ocelot.com/", 0)
};
this.Given(x => GivenTheHttpResponse(response))
.And(x => GivenTheRequestIs(request))
@ -178,16 +210,21 @@ namespace Ocelot.UnitTests.Headers
[Fact]
public void should_replace_downstream_base_url_and_port_with_ocelot_base_url_and_port()
{
var downstreamUrl = "http://downstream.com:123/test/product";
const string downstreamUrl = "http://downstream.com:123/test/product";
var request = new HttpRequestMessage(HttpMethod.Get, "http://test.com");
request.RequestUri = new System.Uri(downstreamUrl);
var request =
new HttpRequestMessage(HttpMethod.Get, "http://test.com") {RequestUri = new System.Uri(downstreamUrl)};
var response = new HttpResponseMessage();
response.Headers.Add("Location", downstreamUrl);
var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted,
new List<KeyValuePair<string, IEnumerable<string>>>()
{
new KeyValuePair<string, IEnumerable<string>>("Location", new List<string> {downstreamUrl})
});
var fAndRs = new List<HeaderFindAndReplace>();
fAndRs.Add(new HeaderFindAndReplace("Location", "{DownstreamBaseUrl}", "http://ocelot.com:321/", 0));
var fAndRs = new List<HeaderFindAndReplace>
{
new HeaderFindAndReplace("Location", "{DownstreamBaseUrl}", "http://ocelot.com:321/", 0)
};
this.Given(x => GivenTheHttpResponse(response))
.And(x => GivenTheRequestIs(request))
@ -207,8 +244,8 @@ namespace Ocelot.UnitTests.Headers
_result.ShouldBeOfType<OkResponse>();
foreach (var f in _headerFindAndReplaces)
{
_response.Headers.TryGetValues(f.Key, out var values);
values.ToList()[f.Index].ShouldBe("test");
var values = _response.Headers.First(x => x.Key == f.Key);
values.Values.ToList()[f.Index].ShouldBe("test");
}
}
@ -217,7 +254,7 @@ namespace Ocelot.UnitTests.Headers
_headerFindAndReplaces = fAndRs;
}
private void GivenTheHttpResponse(HttpResponseMessage response)
private void GivenTheHttpResponse(DownstreamResponse response)
{
_response = response;
}
@ -229,17 +266,17 @@ namespace Ocelot.UnitTests.Headers
private void ThenTheHeaderShouldBe(string key, string value)
{
var test = _response.Headers.GetValues(key);
test.First().ShouldBe(value);
var test = _response.Headers.First(x => x.Key == key);
test.Values.First().ShouldBe(value);
}
private void ThenTheHeadersAreReplaced()
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);
var values = _response.Headers.First(x => x.Key == f.Key);
values.Values.ToList()[f.Index].ShouldBe(f.Replace);
}
}
}

View File

@ -1,5 +1,5 @@
using System.Net.Http;
using System.Net.Http.Headers;
using System.Collections.Generic;
using Ocelot.Middleware;
using Ocelot.Responses;
using Shouldly;
using TestStack.BDDfy;
@ -9,7 +9,7 @@ namespace Ocelot.UnitTests.Headers
{
public class RemoveHeadersTests
{
private HttpResponseHeaders _headers;
private List<Header> _headers;
private readonly Ocelot.Headers.RemoveOutputHeaders _removeOutputHeaders;
private Response _result;
@ -21,18 +21,18 @@ namespace Ocelot.UnitTests.Headers
[Fact]
public void should_remove_header()
{
var httpResponse = new HttpResponseMessage()
var headers = new List<Header>()
{
Headers = {{ "Transfer-Encoding", "chunked"}}
new Header("Transfer-Encoding", new List<string> {"chunked"})
};
this.Given(x => x.GivenAHttpContext(httpResponse.Headers))
this.Given(x => x.GivenAHttpContext(headers))
.When(x => x.WhenIRemoveTheHeaders())
.Then(x => x.TheHeaderIsNoLongerInTheContext())
.BDDfy();
}
private void GivenAHttpContext(HttpResponseHeaders headers)
private void GivenAHttpContext(List<Header> headers)
{
_headers = headers;
}

View File

@ -9,9 +9,9 @@ namespace Ocelot.UnitTests.Infrastructure
{
public class HttpDataRepositoryTests
{
private HttpContext _httpContext;
private readonly HttpContext _httpContext;
private IHttpContextAccessor _httpContextAccessor;
private HttpDataRepository _httpDataRepository;
private readonly HttpDataRepository _httpDataRepository;
private object _result;
public HttpDataRepositoryTests()

View File

@ -51,7 +51,6 @@ namespace Ocelot.UnitTests.Infrastructure
result.Data.ShouldBe("http://www.bbc.co.uk/");
}
[Fact]
public void should_return_downstream_base_url_when_port_is_80_or_443()
{
@ -80,4 +79,4 @@ namespace Ocelot.UnitTests.Infrastructure
result.Data.ShouldBe(traceId);
}
}
}
}

View File

@ -53,7 +53,6 @@ namespace Ocelot.UnitTests.Logging
[Fact]
public void should_log_error()
{
_logger.LogError($"a message from {_a} to {_b}", _ex);
ThenLevelIsLogged("requestId: no request id, previousRequestId: no previous request id, message: a message from tom to laura, exception: System.Exception: oh no", LogLevel.Error);

View File

@ -0,0 +1,86 @@
using Microsoft.Extensions.DependencyInjection;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Middleware.Multiplexer;
using Ocelot.Responses;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
using static Ocelot.UnitTests.Middleware.UserDefinedResponseAggregatorTests;
namespace Ocelot.UnitTests.Middleware
{
public class DefinedAggregatorProviderTests
{
private ServiceLocatorDefinedAggregatorProvider _provider;
private Response<IDefinedAggregator> _aggregator;
private ReRoute _reRoute;
[Fact]
public void should_find_aggregator()
{
var reRoute = new ReRouteBuilder()
.WithAggregator("TestDefinedAggregator")
.Build();
this.Given(_ => GivenDefinedAggregator())
.And(_ => GivenReRoute(reRoute))
.When(_ => WhenIGet())
.Then(_ => ThenTheAggregatorIsReturned())
.BDDfy();
}
[Fact]
public void should_not_find_aggregator()
{
var reRoute = new ReRouteBuilder()
.WithAggregator("TestDefinedAggregator")
.Build();
this.Given(_ => GivenNoDefinedAggregator())
.And(_ => GivenReRoute(reRoute))
.When(_ => WhenIGet())
.Then(_ => ThenAnErrorIsReturned())
.BDDfy();
}
private void GivenDefinedAggregator()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<IDefinedAggregator, TestDefinedAggregator>();
var services = serviceCollection.BuildServiceProvider();
_provider = new ServiceLocatorDefinedAggregatorProvider(services);
}
private void ThenTheAggregatorIsReturned()
{
_aggregator.Data.ShouldNotBeNull();
_aggregator.Data.ShouldBeOfType<TestDefinedAggregator>();
_aggregator.IsError.ShouldBeFalse();
}
private void GivenNoDefinedAggregator()
{
var serviceCollection = new ServiceCollection();
var services = serviceCollection.BuildServiceProvider();
_provider = new ServiceLocatorDefinedAggregatorProvider(services);
}
private void GivenReRoute(ReRoute reRoute)
{
_reRoute = reRoute;
}
private void WhenIGet()
{
_aggregator = _provider.Get(_reRoute);
}
private void ThenAnErrorIsReturned()
{
_aggregator.IsError.ShouldBeTrue();
_aggregator.Errors[0].Message.ShouldBe("Could not find Aggregator: TestDefinedAggregator");
_aggregator.Errors[0].ShouldBeOfType<CouldNotFindAggregatorError>();
}
}
}

View File

@ -19,13 +19,16 @@ namespace Ocelot.UnitTests.Middleware
private readonly OcelotRequestDelegate _pipeline;
private int _count;
private Mock<IResponseAggregator> _aggregator;
private Mock<IResponseAggregatorFactory> _factory;
public MultiplexerTests()
{
_factory = new Mock<IResponseAggregatorFactory>();
_aggregator = new Mock<IResponseAggregator>();
_context = new DownstreamContext(new DefaultHttpContext());
_pipeline = context => Task.FromResult(_count++);
_multiplexer = new Multiplexer(_aggregator.Object);
_factory.Setup(x => x.Get(It.IsAny<ReRoute>())).Returns(_aggregator.Object);
_multiplexer = new Multiplexer(_factory.Object);
}
[Fact]

View File

@ -62,7 +62,6 @@ namespace Ocelot.UnitTests.Middleware
{
_errors.Add(error);
}
}
public class FakeMiddleware : OcelotMiddleware
@ -72,4 +71,4 @@ namespace Ocelot.UnitTests.Middleware
{
}
}
}
}

View File

@ -0,0 +1,64 @@
namespace Ocelot.UnitTests.Middleware
{
using Moq;
using Ocelot.Configuration.Builder;
using Ocelot.Middleware.Multiplexer;
using Shouldly;
using Xunit;
using Ocelot.Configuration;
using TestStack.BDDfy;
public class ResponseAggregatorFactoryTests
{
private readonly InMemoryResponseAggregatorFactory _factory;
private Mock<IDefinedAggregatorProvider> _provider;
private ReRoute _reRoute;
private IResponseAggregator _aggregator;
public ResponseAggregatorFactoryTests()
{
_provider = new Mock<IDefinedAggregatorProvider>();
_factory = new InMemoryResponseAggregatorFactory(_provider.Object);
}
[Fact]
public void should_return_simple_json_aggregator()
{
var reRoute = new ReRouteBuilder()
.Build();
this.Given(_ => GivenReRoute(reRoute))
.When(_ => WhenIGet())
.Then(_ => ThenTheAggregatorIs<SimpleJsonResponseAggregator>())
.BDDfy();
}
[Fact]
public void should_return_user_defined_aggregator()
{
var reRoute = new ReRouteBuilder()
.WithAggregator("doesntmatter")
.Build();
this.Given(_ => GivenReRoute(reRoute))
.When(_ => WhenIGet())
.Then(_ => ThenTheAggregatorIs<UserDefinedResponseAggregator>())
.BDDfy();
}
private void GivenReRoute(ReRoute reRoute)
{
_reRoute = reRoute;
}
private void WhenIGet()
{
_aggregator = _factory.Get(_reRoute);
}
private void ThenTheAggregatorIs<T>()
{
_aggregator.ShouldBeOfType<T>();
}
}
}

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Text;
using Castle.Components.DictionaryAdapter;
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
@ -29,40 +30,6 @@ namespace Ocelot.UnitTests.Middleware
_aggregator = new SimpleJsonResponseAggregator();
}
[Fact]
public void should_map_all_downstream_to_upstream_when_not_aggregate()
{
var billDownstreamReRoute = new DownstreamReRouteBuilder().WithKey("Bill").Build();
var downstreamReRoutes = new List<DownstreamReRoute>
{
billDownstreamReRoute,
};
var reRoute = new ReRouteBuilder()
.WithDownstreamReRoutes(downstreamReRoutes)
.Build();
var billDownstreamContext = new DownstreamContext(new DefaultHttpContext())
{
DownstreamResponse =
new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent("Bill says hi") },
DownstreamReRoute = billDownstreamReRoute,
Errors = new List<Error> { new AnyError() },
DownstreamRequest = new DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, new Uri("http://www.bbc.co.uk"))),
};
var downstreamContexts = new List<DownstreamContext> { billDownstreamContext };
this.Given(x => GivenTheUpstreamContext(new DownstreamContext(new DefaultHttpContext())))
.And(x => GivenTheReRoute(reRoute))
.And(x => GivenTheDownstreamContext(downstreamContexts))
.When(x => WhenIAggregate())
.Then(x => ThenTheContentIs("Bill says hi"))
.And(x => ThenTheUpstreamContextIsMappedForNonAggregate())
.BDDfy();
}
[Fact]
public void should_aggregate_n_responses_and_set_response_content_on_upstream_context()
{
@ -82,15 +49,13 @@ namespace Ocelot.UnitTests.Middleware
var billDownstreamContext = new DownstreamContext(new DefaultHttpContext())
{
DownstreamResponse =
new HttpResponseMessage(HttpStatusCode.OK) {Content = new StringContent("Bill says hi")},
DownstreamResponse = new DownstreamResponse(new StringContent("Bill says hi"), HttpStatusCode.OK, new EditableList<KeyValuePair<string, IEnumerable<string>>>()),
DownstreamReRoute = billDownstreamReRoute
};
var georgeDownstreamContext = new DownstreamContext(new DefaultHttpContext())
{
DownstreamResponse =
new HttpResponseMessage(HttpStatusCode.OK) {Content = new StringContent("George says hi")},
DownstreamResponse = new DownstreamResponse(new StringContent("George says hi"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>()),
DownstreamReRoute = georgeDownstreamReRoute
};
@ -126,19 +91,18 @@ namespace Ocelot.UnitTests.Middleware
var billDownstreamContext = new DownstreamContext(new DefaultHttpContext())
{
DownstreamResponse =
new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent("Bill says hi") },
DownstreamResponse = new DownstreamResponse(new StringContent("Bill says hi"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>()),
DownstreamReRoute = billDownstreamReRoute
};
var georgeDownstreamContext = new DownstreamContext(new DefaultHttpContext())
{
DownstreamResponse =
new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent("Error") },
DownstreamResponse = new DownstreamResponse(new StringContent("Error"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>()),
DownstreamReRoute = georgeDownstreamReRoute,
Errors = new List<Error>() { new AnyError() }
};
georgeDownstreamContext.Errors.Add(new AnyError());
var downstreamContexts = new List<DownstreamContext> { billDownstreamContext, georgeDownstreamContext };
var expected = "Error";

View File

@ -0,0 +1,153 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Middleware;
using Ocelot.Middleware.Multiplexer;
using Ocelot.Responses;
using Ocelot.UnitTests.Responder;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Middleware
{
public class UserDefinedResponseAggregatorTests
{
private readonly UserDefinedResponseAggregator _aggregator;
private readonly Mock<IDefinedAggregatorProvider> _provider;
private ReRoute _reRoute;
private List<DownstreamContext> _contexts;
private DownstreamContext _context;
public UserDefinedResponseAggregatorTests()
{
_provider = new Mock<IDefinedAggregatorProvider>();
_aggregator = new UserDefinedResponseAggregator(_provider.Object);
}
[Fact]
public void should_call_aggregator()
{
var reRoute = new ReRouteBuilder().Build();
var context = new DownstreamContext(new DefaultHttpContext());
var contexts = new List<DownstreamContext>
{
new DownstreamContext(new DefaultHttpContext())
{
DownstreamResponse = new DownstreamResponse(new StringContent("Tom"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>())
},
new DownstreamContext(new DefaultHttpContext())
{
DownstreamResponse = new DownstreamResponse(new StringContent("Laura"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>())
}
};
this.Given(_ => GivenTheProviderReturnsAggregator())
.And(_ => GivenReRoute(reRoute))
.And(_ => GivenContexts(contexts))
.And(_ => GivenContext(context))
.When(_ => WhenIAggregate())
.Then(_ => ThenTheProviderIsCalled())
.And(_ => ThenTheContentIsCorrect())
.BDDfy();
}
[Fact]
public void should_not_find_aggregator()
{
var reRoute = new ReRouteBuilder().Build();
var context = new DownstreamContext(new DefaultHttpContext());
var contexts = new List<DownstreamContext>
{
new DownstreamContext(new DefaultHttpContext())
{
DownstreamResponse = new DownstreamResponse(new StringContent("Tom"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>())
},
new DownstreamContext(new DefaultHttpContext())
{
DownstreamResponse = new DownstreamResponse(new StringContent("Laura"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>())
}
};
this.Given(_ => GivenTheProviderReturnsError())
.And(_ => GivenReRoute(reRoute))
.And(_ => GivenContexts(contexts))
.And(_ => GivenContext(context))
.When(_ => WhenIAggregate())
.Then(_ => ThenTheProviderIsCalled())
.And(_ => ThenTheErrorIsReturned())
.BDDfy();
}
private void ThenTheErrorIsReturned()
{
_context.IsError.ShouldBeTrue();
_context.Errors.Count.ShouldBe(1);
}
private void GivenTheProviderReturnsError()
{
_provider.Setup(x => x.Get(It.IsAny<ReRoute>())).Returns(new ErrorResponse<IDefinedAggregator>(new AnyError()));
}
private async Task ThenTheContentIsCorrect()
{
var content = await _context.DownstreamResponse.Content.ReadAsStringAsync();
content.ShouldBe("Tom, Laura");
}
private void ThenTheProviderIsCalled()
{
_provider.Verify(x => x.Get(_reRoute), Times.Once);
}
private void GivenContext(DownstreamContext context)
{
_context = context;
}
private void GivenContexts(List<DownstreamContext> contexts)
{
_contexts = contexts;
}
private async Task WhenIAggregate()
{
await _aggregator.Aggregate(_reRoute, _context, _contexts);
}
private void GivenTheProviderReturnsAggregator()
{
var aggregator = new TestDefinedAggregator();
_provider.Setup(x => x.Get(It.IsAny<ReRoute>())).Returns(new OkResponse<IDefinedAggregator>(aggregator));
}
private void GivenReRoute(ReRoute reRoute)
{
_reRoute = reRoute;
}
public class TestDefinedAggregator : IDefinedAggregator
{
public async Task<DownstreamResponse> Aggregate(List<DownstreamResponse> responses)
{
var tom = await responses[0].Content.ReadAsStringAsync();
var laura = await responses[1].Content.ReadAsStringAsync();
var content = $"{tom}, {laura}";
var headers = responses.SelectMany(x => x.Headers).ToList();
return new DownstreamResponse(new StringContent(content), HttpStatusCode.OK, headers);
}
}
}
}

View File

@ -153,8 +153,6 @@ namespace Ocelot.UnitTests.QueryStrings
.AddQueryString(_downstreamRequest.ToHttpRequestMessage().RequestUri.OriginalString, key, value);
_request.RequestUri = new Uri(newUri);
//todo - might not need to instanciate
_downstreamRequest = new DownstreamRequest(_request);
}
private void GivenTheClaimParserReturns(Response<string> claimValue)

View File

@ -140,25 +140,28 @@ namespace Ocelot.UnitTests.Requester
.UseIISIntegration()
.Configure(app =>
{
app.Run(async context =>
app.Run(context =>
{
if (_count == 0)
{
context.Response.Cookies.Append("test", "0");
context.Response.StatusCode = 200;
_count++;
return;
return Task.CompletedTask;
}
if (_count == 1)
{
if (context.Request.Cookies.TryGetValue("test", out var cookieValue) || context.Request.Headers.TryGetValue("Set-Cookie", out var headerValue))
{
context.Response.StatusCode = 200;
return;
return Task.CompletedTask;
}
context.Response.StatusCode = 500;
}
return Task.CompletedTask;
});
})
.Build();
@ -200,6 +203,7 @@ namespace Ocelot.UnitTests.Requester
.Setup(x => x.Get(It.IsAny<DownstreamReRoute>()))
.Returns(new OkResponse<List<Func<DelegatingHandler>>>(handlers));
}
private void GivenTheFactoryReturnsNothing()
{
var handlers = new List<Func<DelegatingHandler>>();

View File

@ -1,6 +1,3 @@
using Ocelot.Configuration.Builder;
using Ocelot.Middleware;
namespace Ocelot.UnitTests.Requester
{
using Microsoft.AspNetCore.Http;
@ -14,11 +11,16 @@ namespace Ocelot.UnitTests.Requester
using Xunit;
using Shouldly;
using System.Threading.Tasks;
using Ocelot.Configuration.Builder;
using Ocelot.Middleware;
using System;
using System.Linq;
using Ocelot.UnitTests.Responder;
public class HttpRequesterMiddlewareTests
{
private readonly Mock<IHttpRequester> _requester;
private OkResponse<HttpResponseMessage> _response;
private Response<HttpResponseMessage> _response;
private Mock<IOcelotLoggerFactory> _loggerFactory;
private Mock<IOcelotLogger> _logger;
private readonly HttpRequesterMiddleware _middleware;
@ -39,12 +41,27 @@ namespace Ocelot.UnitTests.Requester
public void should_call_services_correctly()
{
this.Given(x => x.GivenTheRequestIs())
.And(x => x.GivenTheRequesterReturns(new HttpResponseMessage()))
.And(x => x.GivenTheRequesterReturns(new OkResponse<HttpResponseMessage>(new HttpResponseMessage())))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheScopedRepoIsCalledCorrectly())
.Then(x => x.ThenTheDownstreamResponseIsSet())
.BDDfy();
}
[Fact]
public void should_set_error()
{
this.Given(x => x.GivenTheRequestIs())
.And(x => x.GivenTheRequesterReturns(new ErrorResponse<HttpResponseMessage>(new AnyError())))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheErrorIsSet())
.BDDfy();
}
private void ThenTheErrorIsSet()
{
_downstreamContext.IsError.ShouldBeTrue();
}
private void WhenICallTheMiddleware()
{
_middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
@ -52,21 +69,34 @@ namespace Ocelot.UnitTests.Requester
private void GivenTheRequestIs()
{
_downstreamContext = new DownstreamContext(new DefaultHttpContext());
_downstreamContext.DownstreamReRoute = new DownstreamReRouteBuilder().Build();
_downstreamContext =
new DownstreamContext(new DefaultHttpContext())
{
DownstreamReRoute = new DownstreamReRouteBuilder().Build()
};
}
private void GivenTheRequesterReturns(HttpResponseMessage response)
private void GivenTheRequesterReturns(Response<HttpResponseMessage> response)
{
_response = new OkResponse<HttpResponseMessage>(response);
_response = response;
_requester
.Setup(x => x.GetResponse(It.IsAny<DownstreamContext>()))
.ReturnsAsync(_response);
}
private void ThenTheScopedRepoIsCalledCorrectly()
private void ThenTheDownstreamResponseIsSet()
{
_downstreamContext.DownstreamResponse.ShouldBe(_response.Data);
foreach (var httpResponseHeader in _response.Data.Headers)
{
if (_downstreamContext.DownstreamResponse.Headers.Any(x => x.Key == httpResponseHeader.Key))
{
throw new Exception("Header in response not in downstreamresponse headers");
}
}
_downstreamContext.DownstreamResponse.Content.ShouldBe(_response.Data.Content);
_downstreamContext.DownstreamResponse.StatusCode.ShouldBe(_response.Data.StatusCode);
}
}
}

View File

@ -120,7 +120,7 @@ namespace Ocelot.UnitTests.Responder
// If this test fails then it's because the number of error codes has changed.
// You should make the appropriate changes to the test cases here to ensure
// they cover all the error codes, and then modify this assertion.
Enum.GetNames(typeof(OcelotErrorCode)).Length.ShouldBe(34, "Looks like the number of error codes has changed. Do you need to modify ErrorsToHttpStatusCodeMapper?");
Enum.GetNames(typeof(OcelotErrorCode)).Length.ShouldBe(35, "Looks like the number of error codes has changed. Do you need to modify ErrorsToHttpStatusCodeMapper?");
}
private void ShouldMapErrorToStatusCode(OcelotErrorCode errorCode, HttpStatusCode expectedHttpStatusCode)

View File

@ -1,10 +1,11 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using Microsoft.AspNetCore.Http;
using Ocelot.Headers;
using Ocelot.Middleware;
using Ocelot.Middleware.Multiplexer;
using Ocelot.Responder;
using Shouldly;
using Xunit;
@ -26,9 +27,13 @@ namespace Ocelot.UnitTests.Responder
public void should_remove_transfer_encoding_header()
{
var httpContext = new DefaultHttpContext();
var httpResponseMessage = new HttpResponseMessage {Content = new StringContent("")};
httpResponseMessage.Headers.Add("Transfer-Encoding", "woop");
_responder.SetResponseOnHttpContext(httpContext, httpResponseMessage).GetAwaiter().GetResult();
var response = new DownstreamResponse(new StringContent(""), HttpStatusCode.OK,
new List<KeyValuePair<string, IEnumerable<string>>>
{
new KeyValuePair<string, IEnumerable<string>>("Transfer-Encoding", new List<string> {"woop"})
});
_responder.SetResponseOnHttpContext(httpContext, response).GetAwaiter().GetResult();
var header = httpContext.Response.Headers["Transfer-Encoding"];
header.ShouldBeEmpty();
}
@ -37,8 +42,10 @@ namespace Ocelot.UnitTests.Responder
public void should_have_content_length()
{
var httpContext = new DefaultHttpContext();
var httpResponseMessage = new HttpResponseMessage { Content = new StringContent("test") };
_responder.SetResponseOnHttpContext(httpContext, httpResponseMessage).GetAwaiter().GetResult();
var response = new DownstreamResponse(new StringContent("test"), HttpStatusCode.OK,
new List<KeyValuePair<string, IEnumerable<string>>>());
_responder.SetResponseOnHttpContext(httpContext, response).GetAwaiter().GetResult();
var header = httpContext.Response.Headers["Content-Length"];
header.First().ShouldBe("4");
}
@ -47,9 +54,13 @@ namespace Ocelot.UnitTests.Responder
public void should_add_header()
{
var httpContext = new DefaultHttpContext();
var httpResponseMessage = new HttpResponseMessage { Content = new StringContent("test") };
httpResponseMessage.Headers.Add("test", "test");
_responder.SetResponseOnHttpContext(httpContext, httpResponseMessage).GetAwaiter().GetResult();
var response = new DownstreamResponse(new StringContent(""), HttpStatusCode.OK,
new List<KeyValuePair<string, IEnumerable<string>>>
{
new KeyValuePair<string, IEnumerable<string>>("test", new List<string> {"test"})
});
_responder.SetResponseOnHttpContext(httpContext, response).GetAwaiter().GetResult();
var header = httpContext.Response.Headers["test"];
header.First().ShouldBe("test");
}

View File

@ -1,5 +1,6 @@
using System.Collections.Generic;
using Ocelot.Middleware;
using Ocelot.Middleware.Multiplexer;
namespace Ocelot.UnitTests.Responder
{
@ -40,8 +41,7 @@ namespace Ocelot.UnitTests.Responder
[Fact]
public void should_not_return_any_errors()
{
this.Given(x => x.GivenTheHttpResponseMessageIs(new HttpResponseMessage()))
.And(x => x.GivenThereAreNoPipelineErrors())
this.Given(x => x.GivenTheHttpResponseMessageIs(new DownstreamResponse(new HttpResponseMessage())))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenThereAreNoErrors())
.BDDfy();
@ -50,7 +50,7 @@ namespace Ocelot.UnitTests.Responder
[Fact]
public void should_return_any_errors()
{
this.Given(x => x.GivenTheHttpResponseMessageIs(new HttpResponseMessage()))
this.Given(x => x.GivenTheHttpResponseMessageIs(new DownstreamResponse(new HttpResponseMessage())))
.And(x => x.GivenThereArePipelineErrors(new UnableToFindDownstreamRouteError("/path", "GET")))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenThereAreNoErrors())
@ -62,16 +62,11 @@ namespace Ocelot.UnitTests.Responder
_middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
}
private void GivenTheHttpResponseMessageIs(HttpResponseMessage response)
private void GivenTheHttpResponseMessageIs(DownstreamResponse response)
{
_downstreamContext.DownstreamResponse = response;
}
private void GivenThereAreNoPipelineErrors()
{
_downstreamContext.Errors = new List<Error>();
}
private void ThenThereAreNoErrors()
{
//todo a better assert?
@ -79,7 +74,7 @@ namespace Ocelot.UnitTests.Responder
private void GivenThereArePipelineErrors(Error error)
{
_downstreamContext.Errors = new List<Error>(){error};
_downstreamContext.Errors.Add(error);
}
}
}