mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-04-22 06:22:50 +08:00
* #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:
parent
982eebfc74
commit
a15f75dda8
@ -5,12 +5,114 @@ Ocelot allow's you to specify Aggregate ReRoutes that compose multiple normal Re
|
|||||||
a client that is making multiple requests to a server where it could just be one. This feature allows you to start implementing back end for a front end type
|
a client that is making multiple requests to a server where it could just be one. This feature allows you to start implementing back end for a front end type
|
||||||
architecture with Ocelot.
|
architecture with Ocelot.
|
||||||
|
|
||||||
This feature was requested as part of `Issue 79 <https://github.com/TomPallister/Ocelot/pull/79>`_ .
|
This feature was requested as part of `Issue 79 <https://github.com/TomPallister/Ocelot/pull/79>`_ and further improvements were made as part of `Issue 298 <https://github.com/TomPallister/Ocelot/issue/298>`_.
|
||||||
|
|
||||||
In order to set this up you must do something like the following in your configuration.json. Here we have specified two normal ReRoutes and each one has a Key property.
|
In order to set this up you must do something like the following in your configuration.json. Here we have specified two normal ReRoutes and each one has a Key property.
|
||||||
We then specify an Aggregate that composes the two ReRoutes using their keys in the ReRouteKeys list and says then we have the UpstreamPathTemplate which works like a normal ReRoute.
|
We then specify an Aggregate that composes the two ReRoutes using their keys in the ReRouteKeys list and says then we have the UpstreamPathTemplate which works like a normal ReRoute.
|
||||||
Obviously you cannot have duplicate UpstreamPathTemplates between ReRoutes and Aggregates. You can use all of Ocelot's normal ReRoute options apart from RequestIdKey (explained in gotchas below).
|
Obviously you cannot have duplicate UpstreamPathTemplates between ReRoutes and Aggregates. You can use all of Ocelot's normal ReRoute options apart from RequestIdKey (explained in gotchas below).
|
||||||
|
|
||||||
|
Advanced register your own Aggregators
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Ocelot started with just the basic request aggregation and since then we have added a more advanced method that let's the user take in the responses from the
|
||||||
|
downstream services and then aggregate them into a response object.
|
||||||
|
|
||||||
|
The configuration.json setup is pretty much the same as the basic aggregation approach apart from you need to add an Aggregator property like below.
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"ReRoutes": [
|
||||||
|
{
|
||||||
|
"DownstreamPathTemplate": "/",
|
||||||
|
"UpstreamPathTemplate": "/laura",
|
||||||
|
"UpstreamHttpMethod": [
|
||||||
|
"Get"
|
||||||
|
],
|
||||||
|
"DownstreamScheme": "http",
|
||||||
|
"DownstreamHostAndPorts": [
|
||||||
|
{
|
||||||
|
"Host": "localhost",
|
||||||
|
"Port": 51881
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Key": "Laura"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"DownstreamPathTemplate": "/",
|
||||||
|
"UpstreamPathTemplate": "/tom",
|
||||||
|
"UpstreamHttpMethod": [
|
||||||
|
"Get"
|
||||||
|
],
|
||||||
|
"DownstreamScheme": "http",
|
||||||
|
"DownstreamHostAndPorts": [
|
||||||
|
{
|
||||||
|
"Host": "localhost",
|
||||||
|
"Port": 51882
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Key": "Tom"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Aggregates": [
|
||||||
|
{
|
||||||
|
"ReRouteKeys": [
|
||||||
|
"Tom",
|
||||||
|
"Laura"
|
||||||
|
],
|
||||||
|
"UpstreamPathTemplate": "/",
|
||||||
|
"Aggregator": "FakeDefinedAggregator"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Here we have added an aggregator called FakeDefinedAggregator. Ocelot is going to look for this aggregator when it tries to aggregate this ReRoute.
|
||||||
|
|
||||||
|
In order to make the aggregator available we must add the FakeDefinedAggregator to the OcelotBuilder like below.
|
||||||
|
|
||||||
|
.. code-block:: csharp
|
||||||
|
|
||||||
|
services
|
||||||
|
.AddOcelot()
|
||||||
|
.AddSingletonDefinedAggregator<FakeDefinedAggregator>();
|
||||||
|
|
||||||
|
Now when Ocelot tries to aggregate the ReRoute above it will find the FakeDefinedAggregator in the container and use it to aggregate the ReRoute.
|
||||||
|
Because the FakeDefinedAggregator is registered in the container you can add any dependencies it needs into the container like below.
|
||||||
|
|
||||||
|
.. code-block:: csharp
|
||||||
|
|
||||||
|
services.AddSingleton<FooDependency>();
|
||||||
|
|
||||||
|
services
|
||||||
|
.AddOcelot()
|
||||||
|
.AddSingletonDefinedAggregator<FooAggregator>();
|
||||||
|
|
||||||
|
In this example FooAggregator takes a dependency on FooDependency and it will be resolved by the container.
|
||||||
|
|
||||||
|
In addition to this Ocelot lets you add transient aggregators like below.
|
||||||
|
|
||||||
|
.. code-block:: csharp
|
||||||
|
|
||||||
|
services
|
||||||
|
.AddOcelot()
|
||||||
|
.AddTransientDefinedAggregator<FakeDefinedAggregator>();
|
||||||
|
|
||||||
|
In order to make an Aggregator you must implement this interface.
|
||||||
|
|
||||||
|
.. code-block:: csharp
|
||||||
|
|
||||||
|
public interface IDefinedAggregator
|
||||||
|
{
|
||||||
|
Task<DownstreamResponse> Aggregate(List<DownstreamResponse> responses);
|
||||||
|
}
|
||||||
|
|
||||||
|
With this feature you can pretty much do whatever you want because DownstreamResponse contains Content, Headers and Status Code. We can add extra things if needed
|
||||||
|
just raise an issue on GitHub. Please note if the HttpClient throws an exception when making a request to a ReRoute in the aggregate then you will not get a DownstreamResponse for
|
||||||
|
it but you would for any that succeed. If it does throw an exception this will be logged.
|
||||||
|
|
||||||
|
Basic expecting JSON from Downstream Services
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -65,9 +167,6 @@ If the ReRoute /tom returned a body of {"Age": 19} and /laura returned {"Age": 2
|
|||||||
|
|
||||||
{"Tom":{"Age": 19},"Laura":{"Age": 25}}
|
{"Tom":{"Age": 19},"Laura":{"Age": 25}}
|
||||||
|
|
||||||
Gotcha's / Further info
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
At the moment the aggregation is very simple. Ocelot just gets the response from your downstream service and sticks it into a json dictionary
|
At the moment the aggregation is very simple. Ocelot just gets the response from your downstream service and sticks it into a json dictionary
|
||||||
as above. With the ReRoute key being the key of the dictionary and the value the response body from your downstream service. You can see that the object is just
|
as above. With the ReRoute key being the key of the dictionary and the value the response body from your downstream service. You can see that the object is just
|
||||||
JSON without any pretty spaces etc.
|
JSON without any pretty spaces etc.
|
||||||
@ -76,20 +175,13 @@ All headers will be lost from the downstream services response.
|
|||||||
|
|
||||||
Ocelot will always return content type application/json with an aggregate request.
|
Ocelot will always return content type application/json with an aggregate request.
|
||||||
|
|
||||||
|
If you downstream services return a 404 the aggregate will just return nothing for that downstream service.
|
||||||
|
It will not change the aggregate response into a 404 even if all the downstreams return a 404.
|
||||||
|
|
||||||
|
Gotcha's / Further info
|
||||||
|
-----------------------
|
||||||
|
|
||||||
You cannot use ReRoutes with specific RequestIdKeys as this would be crazy complicated to track.
|
You cannot use ReRoutes with specific RequestIdKeys as this would be crazy complicated to track.
|
||||||
|
|
||||||
Aggregation only supports the GET HTTP Verb.
|
Aggregation only supports the GET HTTP Verb.
|
||||||
|
|
||||||
If you downstream services return a 404 the aggregate will just return nothing for that downstream service.
|
|
||||||
It will not change the aggregate response into a 404 even if all the downstreams return a 404.
|
|
||||||
|
|
||||||
Future
|
|
||||||
^^^^^^
|
|
||||||
|
|
||||||
There are loads of cool ways to enchance this such as..
|
|
||||||
|
|
||||||
What happens when downstream goes slow..should we timeout?
|
|
||||||
Can we do something like GraphQL where the user chooses what fields are returned?
|
|
||||||
Can we handle 404 better etc?
|
|
||||||
Can we make this not just support a JSON dictionary response?
|
|
||||||
|
|
||||||
|
@ -2,12 +2,10 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Ocelot.Infrastructure.RequestData;
|
|
||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
using Ocelot.Middleware;
|
using Ocelot.Middleware;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Ocelot.DownstreamRouteFinder.Middleware;
|
using Ocelot.Middleware.Multiplexer;
|
||||||
|
|
||||||
namespace Ocelot.Cache.Middleware
|
namespace Ocelot.Cache.Middleware
|
||||||
{
|
{
|
||||||
@ -72,38 +70,31 @@ namespace Ocelot.Cache.Middleware
|
|||||||
Logger.LogDebug($"finished response added to cache for {downstreamUrlKey}");
|
Logger.LogDebug($"finished response added to cache for {downstreamUrlKey}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetHttpResponseMessageThisRequest(DownstreamContext context, HttpResponseMessage response)
|
private void SetHttpResponseMessageThisRequest(DownstreamContext context, DownstreamResponse response)
|
||||||
{
|
{
|
||||||
context.DownstreamResponse = response;
|
context.DownstreamResponse = response;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal HttpResponseMessage CreateHttpResponseMessage(CachedResponse cached)
|
internal DownstreamResponse CreateHttpResponseMessage(CachedResponse cached)
|
||||||
{
|
{
|
||||||
if (cached == null)
|
if (cached == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var response = new HttpResponseMessage(cached.StatusCode);
|
|
||||||
|
|
||||||
foreach (var header in cached.Headers)
|
|
||||||
{
|
|
||||||
response.Headers.Add(header.Key, header.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
var content = new MemoryStream(Convert.FromBase64String(cached.Body));
|
var content = new MemoryStream(Convert.FromBase64String(cached.Body));
|
||||||
|
|
||||||
response.Content = new StreamContent(content);
|
var streamContent = new StreamContent(content);
|
||||||
|
|
||||||
foreach (var header in cached.ContentHeaders)
|
foreach (var header in cached.ContentHeaders)
|
||||||
{
|
{
|
||||||
response.Content.Headers.Add(header.Key, header.Value);
|
streamContent.Headers.Add(header.Key, header.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
return new DownstreamResponse(streamContent, cached.StatusCode, cached.Headers.ToList());
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task<CachedResponse> CreateCachedResponse(HttpResponseMessage response)
|
internal async Task<CachedResponse> CreateCachedResponse(DownstreamResponse response)
|
||||||
{
|
{
|
||||||
if (response == null)
|
if (response == null)
|
||||||
{
|
{
|
||||||
@ -111,7 +102,7 @@ namespace Ocelot.Cache.Middleware
|
|||||||
}
|
}
|
||||||
|
|
||||||
var statusCode = response.StatusCode;
|
var statusCode = response.StatusCode;
|
||||||
var headers = response.Headers.ToDictionary(v => v.Key, v => v.Value);
|
var headers = response.Headers.ToDictionary(v => v.Key, v => v.Values);
|
||||||
string body = null;
|
string body = null;
|
||||||
|
|
||||||
if (response.Content != null)
|
if (response.Content != null)
|
||||||
|
@ -14,6 +14,7 @@ namespace Ocelot.Configuration.Builder
|
|||||||
private List<HttpMethod> _upstreamHttpMethod;
|
private List<HttpMethod> _upstreamHttpMethod;
|
||||||
private string _upstreamHost;
|
private string _upstreamHost;
|
||||||
private List<DownstreamReRoute> _downstreamReRoutes;
|
private List<DownstreamReRoute> _downstreamReRoutes;
|
||||||
|
private string _aggregator;
|
||||||
|
|
||||||
public ReRouteBuilder()
|
public ReRouteBuilder()
|
||||||
{
|
{
|
||||||
@ -56,6 +57,12 @@ namespace Ocelot.Configuration.Builder
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ReRouteBuilder WithAggregator(string aggregator)
|
||||||
|
{
|
||||||
|
_aggregator = aggregator;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public ReRoute Build()
|
public ReRoute Build()
|
||||||
{
|
{
|
||||||
return new ReRoute(
|
return new ReRoute(
|
||||||
@ -63,7 +70,8 @@ namespace Ocelot.Configuration.Builder
|
|||||||
new PathTemplate(_upstreamTemplate),
|
new PathTemplate(_upstreamTemplate),
|
||||||
_upstreamHttpMethod,
|
_upstreamHttpMethod,
|
||||||
_upstreamTemplatePattern,
|
_upstreamTemplatePattern,
|
||||||
_upstreamHost
|
_upstreamHost,
|
||||||
|
_aggregator
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,6 +132,7 @@ namespace Ocelot.Configuration.Creator
|
|||||||
.WithUpstreamTemplatePattern(upstreamTemplatePattern)
|
.WithUpstreamTemplatePattern(upstreamTemplatePattern)
|
||||||
.WithDownstreamReRoutes(applicableReRoutes)
|
.WithDownstreamReRoutes(applicableReRoutes)
|
||||||
.WithUpstreamHost(aggregateReRoute.UpstreamHost)
|
.WithUpstreamHost(aggregateReRoute.UpstreamHost)
|
||||||
|
.WithAggregator(aggregateReRoute.Aggregator)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
return reRoute;
|
return reRoute;
|
||||||
|
@ -8,6 +8,7 @@ namespace Ocelot.Configuration.File
|
|||||||
public string UpstreamPathTemplate { get;set; }
|
public string UpstreamPathTemplate { get;set; }
|
||||||
public string UpstreamHost { get; set; }
|
public string UpstreamHost { get; set; }
|
||||||
public bool ReRouteIsCaseSensitive { get; set; }
|
public bool ReRouteIsCaseSensitive { get; set; }
|
||||||
|
public string Aggregator { get; set; }
|
||||||
|
|
||||||
// Only supports GET..are you crazy!! POST, PUT WOULD BE CRAZY!! :)
|
// Only supports GET..are you crazy!! POST, PUT WOULD BE CRAZY!! :)
|
||||||
public List<string> UpstreamHttpMethod
|
public List<string> UpstreamHttpMethod
|
||||||
|
@ -12,13 +12,15 @@ namespace Ocelot.Configuration
|
|||||||
PathTemplate upstreamPathTemplate,
|
PathTemplate upstreamPathTemplate,
|
||||||
List<HttpMethod> upstreamHttpMethod,
|
List<HttpMethod> upstreamHttpMethod,
|
||||||
UpstreamPathTemplate upstreamTemplatePattern,
|
UpstreamPathTemplate upstreamTemplatePattern,
|
||||||
string upstreamHost)
|
string upstreamHost,
|
||||||
|
string aggregator)
|
||||||
{
|
{
|
||||||
UpstreamHost = upstreamHost;
|
UpstreamHost = upstreamHost;
|
||||||
DownstreamReRoute = downstreamReRoute;
|
DownstreamReRoute = downstreamReRoute;
|
||||||
UpstreamPathTemplate = upstreamPathTemplate;
|
UpstreamPathTemplate = upstreamPathTemplate;
|
||||||
UpstreamHttpMethod = upstreamHttpMethod;
|
UpstreamHttpMethod = upstreamHttpMethod;
|
||||||
UpstreamTemplatePattern = upstreamTemplatePattern;
|
UpstreamTemplatePattern = upstreamTemplatePattern;
|
||||||
|
Aggregator = aggregator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PathTemplate UpstreamPathTemplate { get; private set; }
|
public PathTemplate UpstreamPathTemplate { get; private set; }
|
||||||
@ -26,5 +28,6 @@ namespace Ocelot.Configuration
|
|||||||
public List<HttpMethod> UpstreamHttpMethod { get; private set; }
|
public List<HttpMethod> UpstreamHttpMethod { get; private set; }
|
||||||
public string UpstreamHost { get; private set; }
|
public string UpstreamHost { get; private set; }
|
||||||
public List<DownstreamReRoute> DownstreamReRoute { get; private set; }
|
public List<DownstreamReRoute> DownstreamReRoute { get; private set; }
|
||||||
|
public string Aggregator {get; private set;}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ using CacheManager.Core;
|
|||||||
using System;
|
using System;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using IdentityServer4.AccessTokenValidation;
|
using IdentityServer4.AccessTokenValidation;
|
||||||
|
using Ocelot.Middleware.Multiplexer;
|
||||||
|
|
||||||
namespace Ocelot.DependencyInjection
|
namespace Ocelot.DependencyInjection
|
||||||
{
|
{
|
||||||
@ -23,5 +24,10 @@ namespace Ocelot.DependencyInjection
|
|||||||
|
|
||||||
IOcelotBuilder AddTransientDelegatingHandler<T>(bool global = false)
|
IOcelotBuilder AddTransientDelegatingHandler<T>(bool global = false)
|
||||||
where T : DelegatingHandler;
|
where T : DelegatingHandler;
|
||||||
|
|
||||||
|
IOcelotBuilder AddSingletonDefinedAggregator<T>()
|
||||||
|
where T : class, IDefinedAggregator;
|
||||||
|
IOcelotBuilder AddTransientDefinedAggregator<T>()
|
||||||
|
where T : class, IDefinedAggregator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,6 +154,8 @@ namespace Ocelot.DependencyInjection
|
|||||||
_services.TryAddSingleton<IAddHeadersToResponse, AddHeadersToResponse>();
|
_services.TryAddSingleton<IAddHeadersToResponse, AddHeadersToResponse>();
|
||||||
_services.TryAddSingleton<IPlaceholders, Placeholders>();
|
_services.TryAddSingleton<IPlaceholders, Placeholders>();
|
||||||
_services.TryAddSingleton<IConsulClientFactory, ConsulClientFactory>();
|
_services.TryAddSingleton<IConsulClientFactory, ConsulClientFactory>();
|
||||||
|
_services.TryAddSingleton<IResponseAggregatorFactory, InMemoryResponseAggregatorFactory>();
|
||||||
|
_services.TryAddSingleton<IDefinedAggregatorProvider, ServiceLocatorDefinedAggregatorProvider>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IOcelotAdministrationBuilder AddAdministration(string path, string secret)
|
public IOcelotAdministrationBuilder AddAdministration(string path, string secret)
|
||||||
@ -188,6 +190,20 @@ namespace Ocelot.DependencyInjection
|
|||||||
return new OcelotAdministrationBuilder(_services, _configurationRoot);
|
return new OcelotAdministrationBuilder(_services, _configurationRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IOcelotBuilder AddSingletonDefinedAggregator<T>()
|
||||||
|
where T : class, IDefinedAggregator
|
||||||
|
{
|
||||||
|
_services.AddSingleton<IDefinedAggregator, T>();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IOcelotBuilder AddTransientDefinedAggregator<T>()
|
||||||
|
where T : class, IDefinedAggregator
|
||||||
|
{
|
||||||
|
_services.AddTransient<IDefinedAggregator, T>();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public IOcelotBuilder AddSingletonDelegatingHandler<THandler>(bool global = false)
|
public IOcelotBuilder AddSingletonDelegatingHandler<THandler>(bool global = false)
|
||||||
where THandler : DelegatingHandler
|
where THandler : DelegatingHandler
|
||||||
{
|
{
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
PathTemplateDoesntStartWithForwardSlash,
|
PathTemplateDoesntStartWithForwardSlash,
|
||||||
FileValidationFailedError,
|
FileValidationFailedError,
|
||||||
UnableToFindDelegatingHandlerProviderError,
|
UnableToFindDelegatingHandlerProviderError,
|
||||||
CouldNotFindPlaceholderError
|
CouldNotFindPlaceholderError,
|
||||||
|
CouldNotFindAggregatorError
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
namespace Ocelot.Headers
|
namespace Ocelot.Headers
|
||||||
{
|
{
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net.Http;
|
|
||||||
using Ocelot.Configuration.Creator;
|
using Ocelot.Configuration.Creator;
|
||||||
using Ocelot.Infrastructure;
|
using Ocelot.Infrastructure;
|
||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
|
using Ocelot.Middleware;
|
||||||
|
|
||||||
public class AddHeadersToResponse : IAddHeadersToResponse
|
public class AddHeadersToResponse : IAddHeadersToResponse
|
||||||
{
|
{
|
||||||
@ -17,7 +17,7 @@ namespace Ocelot.Headers
|
|||||||
_placeholders = placeholders;
|
_placeholders = placeholders;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(List<AddHeader> addHeaders, HttpResponseMessage response)
|
public void Add(List<AddHeader> addHeaders, DownstreamResponse response)
|
||||||
{
|
{
|
||||||
foreach(var add in addHeaders)
|
foreach(var add in addHeaders)
|
||||||
{
|
{
|
||||||
@ -31,11 +31,11 @@ namespace Ocelot.Headers
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
response.Headers.TryAddWithoutValidation(add.Key, value.Data);
|
response.Headers.Add(new Header(add.Key, new List<string> { value.Data }));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
response.Headers.TryAddWithoutValidation(add.Key, add.Value);
|
response.Headers.Add(new Header(add.Key, new List<string> { add.Value }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
|
||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
using Ocelot.Infrastructure;
|
using Ocelot.Infrastructure;
|
||||||
using Ocelot.Infrastructure.Extensions;
|
using Ocelot.Infrastructure.Extensions;
|
||||||
|
using Ocelot.Middleware;
|
||||||
|
using Ocelot.Middleware.Multiplexer;
|
||||||
using Ocelot.Request.Middleware;
|
using Ocelot.Request.Middleware;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
|
|
||||||
@ -12,19 +12,21 @@ namespace Ocelot.Headers
|
|||||||
{
|
{
|
||||||
public class HttpResponseHeaderReplacer : IHttpResponseHeaderReplacer
|
public class HttpResponseHeaderReplacer : IHttpResponseHeaderReplacer
|
||||||
{
|
{
|
||||||
private IPlaceholders _placeholders;
|
private readonly IPlaceholders _placeholders;
|
||||||
|
|
||||||
public HttpResponseHeaderReplacer(IPlaceholders placeholders)
|
public HttpResponseHeaderReplacer(IPlaceholders placeholders)
|
||||||
{
|
{
|
||||||
_placeholders = placeholders;
|
_placeholders = placeholders;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Response Replace(HttpResponseMessage response, List<HeaderFindAndReplace> fAndRs, DownstreamRequest request)
|
public Response Replace(DownstreamResponse response, List<HeaderFindAndReplace> fAndRs, DownstreamRequest request)
|
||||||
{
|
{
|
||||||
foreach (var f in fAndRs)
|
foreach (var f in fAndRs)
|
||||||
{
|
{
|
||||||
|
var dict = response.Headers.ToDictionary(x => x.Key);
|
||||||
|
|
||||||
//if the response headers contain a matching find and replace
|
//if the response headers contain a matching find and replace
|
||||||
if(response.Headers.TryGetValues(f.Key, out var values))
|
if(dict.TryGetValue(f.Key, out var values))
|
||||||
{
|
{
|
||||||
//check to see if it is a placeholder in the find...
|
//check to see if it is a placeholder in the find...
|
||||||
var placeholderValue = _placeholders.Get(f.Find, request);
|
var placeholderValue = _placeholders.Get(f.Find, request);
|
||||||
@ -32,16 +34,17 @@ namespace Ocelot.Headers
|
|||||||
if(!placeholderValue.IsError)
|
if(!placeholderValue.IsError)
|
||||||
{
|
{
|
||||||
//if it is we need to get the value of the placeholder
|
//if it is we need to get the value of the placeholder
|
||||||
//var find = replacePlaceholder(httpRequestMessage);
|
var replaced = values.Values.ToList()[f.Index].Replace(placeholderValue.Data, f.Replace.LastCharAsForwardSlash());
|
||||||
var replaced = values.ToList()[f.Index].Replace(placeholderValue.Data, f.Replace.LastCharAsForwardSlash());
|
|
||||||
response.Headers.Remove(f.Key);
|
response.Headers.Remove(response.Headers.First(item => item.Key == f.Key));
|
||||||
response.Headers.Add(f.Key, replaced);
|
response.Headers.Add(new Header(f.Key, new List<string> { replaced }));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var replaced = values.ToList()[f.Index].Replace(f.Find, f.Replace);
|
var replaced = values.Values.ToList()[f.Index].Replace(f.Find, f.Replace);
|
||||||
response.Headers.Remove(f.Key);
|
|
||||||
response.Headers.Add(f.Key, replaced);
|
response.Headers.Remove(response.Headers.First(item => item.Key == f.Key));
|
||||||
|
response.Headers.Add(new Header(f.Key, new List<string> { replaced }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
|
using Ocelot.Middleware;
|
||||||
|
|
||||||
namespace Ocelot.Headers
|
namespace Ocelot.Headers
|
||||||
{
|
{
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net.Http;
|
|
||||||
using Ocelot.Configuration.Creator;
|
using Ocelot.Configuration.Creator;
|
||||||
|
using Ocelot.Middleware.Multiplexer;
|
||||||
|
|
||||||
public interface IAddHeadersToResponse
|
public interface IAddHeadersToResponse
|
||||||
{
|
{
|
||||||
void Add(List<AddHeader> addHeaders, HttpResponseMessage response);
|
void Add(List<AddHeader> addHeaders, DownstreamResponse response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net.Http;
|
|
||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
|
using Ocelot.Middleware;
|
||||||
|
using Ocelot.Middleware.Multiplexer;
|
||||||
using Ocelot.Request.Middleware;
|
using Ocelot.Request.Middleware;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
|
|
||||||
@ -8,6 +9,6 @@ namespace Ocelot.Headers
|
|||||||
{
|
{
|
||||||
public interface IHttpResponseHeaderReplacer
|
public interface IHttpResponseHeaderReplacer
|
||||||
{
|
{
|
||||||
Response Replace(HttpResponseMessage response, List<HeaderFindAndReplace> fAndRs, DownstreamRequest httpRequestMessage);
|
Response Replace(DownstreamResponse response, List<HeaderFindAndReplace> fAndRs, DownstreamRequest httpRequestMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,10 +1,12 @@
|
|||||||
using System.Net.Http.Headers;
|
using System.Collections.Generic;
|
||||||
|
using Ocelot.Middleware;
|
||||||
|
using Ocelot.Middleware.Multiplexer;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
|
|
||||||
namespace Ocelot.Headers
|
namespace Ocelot.Headers
|
||||||
{
|
{
|
||||||
public interface IRemoveOutputHeaders
|
public interface IRemoveOutputHeaders
|
||||||
{
|
{
|
||||||
Response Remove(HttpResponseHeaders headers);
|
Response Remove(List<Header> headers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Ocelot.DownstreamRouteFinder.Middleware;
|
|
||||||
using Ocelot.Infrastructure.RequestData;
|
|
||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
using Ocelot.Middleware;
|
using Ocelot.Middleware;
|
||||||
|
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
using System.Net.Http.Headers;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Ocelot.Middleware;
|
||||||
|
using Ocelot.Middleware.Multiplexer;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
|
|
||||||
namespace Ocelot.Headers
|
namespace Ocelot.Headers
|
||||||
@ -14,13 +17,10 @@ namespace Ocelot.Headers
|
|||||||
{
|
{
|
||||||
"Transfer-Encoding"
|
"Transfer-Encoding"
|
||||||
};
|
};
|
||||||
public Response Remove(HttpResponseHeaders headers)
|
|
||||||
{
|
|
||||||
foreach (var unsupported in _unsupportedRequestHeaders)
|
|
||||||
{
|
|
||||||
headers.Remove(unsupported);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public Response Remove(List<Header> headers)
|
||||||
|
{
|
||||||
|
headers.RemoveAll(x => _unsupportedRequestHeaders.Contains(x.Key));
|
||||||
return new OkResponse();
|
return new OkResponse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Http;
|
|||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
using Ocelot.DownstreamRouteFinder.UrlMatcher;
|
using Ocelot.DownstreamRouteFinder.UrlMatcher;
|
||||||
using Ocelot.Errors;
|
using Ocelot.Errors;
|
||||||
|
using Ocelot.Middleware.Multiplexer;
|
||||||
using Ocelot.Request.Middleware;
|
using Ocelot.Request.Middleware;
|
||||||
|
|
||||||
namespace Ocelot.Middleware
|
namespace Ocelot.Middleware
|
||||||
@ -27,9 +28,9 @@ namespace Ocelot.Middleware
|
|||||||
|
|
||||||
public DownstreamRequest DownstreamRequest { get; set; }
|
public DownstreamRequest DownstreamRequest { get; set; }
|
||||||
|
|
||||||
public HttpResponseMessage DownstreamResponse { get; set; }
|
public DownstreamResponse DownstreamResponse { get; set; }
|
||||||
|
|
||||||
public List<Error> Errors { get;set; }
|
public List<Error> Errors { get; }
|
||||||
|
|
||||||
public bool IsError => Errors.Count > 0;
|
public bool IsError => Errors.Count > 0;
|
||||||
}
|
}
|
||||||
|
31
src/Ocelot/Middleware/DownstreamResponse.cs
Normal file
31
src/Ocelot/Middleware/DownstreamResponse.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
|
||||||
|
namespace Ocelot.Middleware
|
||||||
|
{
|
||||||
|
public class DownstreamResponse
|
||||||
|
{
|
||||||
|
public DownstreamResponse(HttpContent content, HttpStatusCode statusCode, List<Header> headers)
|
||||||
|
{
|
||||||
|
Content = content;
|
||||||
|
StatusCode = statusCode;
|
||||||
|
Headers = headers ?? new List<Header>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DownstreamResponse(HttpResponseMessage response)
|
||||||
|
:this(response.Content, response.StatusCode, response.Headers.Select(x => new Header(x.Key, x.Value)).ToList())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DownstreamResponse(HttpContent content, HttpStatusCode statusCode, IEnumerable<KeyValuePair<string, IEnumerable<string>>> headers)
|
||||||
|
:this(content, statusCode, headers.Select(x => new Header(x.Key, x.Value)).ToList())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpContent Content { get; }
|
||||||
|
public HttpStatusCode StatusCode { get; }
|
||||||
|
public List<Header> Headers { get; }
|
||||||
|
}
|
||||||
|
}
|
16
src/Ocelot/Middleware/Header.cs
Normal file
16
src/Ocelot/Middleware/Header.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ocelot.Middleware
|
||||||
|
{
|
||||||
|
public class Header
|
||||||
|
{
|
||||||
|
public Header(string key, IEnumerable<string> values)
|
||||||
|
{
|
||||||
|
Key = key;
|
||||||
|
Values = values ?? new List<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Key { get; }
|
||||||
|
public IEnumerable<string> Values { get; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
using Ocelot.Errors;
|
||||||
|
|
||||||
|
namespace Ocelot.Middleware.Multiplexer
|
||||||
|
{
|
||||||
|
public class CouldNotFindAggregatorError : Error
|
||||||
|
{
|
||||||
|
public CouldNotFindAggregatorError(string aggregator)
|
||||||
|
: base($"Could not find Aggregator: {aggregator}", OcelotErrorCode.CouldNotFindAggregatorError)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
src/Ocelot/Middleware/Multiplexer/IDefinedAggregator.cs
Normal file
10
src/Ocelot/Middleware/Multiplexer/IDefinedAggregator.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ocelot.Middleware.Multiplexer
|
||||||
|
{
|
||||||
|
public interface IDefinedAggregator
|
||||||
|
{
|
||||||
|
Task<DownstreamResponse> Aggregate(List<DownstreamResponse> responses);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
using Ocelot.Configuration;
|
||||||
|
using Ocelot.Responses;
|
||||||
|
|
||||||
|
namespace Ocelot.Middleware.Multiplexer
|
||||||
|
{
|
||||||
|
public interface IDefinedAggregatorProvider
|
||||||
|
{
|
||||||
|
Response<IDefinedAggregator> Get(ReRoute reRoute);
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,6 @@ namespace Ocelot.Middleware.Multiplexer
|
|||||||
{
|
{
|
||||||
public interface IResponseAggregator
|
public interface IResponseAggregator
|
||||||
{
|
{
|
||||||
Task Aggregate(ReRoute reRoute, DownstreamContext originalContext, List<DownstreamContext> downstreamContexts);
|
Task Aggregate(ReRoute reRoute, DownstreamContext originalContext, List<DownstreamContext> downstreamResponses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
using Ocelot.Configuration;
|
||||||
|
|
||||||
|
namespace Ocelot.Middleware.Multiplexer
|
||||||
|
{
|
||||||
|
public interface IResponseAggregatorFactory
|
||||||
|
{
|
||||||
|
IResponseAggregator Get(ReRoute reRoute);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
using Ocelot.Configuration;
|
||||||
|
|
||||||
|
namespace Ocelot.Middleware.Multiplexer
|
||||||
|
{
|
||||||
|
public class InMemoryResponseAggregatorFactory : IResponseAggregatorFactory
|
||||||
|
{
|
||||||
|
private readonly UserDefinedResponseAggregator _userDefined;
|
||||||
|
private readonly SimpleJsonResponseAggregator _simple;
|
||||||
|
|
||||||
|
public InMemoryResponseAggregatorFactory(IDefinedAggregatorProvider provider)
|
||||||
|
{
|
||||||
|
_userDefined = new UserDefinedResponseAggregator(provider);
|
||||||
|
_simple = new SimpleJsonResponseAggregator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IResponseAggregator Get(ReRoute reRoute)
|
||||||
|
{
|
||||||
|
if(!string.IsNullOrEmpty(reRoute.Aggregator))
|
||||||
|
{
|
||||||
|
return _userDefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _simple;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
|
|
||||||
@ -6,11 +7,11 @@ namespace Ocelot.Middleware.Multiplexer
|
|||||||
{
|
{
|
||||||
public class Multiplexer : IMultiplexer
|
public class Multiplexer : IMultiplexer
|
||||||
{
|
{
|
||||||
private readonly IResponseAggregator _aggregator;
|
private readonly IResponseAggregatorFactory _factory;
|
||||||
|
|
||||||
public Multiplexer(IResponseAggregator aggregator)
|
public Multiplexer(IResponseAggregatorFactory factory)
|
||||||
{
|
{
|
||||||
_aggregator = aggregator;
|
_factory = factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Multiplex(DownstreamContext context, ReRoute reRoute, OcelotRequestDelegate next)
|
public async Task Multiplex(DownstreamContext context, ReRoute reRoute, OcelotRequestDelegate next)
|
||||||
@ -31,15 +32,40 @@ namespace Ocelot.Middleware.Multiplexer
|
|||||||
|
|
||||||
await Task.WhenAll(tasks);
|
await Task.WhenAll(tasks);
|
||||||
|
|
||||||
var downstreamContexts = new List<DownstreamContext>();
|
var contexts = new List<DownstreamContext>();
|
||||||
|
|
||||||
foreach (var task in tasks)
|
foreach (var task in tasks)
|
||||||
{
|
{
|
||||||
var finished = await task;
|
var finished = await task;
|
||||||
downstreamContexts.Add(finished);
|
contexts.Add(finished);
|
||||||
}
|
}
|
||||||
|
|
||||||
await _aggregator.Aggregate(reRoute, context, downstreamContexts);
|
await Map(reRoute, context, contexts);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Map(ReRoute reRoute, DownstreamContext context, List<DownstreamContext> contexts)
|
||||||
|
{
|
||||||
|
if (reRoute.DownstreamReRoute.Count > 1)
|
||||||
|
{
|
||||||
|
var aggregator = _factory.Get(reRoute);
|
||||||
|
await aggregator.Aggregate(reRoute, context, contexts);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MapNotAggregate(context, contexts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MapNotAggregate(DownstreamContext originalContext, List<DownstreamContext> downstreamContexts)
|
||||||
|
{
|
||||||
|
//assume at least one..if this errors then it will be caught by global exception handler
|
||||||
|
var finished = downstreamContexts.First();
|
||||||
|
|
||||||
|
originalContext.Errors.AddRange(finished.Errors);
|
||||||
|
|
||||||
|
originalContext.DownstreamRequest = finished.DownstreamRequest;
|
||||||
|
|
||||||
|
originalContext.DownstreamResponse = finished.DownstreamResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<DownstreamContext> Fire(DownstreamContext context, OcelotRequestDelegate next)
|
private async Task<DownstreamContext> Fire(DownstreamContext context, OcelotRequestDelegate next)
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Ocelot.Configuration;
|
||||||
|
using Ocelot.Responses;
|
||||||
|
|
||||||
|
namespace Ocelot.Middleware.Multiplexer
|
||||||
|
{
|
||||||
|
public class ServiceLocatorDefinedAggregatorProvider : IDefinedAggregatorProvider
|
||||||
|
{
|
||||||
|
private readonly Dictionary<string, IDefinedAggregator> _aggregators;
|
||||||
|
|
||||||
|
public ServiceLocatorDefinedAggregatorProvider(IServiceProvider services)
|
||||||
|
{
|
||||||
|
_aggregators = services.GetServices<IDefinedAggregator>().ToDictionary(x => x.GetType().Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Response<IDefinedAggregator> Get(ReRoute reRoute)
|
||||||
|
{
|
||||||
|
if(_aggregators.ContainsKey(reRoute.Aggregator))
|
||||||
|
{
|
||||||
|
return new OkResponse<IDefinedAggregator>(_aggregators[reRoute.Aggregator]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ErrorResponse<IDefinedAggregator>(new CouldNotFindAggregatorError(reRoute.Aggregator));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
@ -12,18 +11,6 @@ namespace Ocelot.Middleware.Multiplexer
|
|||||||
public class SimpleJsonResponseAggregator : IResponseAggregator
|
public class SimpleJsonResponseAggregator : IResponseAggregator
|
||||||
{
|
{
|
||||||
public async Task Aggregate(ReRoute reRoute, DownstreamContext originalContext, List<DownstreamContext> downstreamContexts)
|
public async Task Aggregate(ReRoute reRoute, DownstreamContext originalContext, List<DownstreamContext> downstreamContexts)
|
||||||
{
|
|
||||||
if (reRoute.DownstreamReRoute.Count > 1)
|
|
||||||
{
|
|
||||||
await MapAggregtes(originalContext, downstreamContexts);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MapNotAggregate(originalContext, downstreamContexts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task MapAggregtes(DownstreamContext originalContext, List<DownstreamContext> downstreamContexts)
|
|
||||||
{
|
{
|
||||||
await MapAggregateContent(originalContext, downstreamContexts);
|
await MapAggregateContent(originalContext, downstreamContexts);
|
||||||
}
|
}
|
||||||
@ -34,7 +21,7 @@ namespace Ocelot.Middleware.Multiplexer
|
|||||||
|
|
||||||
contentBuilder.Append("{");
|
contentBuilder.Append("{");
|
||||||
|
|
||||||
for (int i = 0; i < downstreamContexts.Count; i++)
|
for (var i = 0; i < downstreamContexts.Count; i++)
|
||||||
{
|
{
|
||||||
if (downstreamContexts[i].IsError)
|
if (downstreamContexts[i].IsError)
|
||||||
{
|
{
|
||||||
@ -54,13 +41,12 @@ namespace Ocelot.Middleware.Multiplexer
|
|||||||
|
|
||||||
contentBuilder.Append("}");
|
contentBuilder.Append("}");
|
||||||
|
|
||||||
originalContext.DownstreamResponse = new HttpResponseMessage(HttpStatusCode.OK)
|
var stringContent = new StringContent(contentBuilder.ToString())
|
||||||
{
|
{
|
||||||
Content = new StringContent(contentBuilder.ToString())
|
Headers = {ContentType = new MediaTypeHeaderValue("application/json")}
|
||||||
{
|
|
||||||
Headers = {ContentType = new MediaTypeHeaderValue("application/json")}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
originalContext.DownstreamResponse = new DownstreamResponse(stringContent, HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void MapAggregateError(DownstreamContext originalContext, List<DownstreamContext> downstreamContexts, int i)
|
private static void MapAggregateError(DownstreamContext originalContext, List<DownstreamContext> downstreamContexts, int i)
|
||||||
@ -68,17 +54,5 @@ namespace Ocelot.Middleware.Multiplexer
|
|||||||
originalContext.Errors.AddRange(downstreamContexts[i].Errors);
|
originalContext.Errors.AddRange(downstreamContexts[i].Errors);
|
||||||
originalContext.DownstreamResponse = downstreamContexts[i].DownstreamResponse;
|
originalContext.DownstreamResponse = downstreamContexts[i].DownstreamResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MapNotAggregate(DownstreamContext originalContext, List<DownstreamContext> downstreamContexts)
|
|
||||||
{
|
|
||||||
//assume at least one..if this errors then it will be caught by global exception handler
|
|
||||||
var finished = downstreamContexts.First();
|
|
||||||
|
|
||||||
originalContext.Errors = finished.Errors;
|
|
||||||
|
|
||||||
originalContext.DownstreamRequest = finished.DownstreamRequest;
|
|
||||||
|
|
||||||
originalContext.DownstreamResponse = finished.DownstreamResponse;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Ocelot.Configuration;
|
||||||
|
|
||||||
|
namespace Ocelot.Middleware.Multiplexer
|
||||||
|
{
|
||||||
|
public class UserDefinedResponseAggregator : IResponseAggregator
|
||||||
|
{
|
||||||
|
private readonly IDefinedAggregatorProvider _provider;
|
||||||
|
|
||||||
|
public UserDefinedResponseAggregator(IDefinedAggregatorProvider provider)
|
||||||
|
{
|
||||||
|
_provider = provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Aggregate(ReRoute reRoute, DownstreamContext originalContext, List<DownstreamContext> downstreamResponses)
|
||||||
|
{
|
||||||
|
var aggregator = _provider.Get(reRoute);
|
||||||
|
|
||||||
|
if (!aggregator.IsError)
|
||||||
|
{
|
||||||
|
var aggregateResponse = await aggregator.Data
|
||||||
|
.Aggregate(downstreamResponses.Select(x => x.DownstreamResponse).ToList());
|
||||||
|
|
||||||
|
originalContext.DownstreamResponse = aggregateResponse;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
originalContext.Errors.AddRange(aggregator.Errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -22,11 +22,6 @@
|
|||||||
|
|
||||||
public static class OcelotMiddlewareExtensions
|
public static class OcelotMiddlewareExtensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Registers the Ocelot default middlewares
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder)
|
public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder)
|
||||||
{
|
{
|
||||||
await builder.UseOcelot(new OcelotPipelineConfiguration());
|
await builder.UseOcelot(new OcelotPipelineConfiguration());
|
||||||
@ -34,12 +29,6 @@
|
|||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Registers Ocelot with a combination of default middlewares and optional middlewares in the configuration
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder"></param>
|
|
||||||
/// <param name="pipelineConfiguration"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder, OcelotPipelineConfiguration pipelineConfiguration)
|
public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder, OcelotPipelineConfiguration pipelineConfiguration)
|
||||||
{
|
{
|
||||||
var configuration = await CreateConfiguration(builder);
|
var configuration = await CreateConfiguration(builder);
|
||||||
@ -231,25 +220,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void UseIfNotNull(this IApplicationBuilder builder, Func<HttpContext, Func<Task>, Task> middleware)
|
private static void ConfigureDiagnosticListener(IApplicationBuilder builder)
|
||||||
{
|
{
|
||||||
if (middleware != null)
|
|
||||||
{
|
|
||||||
builder.Use(middleware);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Configure a DiagnosticListener to listen for diagnostic events when the middleware starts and ends
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder"></param>
|
|
||||||
private static void ConfigureDiagnosticListener(IApplicationBuilder builder)
|
|
||||||
{
|
|
||||||
var env = (IHostingEnvironment)builder.ApplicationServices.GetService(typeof(IHostingEnvironment));
|
var env = (IHostingEnvironment)builder.ApplicationServices.GetService(typeof(IHostingEnvironment));
|
||||||
var listener = (OcelotDiagnosticListener)builder.ApplicationServices.GetService(typeof(OcelotDiagnosticListener));
|
var listener = (OcelotDiagnosticListener)builder.ApplicationServices.GetService(typeof(OcelotDiagnosticListener));
|
||||||
var diagnosticListener = (DiagnosticListener)builder.ApplicationServices.GetService(typeof(DiagnosticListener));
|
var diagnosticListener = (DiagnosticListener)builder.ApplicationServices.GetService(typeof(DiagnosticListener));
|
||||||
diagnosticListener.SubscribeWithAdapter(listener);
|
diagnosticListener.SubscribeWithAdapter(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void OnShutdown(IApplicationBuilder app)
|
private static void OnShutdown(IApplicationBuilder app)
|
||||||
{
|
{
|
||||||
|
@ -5,9 +5,7 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Http.Extensions;
|
using Microsoft.AspNetCore.Http.Extensions;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
@ -83,7 +81,6 @@
|
|||||||
{
|
{
|
||||||
foreach (var header in request.Headers)
|
foreach (var header in request.Headers)
|
||||||
{
|
{
|
||||||
//todo get rid of if..
|
|
||||||
if (IsSupportedHeader(header))
|
if (IsSupportedHeader(header))
|
||||||
{
|
{
|
||||||
requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
|
requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Ocelot.Infrastructure.RequestData;
|
|
||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
using Ocelot.Middleware;
|
using Ocelot.Middleware;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Ocelot.DownstreamRouteFinder.Middleware;
|
|
||||||
using Ocelot.Requester.QoS;
|
|
||||||
|
|
||||||
namespace Ocelot.Requester.Middleware
|
namespace Ocelot.Requester.Middleware
|
||||||
{
|
{
|
||||||
@ -36,7 +32,7 @@ namespace Ocelot.Requester.Middleware
|
|||||||
|
|
||||||
Logger.LogDebug("setting http response message");
|
Logger.LogDebug("setting http response message");
|
||||||
|
|
||||||
context.DownstreamResponse = response.Data;
|
context.DownstreamResponse = new DownstreamResponse(response.Data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,14 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
using Ocelot.Headers;
|
using Ocelot.Headers;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Middleware;
|
||||||
|
|
||||||
namespace Ocelot.Responder
|
namespace Ocelot.Responder
|
||||||
{
|
{
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Cannot unit test things in this class due to methods not being implemented
|
/// Cannot unit test things in this class due to methods not being implemented
|
||||||
/// on .net concretes used for testing
|
/// on .net concretes used for testing
|
||||||
@ -25,7 +22,7 @@ namespace Ocelot.Responder
|
|||||||
_removeOutputHeaders = removeOutputHeaders;
|
_removeOutputHeaders = removeOutputHeaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SetResponseOnHttpContext(HttpContext context, HttpResponseMessage response)
|
public async Task SetResponseOnHttpContext(HttpContext context, DownstreamResponse response)
|
||||||
{
|
{
|
||||||
_removeOutputHeaders.Remove(response.Headers);
|
_removeOutputHeaders.Remove(response.Headers);
|
||||||
|
|
||||||
@ -36,12 +33,12 @@ namespace Ocelot.Responder
|
|||||||
|
|
||||||
foreach (var httpResponseHeader in response.Content.Headers)
|
foreach (var httpResponseHeader in response.Content.Headers)
|
||||||
{
|
{
|
||||||
AddHeaderIfDoesntExist(context, httpResponseHeader);
|
AddHeaderIfDoesntExist(context, new Header(httpResponseHeader.Key, httpResponseHeader.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
var content = await response.Content.ReadAsByteArrayAsync();
|
var content = await response.Content.ReadAsByteArrayAsync();
|
||||||
|
|
||||||
AddHeaderIfDoesntExist(context, new KeyValuePair<string, IEnumerable<string>>("Content-Length", new []{ content.Length.ToString() }) );
|
AddHeaderIfDoesntExist(context, new Header("Content-Length", new []{ content.Length.ToString() }) );
|
||||||
|
|
||||||
context.Response.OnStarting(state =>
|
context.Response.OnStarting(state =>
|
||||||
{
|
{
|
||||||
@ -70,11 +67,11 @@ namespace Ocelot.Responder
|
|||||||
}, context);
|
}, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AddHeaderIfDoesntExist(HttpContext context, KeyValuePair<string, IEnumerable<string>> httpResponseHeader)
|
private static void AddHeaderIfDoesntExist(HttpContext context, Header httpResponseHeader)
|
||||||
{
|
{
|
||||||
if (!context.Response.Headers.ContainsKey(httpResponseHeader.Key))
|
if (!context.Response.Headers.ContainsKey(httpResponseHeader.Key))
|
||||||
{
|
{
|
||||||
context.Response.Headers.Add(httpResponseHeader.Key, new StringValues(httpResponseHeader.Value.ToArray()));
|
context.Response.Headers.Add(httpResponseHeader.Key, new StringValues(httpResponseHeader.Values.ToArray()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
using System.Net.Http;
|
using System.Threading.Tasks;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Ocelot.Middleware;
|
||||||
|
using Ocelot.Middleware.Multiplexer;
|
||||||
|
|
||||||
namespace Ocelot.Responder
|
namespace Ocelot.Responder
|
||||||
{
|
{
|
||||||
public interface IHttpResponder
|
public interface IHttpResponder
|
||||||
{
|
{
|
||||||
Task SetResponseOnHttpContext(HttpContext context, HttpResponseMessage response);
|
Task SetResponseOnHttpContext(HttpContext context, DownstreamResponse response);
|
||||||
void SetErrorResponseOnContext(HttpContext context, int statusCode);
|
void SetErrorResponseOnContext(HttpContext context, int statusCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Ocelot.Errors;
|
using Ocelot.Errors;
|
||||||
using Ocelot.Infrastructure.RequestData;
|
|
||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
using Ocelot.Middleware;
|
using Ocelot.Middleware;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Ocelot.DownstreamRouteFinder.Middleware;
|
|
||||||
using Ocelot.Infrastructure.Extensions;
|
using Ocelot.Infrastructure.Extensions;
|
||||||
|
|
||||||
namespace Ocelot.Responder.Middleware
|
namespace Ocelot.Responder.Middleware
|
||||||
|
@ -1,11 +1,17 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Ocelot.Configuration.File;
|
using Ocelot.Configuration.File;
|
||||||
|
using Ocelot.Middleware;
|
||||||
|
using Ocelot.Middleware.Multiplexer;
|
||||||
using Shouldly;
|
using Shouldly;
|
||||||
using TestStack.BDDfy;
|
using TestStack.BDDfy;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
@ -15,6 +21,7 @@ namespace Ocelot.AcceptanceTests
|
|||||||
public class AggregateTests : IDisposable
|
public class AggregateTests : IDisposable
|
||||||
{
|
{
|
||||||
private IWebHost _serviceOneBuilder;
|
private IWebHost _serviceOneBuilder;
|
||||||
|
private IWebHost _serviceTwoBuilder;
|
||||||
private readonly Steps _steps;
|
private readonly Steps _steps;
|
||||||
private string _downstreamPathOne;
|
private string _downstreamPathOne;
|
||||||
private string _downstreamPathTwo;
|
private string _downstreamPathTwo;
|
||||||
@ -24,6 +31,75 @@ namespace Ocelot.AcceptanceTests
|
|||||||
_steps = new Steps();
|
_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]
|
[Fact]
|
||||||
public void should_return_response_200_with_simple_url()
|
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)
|
private void GivenServiceTwoIsRunning(string baseUrl, string basePath, int statusCode, string responseBody)
|
||||||
{
|
{
|
||||||
_serviceOneBuilder = new WebHostBuilder()
|
_serviceTwoBuilder = new WebHostBuilder()
|
||||||
.UseUrls(baseUrl)
|
.UseUrls(baseUrl)
|
||||||
.UseKestrel()
|
.UseKestrel()
|
||||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||||
@ -351,7 +427,7 @@ namespace Ocelot.AcceptanceTests
|
|||||||
})
|
})
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
_serviceOneBuilder.Start();
|
_serviceTwoBuilder.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void ThenTheDownstreamUrlPathShouldBe(string expectedDownstreamPathOne, string expectedDownstreamPath)
|
internal void ThenTheDownstreamUrlPathShouldBe(string expectedDownstreamPathOne, string expectedDownstreamPath)
|
||||||
@ -363,7 +439,33 @@ namespace Ocelot.AcceptanceTests
|
|||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_serviceOneBuilder?.Dispose();
|
_serviceOneBuilder?.Dispose();
|
||||||
|
_serviceTwoBuilder?.Dispose();
|
||||||
_steps.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,17 +91,17 @@ namespace Ocelot.AcceptanceTests
|
|||||||
|
|
||||||
var butterflyUrl = "http://localhost:9618";
|
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 => GivenServiceTwoIsRunning("http://localhost:51388", "/api/values", 200, "Hello from Tom", butterflyUrl))
|
||||||
.And(x => GivenFakeButterfly(butterflyUrl))
|
|
||||||
.And(x => _steps.GivenThereIsAConfiguration(configuration))
|
.And(x => _steps.GivenThereIsAConfiguration(configuration))
|
||||||
.And(x => _steps.GivenOcelotIsRunningUsingButterfly(butterflyUrl))
|
.And(x => _steps.GivenOcelotIsRunningUsingButterfly(butterflyUrl))
|
||||||
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/api001/values"))
|
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/api001/values"))
|
||||||
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
||||||
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
|
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
|
||||||
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/api002/values"))
|
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/api002/values"))
|
||||||
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
||||||
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Tom"))
|
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Tom"))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
|
|
||||||
var commandOnAllStateMachines = WaitFor(10000).Until(() => _butterflyCalled == 4);
|
var commandOnAllStateMachines = WaitFor(10000).Until(() => _butterflyCalled == 4);
|
||||||
@ -151,8 +151,8 @@ namespace Ocelot.AcceptanceTests
|
|||||||
|
|
||||||
var butterflyUrl = "http://localhost:9618";
|
var butterflyUrl = "http://localhost:9618";
|
||||||
|
|
||||||
this.Given(x => GivenServiceOneIsRunning("http://localhost:51387", "/api/values", 200, "Hello from Laura", butterflyUrl))
|
this.Given(x => GivenFakeButterfly(butterflyUrl))
|
||||||
.And(x => GivenFakeButterfly(butterflyUrl))
|
.And(x => GivenServiceOneIsRunning("http://localhost:51387", "/api/values", 200, "Hello from Laura", butterflyUrl))
|
||||||
.And(x => _steps.GivenThereIsAConfiguration(configuration))
|
.And(x => _steps.GivenThereIsAConfiguration(configuration))
|
||||||
.And(x => _steps.GivenOcelotIsRunningUsingButterfly(butterflyUrl))
|
.And(x => _steps.GivenOcelotIsRunningUsingButterfly(butterflyUrl))
|
||||||
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/api001/values"))
|
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/api001/values"))
|
||||||
|
@ -26,6 +26,7 @@ using System.IO.Compression;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using static Ocelot.AcceptanceTests.HttpDelegatingHandlersTests;
|
using static Ocelot.AcceptanceTests.HttpDelegatingHandlersTests;
|
||||||
using Ocelot.Requester;
|
using Ocelot.Requester;
|
||||||
|
using Ocelot.Middleware.Multiplexer;
|
||||||
|
|
||||||
namespace Ocelot.AcceptanceTests
|
namespace Ocelot.AcceptanceTests
|
||||||
{
|
{
|
||||||
@ -178,12 +179,6 @@ namespace Ocelot.AcceptanceTests
|
|||||||
_ocelotClient = _ocelotServer.CreateClient();
|
_ocelotClient = _ocelotServer.CreateClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
public void GivenIHaveAddedXForwardedForHeader(string value)
|
|
||||||
{
|
|
||||||
_ocelotClient.DefaultRequestHeaders.TryAddWithoutValidation("X-Forwarded-For", value);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
public void GivenOcelotIsRunningWithMiddleareBeforePipeline<T>(Func<object, Task> callback)
|
public void GivenOcelotIsRunningWithMiddleareBeforePipeline<T>(Func<object, Task> callback)
|
||||||
{
|
{
|
||||||
_webHostBuilder = new WebHostBuilder();
|
_webHostBuilder = new WebHostBuilder();
|
||||||
@ -246,6 +241,39 @@ namespace Ocelot.AcceptanceTests
|
|||||||
_ocelotClient = _ocelotServer.CreateClient();
|
_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>()
|
public void GivenOcelotIsRunningWithGlobalHandlersRegisteredInDi<TOne, TWo>()
|
||||||
where TOne : DelegatingHandler
|
where TOne : DelegatingHandler
|
||||||
where TWo : DelegatingHandler
|
where TWo : DelegatingHandler
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
using Ocelot.Errors;
|
namespace Ocelot.UnitTests.Cache
|
||||||
using Ocelot.Middleware;
|
|
||||||
|
|
||||||
namespace Ocelot.UnitTests.Cache
|
|
||||||
{
|
{
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
@ -17,15 +14,17 @@ namespace Ocelot.UnitTests.Cache
|
|||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
using Ocelot.Configuration.Builder;
|
using Ocelot.Configuration.Builder;
|
||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
|
using Ocelot.Middleware;
|
||||||
using TestStack.BDDfy;
|
using TestStack.BDDfy;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Ocelot.Middleware.Multiplexer;
|
||||||
|
|
||||||
public class OutputCacheMiddlewareRealCacheTests
|
public class OutputCacheMiddlewareRealCacheTests
|
||||||
{
|
{
|
||||||
private IOcelotCache<CachedResponse> _cacheManager;
|
private readonly IOcelotCache<CachedResponse> _cacheManager;
|
||||||
private OutputCacheMiddleware _middleware;
|
private readonly OutputCacheMiddleware _middleware;
|
||||||
private DownstreamContext _downstreamContext;
|
private readonly DownstreamContext _downstreamContext;
|
||||||
private OcelotRequestDelegate _next;
|
private OcelotRequestDelegate _next;
|
||||||
private Mock<IOcelotLoggerFactory> _loggerFactory;
|
private Mock<IOcelotLoggerFactory> _loggerFactory;
|
||||||
private IRegionCreator _regionCreator;
|
private IRegionCreator _regionCreator;
|
||||||
@ -56,14 +55,10 @@ namespace Ocelot.UnitTests.Cache
|
|||||||
Headers = { ContentType = new MediaTypeHeaderValue("application/json")}
|
Headers = { ContentType = new MediaTypeHeaderValue("application/json")}
|
||||||
};
|
};
|
||||||
|
|
||||||
var response = new HttpResponseMessage(HttpStatusCode.OK)
|
var response = new DownstreamResponse(content, HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>());
|
||||||
{
|
|
||||||
Content = content,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.Given(x => x.GivenResponseIsNotCached(response))
|
this.Given(x => x.GivenResponseIsNotCached(response))
|
||||||
.And(x => x.GivenTheDownstreamRouteIs())
|
.And(x => x.GivenTheDownstreamRouteIs())
|
||||||
.And(x => x.GivenThereAreNoErrors())
|
|
||||||
.When(x => x.WhenICallTheMiddleware())
|
.When(x => x.WhenICallTheMiddleware())
|
||||||
.Then(x => x.ThenTheContentTypeHeaderIsCached())
|
.Then(x => x.ThenTheContentTypeHeaderIsCached())
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
@ -81,9 +76,9 @@ namespace Ocelot.UnitTests.Cache
|
|||||||
header.First().ShouldBe("application/json");
|
header.First().ShouldBe("application/json");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenResponseIsNotCached(HttpResponseMessage message)
|
private void GivenResponseIsNotCached(DownstreamResponse response)
|
||||||
{
|
{
|
||||||
_downstreamContext.DownstreamResponse = message;
|
_downstreamContext.DownstreamResponse = response;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenTheDownstreamRouteIs()
|
private void GivenTheDownstreamRouteIs()
|
||||||
@ -96,10 +91,5 @@ namespace Ocelot.UnitTests.Cache
|
|||||||
|
|
||||||
_downstreamContext.DownstreamReRoute = reRoute;
|
_downstreamContext.DownstreamReRoute = reRoute;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenThereAreNoErrors()
|
|
||||||
{
|
|
||||||
_downstreamContext.Errors = new List<Error>();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
using System.Net;
|
namespace Ocelot.UnitTests.Cache
|
||||||
using Ocelot.Errors;
|
|
||||||
using Ocelot.Middleware;
|
|
||||||
|
|
||||||
namespace Ocelot.UnitTests.Cache
|
|
||||||
{
|
{
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -19,17 +15,20 @@ namespace Ocelot.UnitTests.Cache
|
|||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
using TestStack.BDDfy;
|
using TestStack.BDDfy;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
using System.Net;
|
||||||
|
using Ocelot.Middleware;
|
||||||
|
using Ocelot.Middleware.Multiplexer;
|
||||||
|
|
||||||
public class OutputCacheMiddlewareTests
|
public class OutputCacheMiddlewareTests
|
||||||
{
|
{
|
||||||
private readonly Mock<IOcelotCache<CachedResponse>> _cacheManager;
|
private readonly Mock<IOcelotCache<CachedResponse>> _cacheManager;
|
||||||
private Mock<IOcelotLoggerFactory> _loggerFactory;
|
private readonly Mock<IOcelotLoggerFactory> _loggerFactory;
|
||||||
private Mock<IOcelotLogger> _logger;
|
private Mock<IOcelotLogger> _logger;
|
||||||
private OutputCacheMiddleware _middleware;
|
private OutputCacheMiddleware _middleware;
|
||||||
private DownstreamContext _downstreamContext;
|
private readonly DownstreamContext _downstreamContext;
|
||||||
private OcelotRequestDelegate _next;
|
private readonly OcelotRequestDelegate _next;
|
||||||
private CachedResponse _response;
|
private CachedResponse _response;
|
||||||
private IRegionCreator _regionCreator;
|
private readonly IRegionCreator _regionCreator;
|
||||||
|
|
||||||
public OutputCacheMiddlewareTests()
|
public OutputCacheMiddlewareTests()
|
||||||
{
|
{
|
||||||
@ -46,7 +45,17 @@ namespace Ocelot.UnitTests.Cache
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void should_returned_cached_item_when_it_is_in_cache()
|
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))
|
this.Given(x => x.GivenThereIsACachedResponse(cachedResponse))
|
||||||
.And(x => x.GivenTheDownstreamRouteIs())
|
.And(x => x.GivenTheDownstreamRouteIs())
|
||||||
.When(x => x.WhenICallTheMiddleware())
|
.When(x => x.WhenICallTheMiddleware())
|
||||||
@ -59,7 +68,6 @@ namespace Ocelot.UnitTests.Cache
|
|||||||
{
|
{
|
||||||
this.Given(x => x.GivenResponseIsNotCached())
|
this.Given(x => x.GivenResponseIsNotCached())
|
||||||
.And(x => x.GivenTheDownstreamRouteIs())
|
.And(x => x.GivenTheDownstreamRouteIs())
|
||||||
.And(x => x.GivenThereAreNoErrors())
|
|
||||||
.When(x => x.WhenICallTheMiddleware())
|
.When(x => x.WhenICallTheMiddleware())
|
||||||
.Then(x => x.ThenTheCacheAddIsCalledCorrectly())
|
.Then(x => x.ThenTheCacheAddIsCalledCorrectly())
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
@ -81,7 +89,7 @@ namespace Ocelot.UnitTests.Cache
|
|||||||
|
|
||||||
private void GivenResponseIsNotCached()
|
private void GivenResponseIsNotCached()
|
||||||
{
|
{
|
||||||
_downstreamContext.DownstreamResponse = new HttpResponseMessage();
|
_downstreamContext.DownstreamResponse = new DownstreamResponse(new HttpResponseMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenTheDownstreamRouteIs()
|
private void GivenTheDownstreamRouteIs()
|
||||||
@ -101,11 +109,6 @@ namespace Ocelot.UnitTests.Cache
|
|||||||
_downstreamContext.DownstreamReRoute = downstreamRoute.ReRoute.DownstreamReRoute[0];
|
_downstreamContext.DownstreamReRoute = downstreamRoute.ReRoute.DownstreamReRoute[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenThereAreNoErrors()
|
|
||||||
{
|
|
||||||
_downstreamContext.Errors = new List<Error>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ThenTheCacheGetIsCalledCorrectly()
|
private void ThenTheCacheGetIsCalledCorrectly()
|
||||||
{
|
{
|
||||||
_cacheManager
|
_cacheManager
|
||||||
|
@ -134,7 +134,8 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
{
|
{
|
||||||
"Tom",
|
"Tom",
|
||||||
"Laura"
|
"Laura"
|
||||||
}
|
},
|
||||||
|
Aggregator = "asdf"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -150,7 +150,6 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_add_trace_id_header()
|
public void should_add_trace_id_header()
|
||||||
{
|
{
|
||||||
|
@ -18,6 +18,8 @@ using Shouldly;
|
|||||||
using IdentityServer4.AccessTokenValidation;
|
using IdentityServer4.AccessTokenValidation;
|
||||||
using TestStack.BDDfy;
|
using TestStack.BDDfy;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
using static Ocelot.UnitTests.Middleware.UserDefinedResponseAggregatorTests;
|
||||||
|
using Ocelot.Middleware.Multiplexer;
|
||||||
|
|
||||||
namespace Ocelot.UnitTests.DependencyInjection
|
namespace Ocelot.UnitTests.DependencyInjection
|
||||||
{
|
{
|
||||||
@ -177,6 +179,40 @@ namespace Ocelot.UnitTests.DependencyInjection
|
|||||||
.BDDfy();
|
.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()
|
private void ThenTheSpecificHandlersAreSingleton()
|
||||||
{
|
{
|
||||||
var handlers = _serviceProvider.GetServices<DelegatingHandler>().ToList();
|
var handlers = _serviceProvider.GetServices<DelegatingHandler>().ToList();
|
||||||
@ -258,6 +294,32 @@ namespace Ocelot.UnitTests.DependencyInjection
|
|||||||
handlers[1].ShouldBeOfType<TWo>();
|
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()
|
private void OnlyOneVersionOfEachCacheIsRegistered()
|
||||||
{
|
{
|
||||||
var outputCache = _services.Single(x => x.ServiceType == typeof(IOcelotCache<CachedResponse>));
|
var outputCache = _services.Single(x => x.ServiceType == typeof(IOcelotCache<CachedResponse>));
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
using Ocelot.Configuration;
|
namespace Ocelot.UnitTests.DownstreamUrlCreator
|
||||||
using Ocelot.Middleware;
|
|
||||||
|
|
||||||
namespace Ocelot.UnitTests.DownstreamUrlCreator
|
|
||||||
{
|
{
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -21,17 +18,19 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator
|
|||||||
using Shouldly;
|
using Shouldly;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Ocelot.Request.Middleware;
|
using Ocelot.Request.Middleware;
|
||||||
|
using Ocelot.Configuration;
|
||||||
|
using Ocelot.Middleware;
|
||||||
|
|
||||||
public class DownstreamUrlCreatorMiddlewareTests
|
public class DownstreamUrlCreatorMiddlewareTests
|
||||||
{
|
{
|
||||||
private readonly Mock<IDownstreamPathPlaceholderReplacer> _downstreamUrlTemplateVariableReplacer;
|
private readonly Mock<IDownstreamPathPlaceholderReplacer> _downstreamUrlTemplateVariableReplacer;
|
||||||
private OkResponse<DownstreamPath> _downstreamPath;
|
private OkResponse<DownstreamPath> _downstreamPath;
|
||||||
private Mock<IOcelotLoggerFactory> _loggerFactory;
|
private readonly Mock<IOcelotLoggerFactory> _loggerFactory;
|
||||||
private Mock<IOcelotLogger> _logger;
|
private Mock<IOcelotLogger> _logger;
|
||||||
private DownstreamUrlCreatorMiddleware _middleware;
|
private DownstreamUrlCreatorMiddleware _middleware;
|
||||||
private DownstreamContext _downstreamContext;
|
private readonly DownstreamContext _downstreamContext;
|
||||||
private OcelotRequestDelegate _next;
|
private readonly OcelotRequestDelegate _next;
|
||||||
private HttpRequestMessage _request;
|
private readonly HttpRequestMessage _request;
|
||||||
|
|
||||||
public DownstreamUrlCreatorMiddlewareTests()
|
public DownstreamUrlCreatorMiddlewareTests()
|
||||||
{
|
{
|
||||||
@ -212,7 +211,6 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator
|
|||||||
private void GivenTheDownstreamRequestUriIs(string uri)
|
private void GivenTheDownstreamRequestUriIs(string uri)
|
||||||
{
|
{
|
||||||
_request.RequestUri = new Uri(uri);
|
_request.RequestUri = new Uri(uri);
|
||||||
//todo - not sure if needed
|
|
||||||
_downstreamContext.DownstreamRequest = new DownstreamRequest(_request);
|
_downstreamContext.DownstreamRequest = new DownstreamRequest(_request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,29 +1,29 @@
|
|||||||
using Xunit;
|
using Xunit;
|
||||||
using Shouldly;
|
|
||||||
using TestStack.BDDfy;
|
using TestStack.BDDfy;
|
||||||
using Ocelot.Headers;
|
using Ocelot.Headers;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Ocelot.Configuration.Creator;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Ocelot.Configuration.Creator;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Ocelot.Infrastructure.RequestData;
|
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
using Ocelot.Infrastructure;
|
using Ocelot.Infrastructure;
|
||||||
using Ocelot.UnitTests.Responder;
|
using Ocelot.UnitTests.Responder;
|
||||||
using System;
|
|
||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
|
using Ocelot.Middleware;
|
||||||
|
using Ocelot.Middleware.Multiplexer;
|
||||||
|
using Shouldly;
|
||||||
|
|
||||||
namespace Ocelot.UnitTests.Headers
|
namespace Ocelot.UnitTests.Headers
|
||||||
{
|
{
|
||||||
public class AddHeadersToResponseTests
|
public class AddHeadersToResponseTests
|
||||||
{
|
{
|
||||||
private IAddHeadersToResponse _adder;
|
private readonly IAddHeadersToResponse _adder;
|
||||||
private Mock<IPlaceholders> _placeholders;
|
private readonly Mock<IPlaceholders> _placeholders;
|
||||||
private HttpResponseMessage _response;
|
private DownstreamResponse _response;
|
||||||
private List<AddHeader> _addHeaders;
|
private List<AddHeader> _addHeaders;
|
||||||
private Mock<IOcelotLoggerFactory> _factory;
|
private Mock<IOcelotLoggerFactory> _factory;
|
||||||
private Mock<IOcelotLogger> _logger;
|
private readonly Mock<IOcelotLogger> _logger;
|
||||||
|
|
||||||
public AddHeadersToResponseTests()
|
public AddHeadersToResponseTests()
|
||||||
{
|
{
|
||||||
@ -111,7 +111,7 @@ namespace Ocelot.UnitTests.Headers
|
|||||||
|
|
||||||
private void ThenTheHeaderIsNotAdded(string key)
|
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)
|
private void GivenTheTraceIdIs(string traceId)
|
||||||
@ -126,8 +126,8 @@ namespace Ocelot.UnitTests.Headers
|
|||||||
|
|
||||||
private void ThenTheHeaderIsReturned(string key, string value)
|
private void ThenTheHeaderIsReturned(string key, string value)
|
||||||
{
|
{
|
||||||
var values = _response.Headers.GetValues(key);
|
var values = _response.Headers.First(x => x.Key == key);
|
||||||
values.First().ShouldBe(value);
|
values.Values.First().ShouldBe(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WhenIAdd()
|
private void WhenIAdd()
|
||||||
@ -137,7 +137,7 @@ namespace Ocelot.UnitTests.Headers
|
|||||||
|
|
||||||
private void GivenAResponseMessage()
|
private void GivenAResponseMessage()
|
||||||
{
|
{
|
||||||
_response = new HttpResponseMessage();
|
_response = new DownstreamResponse(new HttpResponseMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenTheAddHeaders(List<AddHeader> addHeaders)
|
private void GivenTheAddHeaders(List<AddHeader> addHeaders)
|
||||||
|
@ -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
|
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 System.Threading.Tasks;
|
||||||
using Ocelot.Request.Middleware;
|
using Ocelot.Request.Middleware;
|
||||||
|
|
||||||
public class HttpHeadersTransformationMiddlewareTests
|
public class HttpHeadersTransformationMiddlewareTests
|
||||||
{
|
{
|
||||||
private Mock<IHttpContextRequestHeaderReplacer> _preReplacer;
|
private readonly Mock<IHttpContextRequestHeaderReplacer> _preReplacer;
|
||||||
private Mock<IHttpResponseHeaderReplacer> _postReplacer;
|
private readonly Mock<IHttpResponseHeaderReplacer> _postReplacer;
|
||||||
private Mock<IOcelotLoggerFactory> _loggerFactory;
|
private Mock<IOcelotLoggerFactory> _loggerFactory;
|
||||||
private Mock<IOcelotLogger> _logger;
|
private Mock<IOcelotLogger> _logger;
|
||||||
private HttpHeadersTransformationMiddleware _middleware;
|
private readonly HttpHeadersTransformationMiddleware _middleware;
|
||||||
private DownstreamContext _downstreamContext;
|
private readonly DownstreamContext _downstreamContext;
|
||||||
private OcelotRequestDelegate _next;
|
private OcelotRequestDelegate _next;
|
||||||
private Mock<IAddHeadersToResponse> _addHeaders;
|
private readonly Mock<IAddHeadersToResponse> _addHeaders;
|
||||||
|
|
||||||
public HttpHeadersTransformationMiddlewareTests()
|
public HttpHeadersTransformationMiddlewareTests()
|
||||||
{
|
{
|
||||||
@ -74,7 +74,7 @@ namespace Ocelot.UnitTests.Headers
|
|||||||
|
|
||||||
private void GivenTheHttpResponseMessageIs()
|
private void GivenTheHttpResponseMessageIs()
|
||||||
{
|
{
|
||||||
_downstreamContext.DownstreamResponse = new HttpResponseMessage();
|
_downstreamContext.DownstreamResponse = new DownstreamResponse(new HttpResponseMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenTheReRouteHasPreFindAndReplaceSetUp()
|
private void GivenTheReRouteHasPreFindAndReplaceSetUp()
|
||||||
@ -98,7 +98,7 @@ namespace Ocelot.UnitTests.Headers
|
|||||||
|
|
||||||
private void ThenTheIHttpResponseHeaderReplacerIsCalledCorrectly()
|
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()
|
private void GivenTheFollowingRequest()
|
||||||
|
@ -7,19 +7,21 @@ using Ocelot.Configuration;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Ocelot.Infrastructure;
|
using Ocelot.Infrastructure;
|
||||||
using Ocelot.Middleware;
|
using Ocelot.Middleware;
|
||||||
using Ocelot.Infrastructure.RequestData;
|
using Ocelot.Infrastructure.RequestData;
|
||||||
|
using Ocelot.Middleware.Multiplexer;
|
||||||
using Ocelot.Request.Middleware;
|
using Ocelot.Request.Middleware;
|
||||||
|
|
||||||
namespace Ocelot.UnitTests.Headers
|
namespace Ocelot.UnitTests.Headers
|
||||||
{
|
{
|
||||||
public class HttpResponseHeaderReplacerTests
|
public class HttpResponseHeaderReplacerTests
|
||||||
{
|
{
|
||||||
private HttpResponseMessage _response;
|
private DownstreamResponse _response;
|
||||||
private Placeholders _placeholders;
|
private Placeholders _placeholders;
|
||||||
private HttpResponseHeaderReplacer _replacer;
|
private readonly HttpResponseHeaderReplacer _replacer;
|
||||||
private List<HeaderFindAndReplace> _headerFindAndReplaces;
|
private List<HeaderFindAndReplace> _headerFindAndReplaces;
|
||||||
private Response _result;
|
private Response _result;
|
||||||
private DownstreamRequest _request;
|
private DownstreamRequest _request;
|
||||||
@ -37,11 +39,13 @@ namespace Ocelot.UnitTests.Headers
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void should_replace_headers()
|
public void should_replace_headers()
|
||||||
{
|
{
|
||||||
var response = new HttpResponseMessage();
|
var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted,
|
||||||
response.Headers.Add("test", "test");
|
new List<KeyValuePair<string, IEnumerable<string>>>()
|
||||||
|
{
|
||||||
|
new KeyValuePair<string, IEnumerable<string>>("test", new List<string> {"test"})
|
||||||
|
});
|
||||||
|
|
||||||
var fAndRs = new List<HeaderFindAndReplace>();
|
var fAndRs = new List<HeaderFindAndReplace> {new HeaderFindAndReplace("test", "test", "chiken", 0)};
|
||||||
fAndRs.Add(new HeaderFindAndReplace("test", "test", "chiken", 0));
|
|
||||||
|
|
||||||
this.Given(x => GivenTheHttpResponse(response))
|
this.Given(x => GivenTheHttpResponse(response))
|
||||||
.And(x => GivenTheFollowingHeaderReplacements(fAndRs))
|
.And(x => GivenTheFollowingHeaderReplacements(fAndRs))
|
||||||
@ -53,8 +57,11 @@ namespace Ocelot.UnitTests.Headers
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void should_not_replace_headers()
|
public void should_not_replace_headers()
|
||||||
{
|
{
|
||||||
var response = new HttpResponseMessage();
|
var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted,
|
||||||
response.Headers.Add("test", "test");
|
new List<KeyValuePair<string, IEnumerable<string>>>()
|
||||||
|
{
|
||||||
|
new KeyValuePair<string, IEnumerable<string>>("test", new List<string> {"test"})
|
||||||
|
});
|
||||||
|
|
||||||
var fAndRs = new List<HeaderFindAndReplace>();
|
var fAndRs = new List<HeaderFindAndReplace>();
|
||||||
|
|
||||||
@ -68,16 +75,21 @@ namespace Ocelot.UnitTests.Headers
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void should_replace_downstream_base_url_with_ocelot_base_url()
|
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");
|
var request =
|
||||||
request.RequestUri = new System.Uri(downstreamUrl);
|
new HttpRequestMessage(HttpMethod.Get, "http://test.com") {RequestUri = new System.Uri(downstreamUrl)};
|
||||||
|
|
||||||
var response = new HttpResponseMessage();
|
var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted,
|
||||||
response.Headers.Add("Location", downstreamUrl);
|
new List<KeyValuePair<string, IEnumerable<string>>>()
|
||||||
|
{
|
||||||
|
new KeyValuePair<string, IEnumerable<string>>("Location", new List<string> {downstreamUrl})
|
||||||
|
});
|
||||||
|
|
||||||
var fAndRs = new List<HeaderFindAndReplace>();
|
var fAndRs = new List<HeaderFindAndReplace>
|
||||||
fAndRs.Add(new HeaderFindAndReplace("Location", "{DownstreamBaseUrl}", "http://ocelot.com/", 0));
|
{
|
||||||
|
new HeaderFindAndReplace("Location", "{DownstreamBaseUrl}", "http://ocelot.com/", 0)
|
||||||
|
};
|
||||||
|
|
||||||
this.Given(x => GivenTheHttpResponse(response))
|
this.Given(x => GivenTheHttpResponse(response))
|
||||||
.And(x => GivenTheRequestIs(request))
|
.And(x => GivenTheRequestIs(request))
|
||||||
@ -90,16 +102,21 @@ namespace Ocelot.UnitTests.Headers
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void should_replace_downstream_base_url_with_ocelot_base_url_with_port()
|
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");
|
var request =
|
||||||
request.RequestUri = new System.Uri(downstreamUrl);
|
new HttpRequestMessage(HttpMethod.Get, "http://test.com") {RequestUri = new System.Uri(downstreamUrl)};
|
||||||
|
|
||||||
var response = new HttpResponseMessage();
|
var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted,
|
||||||
response.Headers.Add("Location", downstreamUrl);
|
new List<KeyValuePair<string, IEnumerable<string>>>()
|
||||||
|
{
|
||||||
|
new KeyValuePair<string, IEnumerable<string>>("Location", new List<string> {downstreamUrl})
|
||||||
|
});
|
||||||
|
|
||||||
var fAndRs = new List<HeaderFindAndReplace>();
|
var fAndRs = new List<HeaderFindAndReplace>
|
||||||
fAndRs.Add(new HeaderFindAndReplace("Location", "{DownstreamBaseUrl}", "http://ocelot.com:123/", 0));
|
{
|
||||||
|
new HeaderFindAndReplace("Location", "{DownstreamBaseUrl}", "http://ocelot.com:123/", 0)
|
||||||
|
};
|
||||||
|
|
||||||
this.Given(x => GivenTheHttpResponse(response))
|
this.Given(x => GivenTheHttpResponse(response))
|
||||||
.And(x => GivenTheRequestIs(request))
|
.And(x => GivenTheRequestIs(request))
|
||||||
@ -112,16 +129,21 @@ namespace Ocelot.UnitTests.Headers
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void should_replace_downstream_base_url_with_ocelot_base_url_and_path()
|
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");
|
var request =
|
||||||
request.RequestUri = new System.Uri(downstreamUrl);
|
new HttpRequestMessage(HttpMethod.Get, "http://test.com") {RequestUri = new System.Uri(downstreamUrl)};
|
||||||
|
|
||||||
var response = new HttpResponseMessage();
|
var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted,
|
||||||
response.Headers.Add("Location", downstreamUrl);
|
new List<KeyValuePair<string, IEnumerable<string>>>()
|
||||||
|
{
|
||||||
|
new KeyValuePair<string, IEnumerable<string>>("Location", new List<string> {downstreamUrl})
|
||||||
|
});
|
||||||
|
|
||||||
var fAndRs = new List<HeaderFindAndReplace>();
|
var fAndRs = new List<HeaderFindAndReplace>
|
||||||
fAndRs.Add(new HeaderFindAndReplace("Location", "{DownstreamBaseUrl}", "http://ocelot.com/", 0));
|
{
|
||||||
|
new HeaderFindAndReplace("Location", "{DownstreamBaseUrl}", "http://ocelot.com/", 0)
|
||||||
|
};
|
||||||
|
|
||||||
this.Given(x => GivenTheHttpResponse(response))
|
this.Given(x => GivenTheHttpResponse(response))
|
||||||
.And(x => GivenTheRequestIs(request))
|
.And(x => GivenTheRequestIs(request))
|
||||||
@ -134,16 +156,21 @@ namespace Ocelot.UnitTests.Headers
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void should_replace_downstream_base_url_with_ocelot_base_url_with_path_and_port()
|
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");
|
var request =
|
||||||
request.RequestUri = new System.Uri(downstreamUrl);
|
new HttpRequestMessage(HttpMethod.Get, "http://test.com") {RequestUri = new System.Uri(downstreamUrl)};
|
||||||
|
|
||||||
var response = new HttpResponseMessage();
|
var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted,
|
||||||
response.Headers.Add("Location", downstreamUrl);
|
new List<KeyValuePair<string, IEnumerable<string>>>()
|
||||||
|
{
|
||||||
|
new KeyValuePair<string, IEnumerable<string>>("Location", new List<string> {downstreamUrl})
|
||||||
|
});
|
||||||
|
|
||||||
var fAndRs = new List<HeaderFindAndReplace>();
|
var fAndRs = new List<HeaderFindAndReplace>
|
||||||
fAndRs.Add(new HeaderFindAndReplace("Location", "{DownstreamBaseUrl}", "http://ocelot.com:123/", 0));
|
{
|
||||||
|
new HeaderFindAndReplace("Location", "{DownstreamBaseUrl}", "http://ocelot.com:123/", 0)
|
||||||
|
};
|
||||||
|
|
||||||
this.Given(x => GivenTheHttpResponse(response))
|
this.Given(x => GivenTheHttpResponse(response))
|
||||||
.And(x => GivenTheRequestIs(request))
|
.And(x => GivenTheRequestIs(request))
|
||||||
@ -156,16 +183,21 @@ namespace Ocelot.UnitTests.Headers
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void should_replace_downstream_base_url_and_port_with_ocelot_base_url()
|
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");
|
var request =
|
||||||
request.RequestUri = new System.Uri(downstreamUrl);
|
new HttpRequestMessage(HttpMethod.Get, "http://test.com") {RequestUri = new System.Uri(downstreamUrl)};
|
||||||
|
|
||||||
var response = new HttpResponseMessage();
|
var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted,
|
||||||
response.Headers.Add("Location", downstreamUrl);
|
new List<KeyValuePair<string, IEnumerable<string>>>()
|
||||||
|
{
|
||||||
|
new KeyValuePair<string, IEnumerable<string>>("Location", new List<string> {downstreamUrl})
|
||||||
|
});
|
||||||
|
|
||||||
var fAndRs = new List<HeaderFindAndReplace>();
|
var fAndRs = new List<HeaderFindAndReplace>
|
||||||
fAndRs.Add(new HeaderFindAndReplace("Location", "{DownstreamBaseUrl}", "http://ocelot.com/", 0));
|
{
|
||||||
|
new HeaderFindAndReplace("Location", "{DownstreamBaseUrl}", "http://ocelot.com/", 0)
|
||||||
|
};
|
||||||
|
|
||||||
this.Given(x => GivenTheHttpResponse(response))
|
this.Given(x => GivenTheHttpResponse(response))
|
||||||
.And(x => GivenTheRequestIs(request))
|
.And(x => GivenTheRequestIs(request))
|
||||||
@ -178,16 +210,21 @@ namespace Ocelot.UnitTests.Headers
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void should_replace_downstream_base_url_and_port_with_ocelot_base_url_and_port()
|
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");
|
var request =
|
||||||
request.RequestUri = new System.Uri(downstreamUrl);
|
new HttpRequestMessage(HttpMethod.Get, "http://test.com") {RequestUri = new System.Uri(downstreamUrl)};
|
||||||
|
|
||||||
var response = new HttpResponseMessage();
|
var response = new DownstreamResponse(new StringContent(string.Empty), HttpStatusCode.Accepted,
|
||||||
response.Headers.Add("Location", downstreamUrl);
|
new List<KeyValuePair<string, IEnumerable<string>>>()
|
||||||
|
{
|
||||||
|
new KeyValuePair<string, IEnumerable<string>>("Location", new List<string> {downstreamUrl})
|
||||||
|
});
|
||||||
|
|
||||||
var fAndRs = new List<HeaderFindAndReplace>();
|
var fAndRs = new List<HeaderFindAndReplace>
|
||||||
fAndRs.Add(new HeaderFindAndReplace("Location", "{DownstreamBaseUrl}", "http://ocelot.com:321/", 0));
|
{
|
||||||
|
new HeaderFindAndReplace("Location", "{DownstreamBaseUrl}", "http://ocelot.com:321/", 0)
|
||||||
|
};
|
||||||
|
|
||||||
this.Given(x => GivenTheHttpResponse(response))
|
this.Given(x => GivenTheHttpResponse(response))
|
||||||
.And(x => GivenTheRequestIs(request))
|
.And(x => GivenTheRequestIs(request))
|
||||||
@ -207,8 +244,8 @@ namespace Ocelot.UnitTests.Headers
|
|||||||
_result.ShouldBeOfType<OkResponse>();
|
_result.ShouldBeOfType<OkResponse>();
|
||||||
foreach (var f in _headerFindAndReplaces)
|
foreach (var f in _headerFindAndReplaces)
|
||||||
{
|
{
|
||||||
_response.Headers.TryGetValues(f.Key, out var values);
|
var values = _response.Headers.First(x => x.Key == f.Key);
|
||||||
values.ToList()[f.Index].ShouldBe("test");
|
values.Values.ToList()[f.Index].ShouldBe("test");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,7 +254,7 @@ namespace Ocelot.UnitTests.Headers
|
|||||||
_headerFindAndReplaces = fAndRs;
|
_headerFindAndReplaces = fAndRs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenTheHttpResponse(HttpResponseMessage response)
|
private void GivenTheHttpResponse(DownstreamResponse response)
|
||||||
{
|
{
|
||||||
_response = response;
|
_response = response;
|
||||||
}
|
}
|
||||||
@ -229,17 +266,17 @@ namespace Ocelot.UnitTests.Headers
|
|||||||
|
|
||||||
private void ThenTheHeaderShouldBe(string key, string value)
|
private void ThenTheHeaderShouldBe(string key, string value)
|
||||||
{
|
{
|
||||||
var test = _response.Headers.GetValues(key);
|
var test = _response.Headers.First(x => x.Key == key);
|
||||||
test.First().ShouldBe(value);
|
test.Values.First().ShouldBe(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenTheHeadersAreReplaced()
|
private void ThenTheHeadersAreReplaced()
|
||||||
{
|
{
|
||||||
_result.ShouldBeOfType<OkResponse>();
|
_result.ShouldBeOfType<OkResponse>();
|
||||||
foreach (var f in _headerFindAndReplaces)
|
foreach (var f in _headerFindAndReplaces)
|
||||||
{
|
{
|
||||||
_response.Headers.TryGetValues(f.Key, out var values);
|
var values = _response.Headers.First(x => x.Key == f.Key);
|
||||||
values.ToList()[f.Index].ShouldBe(f.Replace);
|
values.Values.ToList()[f.Index].ShouldBe(f.Replace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
using System.Net.Http;
|
using System.Collections.Generic;
|
||||||
using System.Net.Http.Headers;
|
using Ocelot.Middleware;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
using Shouldly;
|
using Shouldly;
|
||||||
using TestStack.BDDfy;
|
using TestStack.BDDfy;
|
||||||
@ -9,7 +9,7 @@ namespace Ocelot.UnitTests.Headers
|
|||||||
{
|
{
|
||||||
public class RemoveHeadersTests
|
public class RemoveHeadersTests
|
||||||
{
|
{
|
||||||
private HttpResponseHeaders _headers;
|
private List<Header> _headers;
|
||||||
private readonly Ocelot.Headers.RemoveOutputHeaders _removeOutputHeaders;
|
private readonly Ocelot.Headers.RemoveOutputHeaders _removeOutputHeaders;
|
||||||
private Response _result;
|
private Response _result;
|
||||||
|
|
||||||
@ -21,18 +21,18 @@ namespace Ocelot.UnitTests.Headers
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void should_remove_header()
|
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())
|
.When(x => x.WhenIRemoveTheHeaders())
|
||||||
.Then(x => x.TheHeaderIsNoLongerInTheContext())
|
.Then(x => x.TheHeaderIsNoLongerInTheContext())
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenAHttpContext(HttpResponseHeaders headers)
|
private void GivenAHttpContext(List<Header> headers)
|
||||||
{
|
{
|
||||||
_headers = headers;
|
_headers = headers;
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,9 @@ namespace Ocelot.UnitTests.Infrastructure
|
|||||||
{
|
{
|
||||||
public class HttpDataRepositoryTests
|
public class HttpDataRepositoryTests
|
||||||
{
|
{
|
||||||
private HttpContext _httpContext;
|
private readonly HttpContext _httpContext;
|
||||||
private IHttpContextAccessor _httpContextAccessor;
|
private IHttpContextAccessor _httpContextAccessor;
|
||||||
private HttpDataRepository _httpDataRepository;
|
private readonly HttpDataRepository _httpDataRepository;
|
||||||
private object _result;
|
private object _result;
|
||||||
|
|
||||||
public HttpDataRepositoryTests()
|
public HttpDataRepositoryTests()
|
||||||
|
@ -51,7 +51,6 @@ namespace Ocelot.UnitTests.Infrastructure
|
|||||||
result.Data.ShouldBe("http://www.bbc.co.uk/");
|
result.Data.ShouldBe("http://www.bbc.co.uk/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_return_downstream_base_url_when_port_is_80_or_443()
|
public void should_return_downstream_base_url_when_port_is_80_or_443()
|
||||||
{
|
{
|
||||||
|
@ -53,7 +53,6 @@ namespace Ocelot.UnitTests.Logging
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void should_log_error()
|
public void should_log_error()
|
||||||
{
|
{
|
||||||
|
|
||||||
_logger.LogError($"a message from {_a} to {_b}", _ex);
|
_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);
|
ThenLevelIsLogged("requestId: no request id, previousRequestId: no previous request id, message: a message from tom to laura, exception: System.Exception: oh no", LogLevel.Error);
|
||||||
|
@ -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>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -19,13 +19,16 @@ namespace Ocelot.UnitTests.Middleware
|
|||||||
private readonly OcelotRequestDelegate _pipeline;
|
private readonly OcelotRequestDelegate _pipeline;
|
||||||
private int _count;
|
private int _count;
|
||||||
private Mock<IResponseAggregator> _aggregator;
|
private Mock<IResponseAggregator> _aggregator;
|
||||||
|
private Mock<IResponseAggregatorFactory> _factory;
|
||||||
|
|
||||||
public MultiplexerTests()
|
public MultiplexerTests()
|
||||||
{
|
{
|
||||||
|
_factory = new Mock<IResponseAggregatorFactory>();
|
||||||
_aggregator = new Mock<IResponseAggregator>();
|
_aggregator = new Mock<IResponseAggregator>();
|
||||||
_context = new DownstreamContext(new DefaultHttpContext());
|
_context = new DownstreamContext(new DefaultHttpContext());
|
||||||
_pipeline = context => Task.FromResult(_count++);
|
_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]
|
[Fact]
|
||||||
|
@ -62,7 +62,6 @@ namespace Ocelot.UnitTests.Middleware
|
|||||||
{
|
{
|
||||||
_errors.Add(error);
|
_errors.Add(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FakeMiddleware : OcelotMiddleware
|
public class FakeMiddleware : OcelotMiddleware
|
||||||
|
@ -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>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Castle.Components.DictionaryAdapter;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
using Ocelot.Configuration.Builder;
|
using Ocelot.Configuration.Builder;
|
||||||
@ -29,40 +30,6 @@ namespace Ocelot.UnitTests.Middleware
|
|||||||
_aggregator = new SimpleJsonResponseAggregator();
|
_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]
|
[Fact]
|
||||||
public void should_aggregate_n_responses_and_set_response_content_on_upstream_context()
|
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())
|
var billDownstreamContext = new DownstreamContext(new DefaultHttpContext())
|
||||||
{
|
{
|
||||||
DownstreamResponse =
|
DownstreamResponse = new DownstreamResponse(new StringContent("Bill says hi"), HttpStatusCode.OK, new EditableList<KeyValuePair<string, IEnumerable<string>>>()),
|
||||||
new HttpResponseMessage(HttpStatusCode.OK) {Content = new StringContent("Bill says hi")},
|
|
||||||
DownstreamReRoute = billDownstreamReRoute
|
DownstreamReRoute = billDownstreamReRoute
|
||||||
};
|
};
|
||||||
|
|
||||||
var georgeDownstreamContext = new DownstreamContext(new DefaultHttpContext())
|
var georgeDownstreamContext = new DownstreamContext(new DefaultHttpContext())
|
||||||
{
|
{
|
||||||
DownstreamResponse =
|
DownstreamResponse = new DownstreamResponse(new StringContent("George says hi"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>()),
|
||||||
new HttpResponseMessage(HttpStatusCode.OK) {Content = new StringContent("George says hi")},
|
|
||||||
DownstreamReRoute = georgeDownstreamReRoute
|
DownstreamReRoute = georgeDownstreamReRoute
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -126,19 +91,18 @@ namespace Ocelot.UnitTests.Middleware
|
|||||||
|
|
||||||
var billDownstreamContext = new DownstreamContext(new DefaultHttpContext())
|
var billDownstreamContext = new DownstreamContext(new DefaultHttpContext())
|
||||||
{
|
{
|
||||||
DownstreamResponse =
|
DownstreamResponse = new DownstreamResponse(new StringContent("Bill says hi"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>()),
|
||||||
new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent("Bill says hi") },
|
|
||||||
DownstreamReRoute = billDownstreamReRoute
|
DownstreamReRoute = billDownstreamReRoute
|
||||||
};
|
};
|
||||||
|
|
||||||
var georgeDownstreamContext = new DownstreamContext(new DefaultHttpContext())
|
var georgeDownstreamContext = new DownstreamContext(new DefaultHttpContext())
|
||||||
{
|
{
|
||||||
DownstreamResponse =
|
DownstreamResponse = new DownstreamResponse(new StringContent("Error"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>()),
|
||||||
new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent("Error") },
|
|
||||||
DownstreamReRoute = georgeDownstreamReRoute,
|
DownstreamReRoute = georgeDownstreamReRoute,
|
||||||
Errors = new List<Error>() { new AnyError() }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
georgeDownstreamContext.Errors.Add(new AnyError());
|
||||||
|
|
||||||
var downstreamContexts = new List<DownstreamContext> { billDownstreamContext, georgeDownstreamContext };
|
var downstreamContexts = new List<DownstreamContext> { billDownstreamContext, georgeDownstreamContext };
|
||||||
|
|
||||||
var expected = "Error";
|
var expected = "Error";
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -153,8 +153,6 @@ namespace Ocelot.UnitTests.QueryStrings
|
|||||||
.AddQueryString(_downstreamRequest.ToHttpRequestMessage().RequestUri.OriginalString, key, value);
|
.AddQueryString(_downstreamRequest.ToHttpRequestMessage().RequestUri.OriginalString, key, value);
|
||||||
|
|
||||||
_request.RequestUri = new Uri(newUri);
|
_request.RequestUri = new Uri(newUri);
|
||||||
//todo - might not need to instanciate
|
|
||||||
_downstreamRequest = new DownstreamRequest(_request);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenTheClaimParserReturns(Response<string> claimValue)
|
private void GivenTheClaimParserReturns(Response<string> claimValue)
|
||||||
|
@ -140,25 +140,28 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
.UseIISIntegration()
|
.UseIISIntegration()
|
||||||
.Configure(app =>
|
.Configure(app =>
|
||||||
{
|
{
|
||||||
app.Run(async context =>
|
app.Run(context =>
|
||||||
{
|
{
|
||||||
if (_count == 0)
|
if (_count == 0)
|
||||||
{
|
{
|
||||||
context.Response.Cookies.Append("test", "0");
|
context.Response.Cookies.Append("test", "0");
|
||||||
context.Response.StatusCode = 200;
|
context.Response.StatusCode = 200;
|
||||||
_count++;
|
_count++;
|
||||||
return;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_count == 1)
|
if (_count == 1)
|
||||||
{
|
{
|
||||||
if (context.Request.Cookies.TryGetValue("test", out var cookieValue) || context.Request.Headers.TryGetValue("Set-Cookie", out var headerValue))
|
if (context.Request.Cookies.TryGetValue("test", out var cookieValue) || context.Request.Headers.TryGetValue("Set-Cookie", out var headerValue))
|
||||||
{
|
{
|
||||||
context.Response.StatusCode = 200;
|
context.Response.StatusCode = 200;
|
||||||
return;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Response.StatusCode = 500;
|
context.Response.StatusCode = 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.Build();
|
.Build();
|
||||||
@ -200,6 +203,7 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
.Setup(x => x.Get(It.IsAny<DownstreamReRoute>()))
|
.Setup(x => x.Get(It.IsAny<DownstreamReRoute>()))
|
||||||
.Returns(new OkResponse<List<Func<DelegatingHandler>>>(handlers));
|
.Returns(new OkResponse<List<Func<DelegatingHandler>>>(handlers));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenTheFactoryReturnsNothing()
|
private void GivenTheFactoryReturnsNothing()
|
||||||
{
|
{
|
||||||
var handlers = new List<Func<DelegatingHandler>>();
|
var handlers = new List<Func<DelegatingHandler>>();
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
using Ocelot.Configuration.Builder;
|
|
||||||
using Ocelot.Middleware;
|
|
||||||
|
|
||||||
namespace Ocelot.UnitTests.Requester
|
namespace Ocelot.UnitTests.Requester
|
||||||
{
|
{
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
@ -14,11 +11,16 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
using Xunit;
|
using Xunit;
|
||||||
using Shouldly;
|
using Shouldly;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Ocelot.Configuration.Builder;
|
||||||
|
using Ocelot.Middleware;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using Ocelot.UnitTests.Responder;
|
||||||
|
|
||||||
public class HttpRequesterMiddlewareTests
|
public class HttpRequesterMiddlewareTests
|
||||||
{
|
{
|
||||||
private readonly Mock<IHttpRequester> _requester;
|
private readonly Mock<IHttpRequester> _requester;
|
||||||
private OkResponse<HttpResponseMessage> _response;
|
private Response<HttpResponseMessage> _response;
|
||||||
private Mock<IOcelotLoggerFactory> _loggerFactory;
|
private Mock<IOcelotLoggerFactory> _loggerFactory;
|
||||||
private Mock<IOcelotLogger> _logger;
|
private Mock<IOcelotLogger> _logger;
|
||||||
private readonly HttpRequesterMiddleware _middleware;
|
private readonly HttpRequesterMiddleware _middleware;
|
||||||
@ -39,12 +41,27 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
public void should_call_services_correctly()
|
public void should_call_services_correctly()
|
||||||
{
|
{
|
||||||
this.Given(x => x.GivenTheRequestIs())
|
this.Given(x => x.GivenTheRequestIs())
|
||||||
.And(x => x.GivenTheRequesterReturns(new HttpResponseMessage()))
|
.And(x => x.GivenTheRequesterReturns(new OkResponse<HttpResponseMessage>(new HttpResponseMessage())))
|
||||||
.When(x => x.WhenICallTheMiddleware())
|
.When(x => x.WhenICallTheMiddleware())
|
||||||
.Then(x => x.ThenTheScopedRepoIsCalledCorrectly())
|
.Then(x => x.ThenTheDownstreamResponseIsSet())
|
||||||
.BDDfy();
|
.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()
|
private void WhenICallTheMiddleware()
|
||||||
{
|
{
|
||||||
_middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
|
_middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
|
||||||
@ -52,21 +69,34 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
|
|
||||||
private void GivenTheRequestIs()
|
private void GivenTheRequestIs()
|
||||||
{
|
{
|
||||||
_downstreamContext = new DownstreamContext(new DefaultHttpContext());
|
_downstreamContext =
|
||||||
_downstreamContext.DownstreamReRoute = new DownstreamReRouteBuilder().Build();
|
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
|
_requester
|
||||||
.Setup(x => x.GetResponse(It.IsAny<DownstreamContext>()))
|
.Setup(x => x.GetResponse(It.IsAny<DownstreamContext>()))
|
||||||
.ReturnsAsync(_response);
|
.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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,7 @@ namespace Ocelot.UnitTests.Responder
|
|||||||
// If this test fails then it's because the number of error codes has changed.
|
// 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
|
// You should make the appropriate changes to the test cases here to ensure
|
||||||
// they cover all the error codes, and then modify this assertion.
|
// 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)
|
private void ShouldMapErrorToStatusCode(OcelotErrorCode errorCode, HttpStatusCode expectedHttpStatusCode)
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Ocelot.Headers;
|
using Ocelot.Headers;
|
||||||
|
using Ocelot.Middleware;
|
||||||
|
using Ocelot.Middleware.Multiplexer;
|
||||||
using Ocelot.Responder;
|
using Ocelot.Responder;
|
||||||
using Shouldly;
|
using Shouldly;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
@ -26,9 +27,13 @@ namespace Ocelot.UnitTests.Responder
|
|||||||
public void should_remove_transfer_encoding_header()
|
public void should_remove_transfer_encoding_header()
|
||||||
{
|
{
|
||||||
var httpContext = new DefaultHttpContext();
|
var httpContext = new DefaultHttpContext();
|
||||||
var httpResponseMessage = new HttpResponseMessage {Content = new StringContent("")};
|
var response = new DownstreamResponse(new StringContent(""), HttpStatusCode.OK,
|
||||||
httpResponseMessage.Headers.Add("Transfer-Encoding", "woop");
|
new List<KeyValuePair<string, IEnumerable<string>>>
|
||||||
_responder.SetResponseOnHttpContext(httpContext, httpResponseMessage).GetAwaiter().GetResult();
|
{
|
||||||
|
new KeyValuePair<string, IEnumerable<string>>("Transfer-Encoding", new List<string> {"woop"})
|
||||||
|
});
|
||||||
|
|
||||||
|
_responder.SetResponseOnHttpContext(httpContext, response).GetAwaiter().GetResult();
|
||||||
var header = httpContext.Response.Headers["Transfer-Encoding"];
|
var header = httpContext.Response.Headers["Transfer-Encoding"];
|
||||||
header.ShouldBeEmpty();
|
header.ShouldBeEmpty();
|
||||||
}
|
}
|
||||||
@ -37,8 +42,10 @@ namespace Ocelot.UnitTests.Responder
|
|||||||
public void should_have_content_length()
|
public void should_have_content_length()
|
||||||
{
|
{
|
||||||
var httpContext = new DefaultHttpContext();
|
var httpContext = new DefaultHttpContext();
|
||||||
var httpResponseMessage = new HttpResponseMessage { Content = new StringContent("test") };
|
var response = new DownstreamResponse(new StringContent("test"), HttpStatusCode.OK,
|
||||||
_responder.SetResponseOnHttpContext(httpContext, httpResponseMessage).GetAwaiter().GetResult();
|
new List<KeyValuePair<string, IEnumerable<string>>>());
|
||||||
|
|
||||||
|
_responder.SetResponseOnHttpContext(httpContext, response).GetAwaiter().GetResult();
|
||||||
var header = httpContext.Response.Headers["Content-Length"];
|
var header = httpContext.Response.Headers["Content-Length"];
|
||||||
header.First().ShouldBe("4");
|
header.First().ShouldBe("4");
|
||||||
}
|
}
|
||||||
@ -47,9 +54,13 @@ namespace Ocelot.UnitTests.Responder
|
|||||||
public void should_add_header()
|
public void should_add_header()
|
||||||
{
|
{
|
||||||
var httpContext = new DefaultHttpContext();
|
var httpContext = new DefaultHttpContext();
|
||||||
var httpResponseMessage = new HttpResponseMessage { Content = new StringContent("test") };
|
var response = new DownstreamResponse(new StringContent(""), HttpStatusCode.OK,
|
||||||
httpResponseMessage.Headers.Add("test", "test");
|
new List<KeyValuePair<string, IEnumerable<string>>>
|
||||||
_responder.SetResponseOnHttpContext(httpContext, httpResponseMessage).GetAwaiter().GetResult();
|
{
|
||||||
|
new KeyValuePair<string, IEnumerable<string>>("test", new List<string> {"test"})
|
||||||
|
});
|
||||||
|
|
||||||
|
_responder.SetResponseOnHttpContext(httpContext, response).GetAwaiter().GetResult();
|
||||||
var header = httpContext.Response.Headers["test"];
|
var header = httpContext.Response.Headers["test"];
|
||||||
header.First().ShouldBe("test");
|
header.First().ShouldBe("test");
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Ocelot.Middleware;
|
using Ocelot.Middleware;
|
||||||
|
using Ocelot.Middleware.Multiplexer;
|
||||||
|
|
||||||
namespace Ocelot.UnitTests.Responder
|
namespace Ocelot.UnitTests.Responder
|
||||||
{
|
{
|
||||||
@ -40,8 +41,7 @@ namespace Ocelot.UnitTests.Responder
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void should_not_return_any_errors()
|
public void should_not_return_any_errors()
|
||||||
{
|
{
|
||||||
this.Given(x => x.GivenTheHttpResponseMessageIs(new HttpResponseMessage()))
|
this.Given(x => x.GivenTheHttpResponseMessageIs(new DownstreamResponse(new HttpResponseMessage())))
|
||||||
.And(x => x.GivenThereAreNoPipelineErrors())
|
|
||||||
.When(x => x.WhenICallTheMiddleware())
|
.When(x => x.WhenICallTheMiddleware())
|
||||||
.Then(x => x.ThenThereAreNoErrors())
|
.Then(x => x.ThenThereAreNoErrors())
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
@ -50,7 +50,7 @@ namespace Ocelot.UnitTests.Responder
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void should_return_any_errors()
|
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")))
|
.And(x => x.GivenThereArePipelineErrors(new UnableToFindDownstreamRouteError("/path", "GET")))
|
||||||
.When(x => x.WhenICallTheMiddleware())
|
.When(x => x.WhenICallTheMiddleware())
|
||||||
.Then(x => x.ThenThereAreNoErrors())
|
.Then(x => x.ThenThereAreNoErrors())
|
||||||
@ -62,16 +62,11 @@ namespace Ocelot.UnitTests.Responder
|
|||||||
_middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
|
_middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenTheHttpResponseMessageIs(HttpResponseMessage response)
|
private void GivenTheHttpResponseMessageIs(DownstreamResponse response)
|
||||||
{
|
{
|
||||||
_downstreamContext.DownstreamResponse = response;
|
_downstreamContext.DownstreamResponse = response;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenThereAreNoPipelineErrors()
|
|
||||||
{
|
|
||||||
_downstreamContext.Errors = new List<Error>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ThenThereAreNoErrors()
|
private void ThenThereAreNoErrors()
|
||||||
{
|
{
|
||||||
//todo a better assert?
|
//todo a better assert?
|
||||||
@ -79,7 +74,7 @@ namespace Ocelot.UnitTests.Responder
|
|||||||
|
|
||||||
private void GivenThereArePipelineErrors(Error error)
|
private void GivenThereArePipelineErrors(Error error)
|
||||||
{
|
{
|
||||||
_downstreamContext.Errors = new List<Error>(){error};
|
_downstreamContext.Errors.Add(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user