Merge branch 'release-4.0.0'

This commit is contained in:
Tom Gardham-Pallister 2018-03-09 07:38:50 +00:00
commit ae5b86ef61
50 changed files with 1437 additions and 718 deletions

View File

@ -1,74 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="Rules for StyleCop.Analyzers" Description="Code analysis rules for StyleCop.Analyzers.csproj." ToolsVersion="14.0"> <RuleSet Name="Rules for StyleCop.Analyzers" Description="Code analysis rules for StyleCop.Analyzers.csproj." ToolsVersion="15.0">
<Rules AnalyzerId="AsyncUsageAnalyzers" RuleNamespace="AsyncUsageAnalyzers"> <Rules AnalyzerId="AsyncUsageAnalyzers" RuleNamespace="AsyncUsageAnalyzers">
<Rule Id="AvoidAsyncSuffix" Action="None" /> <Rule Id="AvoidAsyncSuffix" Action="None" />
<Rule Id="AvoidAsyncVoid" Action="None" /> <Rule Id="AvoidAsyncVoid" Action="Error" />
<Rule Id="UseAsyncSuffix" Action="None" /> <Rule Id="UseAsyncSuffix" Action="None" />
<Rule Id="UseConfigureAwait" Action="None" /> <Rule Id="UseConfigureAwait" Action="Error" />
</Rules>
<Rules AnalyzerId="Microsoft.Analyzers.ManagedCodeAnalysis" RuleNamespace="Microsoft.Rules.Managed">
<Rule Id="CA1001" Action="None" />
<Rule Id="CA1009" Action="None" />
<Rule Id="CA1016" Action="None" />
<Rule Id="CA1033" Action="None" />
<Rule Id="CA1049" Action="None" />
<Rule Id="CA1060" Action="None" />
<Rule Id="CA1061" Action="None" />
<Rule Id="CA1063" Action="None" />
<Rule Id="CA1065" Action="None" />
<Rule Id="CA1301" Action="None" />
<Rule Id="CA1400" Action="None" />
<Rule Id="CA1401" Action="None" />
<Rule Id="CA1403" Action="None" />
<Rule Id="CA1404" Action="None" />
<Rule Id="CA1405" Action="None" />
<Rule Id="CA1410" Action="None" />
<Rule Id="CA1415" Action="None" />
<Rule Id="CA1821" Action="None" />
<Rule Id="CA1900" Action="None" />
<Rule Id="CA1901" Action="None" />
<Rule Id="CA2002" Action="None" />
<Rule Id="CA2100" Action="None" />
<Rule Id="CA2101" Action="None" />
<Rule Id="CA2108" Action="None" />
<Rule Id="CA2111" Action="None" />
<Rule Id="CA2112" Action="None" />
<Rule Id="CA2114" Action="None" />
<Rule Id="CA2116" Action="None" />
<Rule Id="CA2117" Action="None" />
<Rule Id="CA2122" Action="None" />
<Rule Id="CA2123" Action="None" />
<Rule Id="CA2124" Action="None" />
<Rule Id="CA2126" Action="None" />
<Rule Id="CA2131" Action="None" />
<Rule Id="CA2132" Action="None" />
<Rule Id="CA2133" Action="None" />
<Rule Id="CA2134" Action="None" />
<Rule Id="CA2137" Action="None" />
<Rule Id="CA2138" Action="None" />
<Rule Id="CA2140" Action="None" />
<Rule Id="CA2141" Action="None" />
<Rule Id="CA2146" Action="None" />
<Rule Id="CA2147" Action="None" />
<Rule Id="CA2149" Action="None" />
<Rule Id="CA2200" Action="None" />
<Rule Id="CA2202" Action="None" />
<Rule Id="CA2207" Action="None" />
<Rule Id="CA2212" Action="None" />
<Rule Id="CA2213" Action="None" />
<Rule Id="CA2214" Action="None" />
<Rule Id="CA2216" Action="None" />
<Rule Id="CA2220" Action="None" />
<Rule Id="CA2229" Action="None" />
<Rule Id="CA2231" Action="None" />
<Rule Id="CA2232" Action="None" />
<Rule Id="CA2235" Action="None" />
<Rule Id="CA2236" Action="None" />
<Rule Id="CA2237" Action="None" />
<Rule Id="CA2238" Action="None" />
<Rule Id="CA2240" Action="None" />
<Rule Id="CA2241" Action="None" />
<Rule Id="CA2242" Action="None" />
</Rules> </Rules>
<Rules AnalyzerId="Microsoft.CodeAnalysis.CSharp.Features" RuleNamespace="Microsoft.CodeAnalysis.CSharp.Features"> <Rules AnalyzerId="Microsoft.CodeAnalysis.CSharp.Features" RuleNamespace="Microsoft.CodeAnalysis.CSharp.Features">
<Rule Id="IDE0003" Action="None" /> <Rule Id="IDE0003" Action="None" />
@ -87,12 +23,12 @@
<Rule Id="SA1013" Action="None" /> <Rule Id="SA1013" Action="None" />
<Rule Id="SA1015" Action="None" /> <Rule Id="SA1015" Action="None" />
<Rule Id="SA1016" Action="None" /> <Rule Id="SA1016" Action="None" />
<Rule Id="SA1021" Action="None" /> <Rule Id="SA1021" Action="Error" />
<Rule Id="SA1022" Action="None" /> <Rule Id="SA1022" Action="Error" />
<Rule Id="SA1024" Action="None" /> <Rule Id="SA1024" Action="None" />
<Rule Id="SA1026" Action="None" /> <Rule Id="SA1026" Action="None" />
<Rule Id="SA1028" Action="None" /> <Rule Id="SA1028" Action="None" />
<Rule Id="SA1100" Action="None" /> <Rule Id="SA1100" Action="Error" />
<Rule Id="SA1101" Action="None" /> <Rule Id="SA1101" Action="None" />
<Rule Id="SA1106" Action="None" /> <Rule Id="SA1106" Action="None" />
<Rule Id="SA1111" Action="None" /> <Rule Id="SA1111" Action="None" />
@ -100,11 +36,11 @@
<Rule Id="SA1116" Action="None" /> <Rule Id="SA1116" Action="None" />
<Rule Id="SA1117" Action="None" /> <Rule Id="SA1117" Action="None" />
<Rule Id="SA1118" Action="None" /> <Rule Id="SA1118" Action="None" />
<Rule Id="SA1119" Action="None" /> <Rule Id="SA1119" Action="Error" />
<Rule Id="SA1121" Action="None" /> <Rule Id="SA1121" Action="Error" />
<Rule Id="SA1122" Action="None" /> <Rule Id="SA1122" Action="None" />
<Rule Id="SA1128" Action="None" /> <Rule Id="SA1128" Action="None" />
<Rule Id="SA1133" Action="None" /> <Rule Id="SA1133" Action="Error" />
<Rule Id="SA1200" Action="None" /> <Rule Id="SA1200" Action="None" />
<Rule Id="SA1201" Action="None" /> <Rule Id="SA1201" Action="None" />
<Rule Id="SA1202" Action="None" /> <Rule Id="SA1202" Action="None" />
@ -116,37 +52,37 @@
<Rule Id="SA1214" Action="None" /> <Rule Id="SA1214" Action="None" />
<Rule Id="SA1216" Action="None" /> <Rule Id="SA1216" Action="None" />
<Rule Id="SA1300" Action="None" /> <Rule Id="SA1300" Action="None" />
<Rule Id="SA1302" Action="None" /> <Rule Id="SA1302" Action="Error" />
<Rule Id="SA1303" Action="None" /> <Rule Id="SA1303" Action="None" />
<Rule Id="SA1304" Action="None" /> <Rule Id="SA1304" Action="Error" />
<Rule Id="SA1305" Action="None" /> <Rule Id="SA1305" Action="None" />
<Rule Id="SA1309" Action="None" /> <Rule Id="SA1309" Action="None" />
<Rule Id="SA1310" Action="None" /> <Rule Id="SA1310" Action="None" />
<Rule Id="SA1311" Action="None" /> <Rule Id="SA1311" Action="Error" />
<Rule Id="SA1400" Action="None" /> <Rule Id="SA1400" Action="None" />
<Rule Id="SA1401" Action="None" /> <Rule Id="SA1401" Action="None" />
<Rule Id="SA1402" Action="None" /> <Rule Id="SA1402" Action="None" />
<Rule Id="SA1403" Action="None" /> <Rule Id="SA1403" Action="Error" />
<Rule Id="SA1404" Action="None" /> <Rule Id="SA1404" Action="Error" />
<Rule Id="SA1405" Action="None" /> <Rule Id="SA1405" Action="Error" />
<Rule Id="SA1406" Action="None" /> <Rule Id="SA1406" Action="Error" />
<Rule Id="SA1407" Action="None" /> <Rule Id="SA1407" Action="Error" />
<Rule Id="SA1408" Action="None" /> <Rule Id="SA1408" Action="None" />
<Rule Id="SA1410" Action="None" /> <Rule Id="SA1410" Action="Error" />
<Rule Id="SA1411" Action="None" /> <Rule Id="SA1411" Action="Error" />
<Rule Id="SA1412" Action="None" /> <Rule Id="SA1412" Action="None" />
<Rule Id="SA1500" Action="None" /> <Rule Id="SA1500" Action="None" />
<Rule Id="SA1502" Action="None" /> <Rule Id="SA1502" Action="None" />
<Rule Id="SA1516" Action="None" /> <Rule Id="SA1516" Action="None" />
<Rule Id="SA1600" Action="None" /> <Rule Id="SA1600" Action="None" />
<Rule Id="SA1603" Action="None" /> <Rule Id="SA1603" Action="Error" />
<Rule Id="SA1609" Action="None" /> <Rule Id="SA1609" Action="Error" />
<Rule Id="SA1611" Action="None" />
<Rule Id="SA1623" Action="None" /> <Rule Id="SA1623" Action="None" />
<Rule Id="SA1633" Action="None" /> <Rule Id="SA1633" Action="None" />
<Rule Id="SA1636" Action="None" /> <Rule Id="SA1636" Action="Error" />
<Rule Id="SA1642" Action="None" /> <Rule Id="SA1642" Action="Error" />
<Rule Id="SA1643" Action="None" /> <Rule Id="SA1643" Action="Error" />
<Rule Id="SA1652" Action="None" /> <Rule Id="SA1652" Action="None" />
</Rules> </Rules>
</RuleSet> </RuleSet>

View File

@ -4,28 +4,21 @@ Delegating Handers
Ocelot allows the user to add delegating handlers to the HttpClient transport. This feature was requested `GitHub #208 <https://github.com/TomPallister/Ocelot/issues/208>`_ and I decided that it was going to be useful in various ways. Ocelot allows the user to add delegating handlers to the HttpClient transport. This feature was requested `GitHub #208 <https://github.com/TomPallister/Ocelot/issues/208>`_ and I decided that it was going to be useful in various ways.
Usage Usage
^^^^^^ ^^^^^
In order to add delegating handlers to the HttpClient transport you need to do the following. In order to add delegating handlers to the HttpClient transport you need to do the following.
.. code-block:: csharp This will register the Handlers as singletons. Because Ocelot caches the HttpClient for the downstream services to avoid
socket exhaustion (well known http client issue) you can only register singleton handlers.
services.AddOcelot()
.AddDelegatingHandler(() => new FakeHandler())
.AddDelegatingHandler(() => new FakeHandler());
Or for singleton like behaviour..
.. code-block:: csharp .. code-block:: csharp
var handlerOne = new FakeHandler();
var handlerTwo = new FakeHandler();
services.AddOcelot() services.AddOcelot()
.AddDelegatingHandler(() => handlerOne) .AddDelegatingHandler<FakeHandler>()
.AddDelegatingHandler(() => handlerTwo); .AddDelegatingHandler<FakeHandlerTwo>()
You can have as many DelegatingHandlers as you want and they are run in a first in first out order. If you are using Ocelot's QoS functionality then that will always be run after your last delegating handler. You can have as many DelegatingHandlers as you want and they are run in a first in first out order. If you are using Ocelot's QoS functionality then that will always be run after your last delegating handler. If you are also registering handlers in DI these will be
run first.
In order to create a class that can be used a delegating handler it must look as follows In order to create a class that can be used a delegating handler it must look as follows

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View File

@ -36,3 +36,7 @@ Multiple Instances
With Consul With Consul
^^^^^^^^^^^ ^^^^^^^^^^^
.. image:: ../images/OcelotMultipleInstancesConsul.jpg .. image:: ../images/OcelotMultipleInstancesConsul.jpg
With Service Fabric
^^^^^^^^^^^^^^^^^^^
.. image:: ../images/OcelotServiceFabric.jpg

View File

@ -6,3 +6,27 @@ Ocelot does not support...
* Chunked Encoding - Ocelot will always get the body size and return Content-Length header. Sorry if this doesn't work for your use case! * Chunked Encoding - Ocelot will always get the body size and return Content-Length header. Sorry if this doesn't work for your use case!
* Fowarding a host header - The host header that you send to Ocelot will not be forwarded to the downstream service. Obviously this would break everything :( * Fowarding a host header - The host header that you send to Ocelot will not be forwarded to the downstream service. Obviously this would break everything :(
* Swagger - I have looked multiple times at building swagger.json out of the Ocelot configuration.json but it doesnt fit into the vision I have for Ocelot. If you would like to have Swagger in Ocelot then you must roll your own swagger.json and do the following in your Startup.cs or Program.cs. The code sample below registers a piece of middleware that loads your hand rolled swagger.json and returns it on /swagger/v1/swagger.json. It then registers the SwaggerUI middleware from Swashbuckle.AspNetCore
.. code-block:: csharp
app.Map("/swagger/v1/swagger.json", b =>
{
b.Run(async x => {
var json = File.ReadAllText("swagger.json");
await x.Response.WriteAsync(json);
});
});
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Ocelot");
});
app.UseOcelot().Wait();
The main reasons why I don't think Swagger makes sense is we already hand roll our definition in configuration.json. If we want people developing against Ocelot to be able to see what routes are available then either share the configuration.json with them (This should be as easy as granting access to a repo etc) or use the Ocelot administration API so that they can query Ocelot for the configuration.
In addition to this many people will configure Ocelot to proxy all traffic like /products/{everything} to there product service and you would not be describing what is actually available if you parsed this and turned it into a Swagger path. Also Ocelot has no concept of the models that the downstream services can return and linking to the above problem the same endpoint can return multiple models. Ocelot does not know what models might be used in POST, PUT etc so it all gets a bit messy and finally the Swashbuckle package doesnt reload swagger.json if it changes during runtime. Ocelot's configuration can change during runtime so the Swagger and Ocelot information would not match. Unless I rolled my own Swagger implementation.
If the user wants something to easily test against the Ocelot API then I suggest using Postman as a simple way to do this. It might even be possible to write something that maps configuration.json to the postman json spec. However I don't intend to do this.

View File

@ -18,7 +18,7 @@ namespace Ocelot.Configuration.Repository
_configFilePath = $"{AppContext.BaseDirectory}/configuration{(string.IsNullOrEmpty(hostingEnvironment.EnvironmentName) ? string.Empty : ".")}{hostingEnvironment.EnvironmentName}.json"; _configFilePath = $"{AppContext.BaseDirectory}/configuration{(string.IsNullOrEmpty(hostingEnvironment.EnvironmentName) ? string.Empty : ".")}{hostingEnvironment.EnvironmentName}.json";
} }
public async Task<Response<FileConfiguration>> Get() public Task<Response<FileConfiguration>> Get()
{ {
string jsonConfiguration; string jsonConfiguration;
@ -29,10 +29,10 @@ namespace Ocelot.Configuration.Repository
var fileConfiguration = JsonConvert.DeserializeObject<FileConfiguration>(jsonConfiguration); var fileConfiguration = JsonConvert.DeserializeObject<FileConfiguration>(jsonConfiguration);
return new OkResponse<FileConfiguration>(fileConfiguration); return Task.FromResult<Response<FileConfiguration>>(new OkResponse<FileConfiguration>(fileConfiguration));
} }
public async Task<Response> Set(FileConfiguration fileConfiguration) public Task<Response> Set(FileConfiguration fileConfiguration)
{ {
string jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration); string jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration);
@ -46,7 +46,7 @@ namespace Ocelot.Configuration.Repository
System.IO.File.WriteAllText(_configFilePath, jsonConfiguration); System.IO.File.WriteAllText(_configFilePath, jsonConfiguration);
} }
return new OkResponse(); return Task.FromResult<Response>(new OkResponse());
} }
} }
} }

View File

@ -12,19 +12,19 @@ namespace Ocelot.Configuration.Repository
private IOcelotConfiguration _ocelotConfiguration; private IOcelotConfiguration _ocelotConfiguration;
public async Task<Response<IOcelotConfiguration>> Get() public Task<Response<IOcelotConfiguration>> Get()
{ {
return new OkResponse<IOcelotConfiguration>(_ocelotConfiguration); return Task.FromResult<Response<IOcelotConfiguration>>(new OkResponse<IOcelotConfiguration>(_ocelotConfiguration));
} }
public async Task<Response> AddOrReplace(IOcelotConfiguration ocelotConfiguration) public Task<Response> AddOrReplace(IOcelotConfiguration ocelotConfiguration)
{ {
lock (LockObject) lock (LockObject)
{ {
_ocelotConfiguration = ocelotConfiguration; _ocelotConfiguration = ocelotConfiguration;
} }
return new OkResponse(); return Task.FromResult<Response>(new OkResponse());
} }
} }
} }

View File

@ -3,16 +3,22 @@ using CacheManager.Core;
using System; using System;
using System.Net.Http; using System.Net.Http;
using IdentityServer4.AccessTokenValidation; using IdentityServer4.AccessTokenValidation;
using Ocelot.Requester;
namespace Ocelot.DependencyInjection namespace Ocelot.DependencyInjection
{ {
public interface IOcelotBuilder public interface IOcelotBuilder
{ {
IOcelotBuilder AddStoreOcelotConfigurationInConsul(); IOcelotBuilder AddStoreOcelotConfigurationInConsul();
IOcelotBuilder AddCacheManager(Action<ConfigurationBuilderCachePart> settings); IOcelotBuilder AddCacheManager(Action<ConfigurationBuilderCachePart> settings);
IOcelotBuilder AddOpenTracing(Action<ButterflyOptions> settings); IOcelotBuilder AddOpenTracing(Action<ButterflyOptions> settings);
IOcelotAdministrationBuilder AddAdministration(string path, string secret); IOcelotAdministrationBuilder AddAdministration(string path, string secret);
IOcelotAdministrationBuilder AddAdministration(string path, Action<IdentityServerAuthenticationOptions> configOptions); IOcelotAdministrationBuilder AddAdministration(string path, Action<IdentityServerAuthenticationOptions> configOptions);
IOcelotBuilder AddDelegatingHandler(Func<DelegatingHandler> delegatingHandler);
IOcelotBuilder AddDelegatingHandler<T>() where T : DelegatingHandler;
} }
} }

View File

@ -57,7 +57,6 @@ namespace Ocelot.DependencyInjection
{ {
private readonly IServiceCollection _services; private readonly IServiceCollection _services;
private readonly IConfiguration _configurationRoot; private readonly IConfiguration _configurationRoot;
private readonly IDelegatingHandlerHandlerProvider _provider;
public OcelotBuilder(IServiceCollection services, IConfiguration configurationRoot) public OcelotBuilder(IServiceCollection services, IConfiguration configurationRoot)
{ {
@ -120,8 +119,7 @@ namespace Ocelot.DependencyInjection
_services.TryAddSingleton<IRequestMapper, RequestMapper>(); _services.TryAddSingleton<IRequestMapper, RequestMapper>();
_services.TryAddSingleton<IHttpHandlerOptionsCreator, HttpHandlerOptionsCreator>(); _services.TryAddSingleton<IHttpHandlerOptionsCreator, HttpHandlerOptionsCreator>();
_services.TryAddSingleton<IDownstreamAddressesCreator, DownstreamAddressesCreator>(); _services.TryAddSingleton<IDownstreamAddressesCreator, DownstreamAddressesCreator>();
_services.TryAddSingleton<IDelegatingHandlerHandlerProviderFactory, DelegatingHandlerHandlerProviderFactory>(); _services.TryAddSingleton<IDelegatingHandlerHandlerFactory, DelegatingHandlerHandlerFactory>();
_services.TryAddSingleton<IDelegatingHandlerHandlerHouse, DelegatingHandlerHandlerHouse>();
// see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc // see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc
// could maybe use a scoped data repository // could maybe use a scoped data repository
@ -144,9 +142,6 @@ namespace Ocelot.DependencyInjection
_services.AddWebEncoders(); _services.AddWebEncoders();
_services.AddSingleton<IAdministrationPath>(new NullAdministrationPath()); _services.AddSingleton<IAdministrationPath>(new NullAdministrationPath());
//these get picked out later and added to http request
_provider = new DelegatingHandlerHandlerProvider();
_services.TryAddSingleton<IDelegatingHandlerHandlerProvider>(_provider);
_services.TryAddSingleton<IMultiplexer, Multiplexer>(); _services.TryAddSingleton<IMultiplexer, Multiplexer>();
_services.TryAddSingleton<IResponseAggregator, SimpleJsonResponseAggregator>(); _services.TryAddSingleton<IResponseAggregator, SimpleJsonResponseAggregator>();
_services.AddSingleton<ITracingHandlerFactory, TracingHandlerFactory>(); _services.AddSingleton<ITracingHandlerFactory, TracingHandlerFactory>();
@ -187,9 +182,10 @@ namespace Ocelot.DependencyInjection
return new OcelotAdministrationBuilder(_services, _configurationRoot); return new OcelotAdministrationBuilder(_services, _configurationRoot);
} }
public IOcelotBuilder AddDelegatingHandler(Func<DelegatingHandler> delegatingHandler) public IOcelotBuilder AddDelegatingHandler<THandler>()
where THandler : DelegatingHandler
{ {
_provider.Add(delegatingHandler); _services.AddSingleton<DelegatingHandler, THandler>();
return this; return this;
} }

View File

@ -47,11 +47,28 @@
var content = new ByteArrayContent(await ToByteArray(request.Body)); var content = new ByteArrayContent(await ToByteArray(request.Body));
content.Headers.TryAddWithoutValidation("Content-Type", new[] {request.ContentType}); content.Headers
.TryAddWithoutValidation("Content-Type", new[] {request.ContentType});
AddHeaderIfExistsOnRequest("Content-Language", content, request);
AddHeaderIfExistsOnRequest("Content-Location", content, request);
AddHeaderIfExistsOnRequest("Content-Range", content, request);
AddHeaderIfExistsOnRequest("Content-MD5", content, request);
AddHeaderIfExistsOnRequest("Content-Disposition", content, request);
AddHeaderIfExistsOnRequest("Content-Encoding", content, request);
return content; return content;
} }
private void AddHeaderIfExistsOnRequest(string key, HttpContent content, HttpRequest request)
{
if(request.Headers.ContainsKey(key))
{
content.Headers
.TryAddWithoutValidation(key, request.Headers[key].ToList());
}
}
private HttpMethod MapMethod(HttpRequest request) private HttpMethod MapMethod(HttpRequest request)
{ {
return new HttpMethod(request.Method); return new HttpMethod(request.Method);

View File

@ -1,58 +0,0 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using Ocelot.Configuration;
using Ocelot.Errors;
using Ocelot.Responses;
namespace Ocelot.Requester
{
public class DelegatingHandlerHandlerHouse : IDelegatingHandlerHandlerHouse
{
private readonly IDelegatingHandlerHandlerProviderFactory _factory;
private readonly ConcurrentDictionary<string, IDelegatingHandlerHandlerProvider> _housed;
public DelegatingHandlerHandlerHouse(IDelegatingHandlerHandlerProviderFactory factory)
{
_factory = factory;
_housed = new ConcurrentDictionary<string, IDelegatingHandlerHandlerProvider>();
}
public Response<IDelegatingHandlerHandlerProvider> Get(DownstreamReRoute request)
{
try
{
if (_housed.TryGetValue(request.ReRouteKey, out var provider))
{
//todo once day we might need a check here to see if we need to create a new provider
provider = _housed[request.ReRouteKey];
return new OkResponse<IDelegatingHandlerHandlerProvider>(provider);
}
//todo - unit test for this
var providerResponse = _factory.Get(request);
if (providerResponse.IsError)
{
return new ErrorResponse<IDelegatingHandlerHandlerProvider>(providerResponse.Errors);
}
provider = providerResponse.Data;
AddHoused(request.ReRouteKey, provider);
return new OkResponse<IDelegatingHandlerHandlerProvider>(provider);
}
catch (Exception ex)
{
return new ErrorResponse<IDelegatingHandlerHandlerProvider>(new List<Error>()
{
new UnableToFindDelegatingHandlerProviderError($"unabe to find delegating handler provider for {request.ReRouteKey} exception is {ex}")
});
}
}
private void AddHoused(string key, IDelegatingHandlerHandlerProvider provider)
{
_housed.AddOrUpdate(key, provider, (k, v) => provider);
}
}
}

View File

@ -1,28 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
namespace Ocelot.Requester
{
public class DelegatingHandlerHandlerProvider : IDelegatingHandlerHandlerProvider
{
private readonly Dictionary<int, Func<DelegatingHandler>> _handlers;
public DelegatingHandlerHandlerProvider()
{
_handlers = new Dictionary<int, Func<DelegatingHandler>>();
}
public void Add(Func<DelegatingHandler> handler)
{
var key = _handlers.Count == 0 ? 0 : _handlers.Count + 1;
_handlers[key] = handler;
}
public List<Func<DelegatingHandler>> Get()
{
return _handlers.Count > 0 ? _handlers.OrderBy(x => x.Key).Select(x => x.Value).ToList() : new List<Func<DelegatingHandler>>();
}
}
}

View File

@ -1,5 +1,7 @@
using System; using System;
using System.Collections.Generic;
using System.Net.Http; using System.Net.Http;
using Microsoft.Extensions.DependencyInjection;
using Ocelot.Configuration; using Ocelot.Configuration;
using Ocelot.Logging; using Ocelot.Logging;
using Ocelot.Requester.QoS; using Ocelot.Requester.QoS;
@ -7,38 +9,38 @@ using Ocelot.Responses;
namespace Ocelot.Requester namespace Ocelot.Requester
{ {
public class DelegatingHandlerHandlerProviderFactory : IDelegatingHandlerHandlerProviderFactory public class DelegatingHandlerHandlerFactory : IDelegatingHandlerHandlerFactory
{ {
private readonly ITracingHandlerFactory _factory; private readonly ITracingHandlerFactory _factory;
private readonly IOcelotLoggerFactory _loggerFactory; private readonly IOcelotLoggerFactory _loggerFactory;
private readonly IDelegatingHandlerHandlerProvider _allRoutesProvider;
private readonly IQosProviderHouse _qosProviderHouse; private readonly IQosProviderHouse _qosProviderHouse;
private readonly IServiceProvider _serviceProvider;
public DelegatingHandlerHandlerProviderFactory(IOcelotLoggerFactory loggerFactory, public DelegatingHandlerHandlerFactory(IOcelotLoggerFactory loggerFactory,
IDelegatingHandlerHandlerProvider allRoutesProvider,
ITracingHandlerFactory factory, ITracingHandlerFactory factory,
IQosProviderHouse qosProviderHouse) IQosProviderHouse qosProviderHouse,
IServiceProvider serviceProvider)
{ {
_serviceProvider = serviceProvider;
_factory = factory; _factory = factory;
_loggerFactory = loggerFactory; _loggerFactory = loggerFactory;
_allRoutesProvider = allRoutesProvider;
_qosProviderHouse = qosProviderHouse; _qosProviderHouse = qosProviderHouse;
} }
public Response<IDelegatingHandlerHandlerProvider> Get(DownstreamReRoute request) public Response<List<Func<DelegatingHandler>>> Get(DownstreamReRoute request)
{ {
var handlersAppliedToAll = _allRoutesProvider.Get(); var handlersAppliedToAll = _serviceProvider.GetServices<DelegatingHandler>();
var provider = new DelegatingHandlerHandlerProvider(); var handlers = new List<Func<DelegatingHandler>>();
foreach (var handler in handlersAppliedToAll) foreach (var handler in handlersAppliedToAll)
{ {
provider.Add(handler); handlers.Add(() => handler);
} }
if (request.HttpHandlerOptions.UseTracing) if (request.HttpHandlerOptions.UseTracing)
{ {
provider.Add(() => (DelegatingHandler)_factory.Get()); handlers.Add(() => (DelegatingHandler)_factory.Get());
} }
if (request.IsQos) if (request.IsQos)
@ -47,13 +49,13 @@ namespace Ocelot.Requester
if (qosProvider.IsError) if (qosProvider.IsError)
{ {
return new ErrorResponse<IDelegatingHandlerHandlerProvider>(qosProvider.Errors); return new ErrorResponse<List<Func<DelegatingHandler>>>(qosProvider.Errors);
} }
provider.Add(() => new PollyCircuitBreakingDelegatingHandler(qosProvider.Data, _loggerFactory)); handlers.Add(() => new PollyCircuitBreakingDelegatingHandler(qosProvider.Data, _loggerFactory));
} }
return new OkResponse<IDelegatingHandlerHandlerProvider>(provider); return new OkResponse<List<Func<DelegatingHandler>>>(handlers);
} }
} }
} }

View File

@ -6,11 +6,11 @@ namespace Ocelot.Requester
{ {
public class HttpClientBuilder : IHttpClientBuilder public class HttpClientBuilder : IHttpClientBuilder
{ {
private readonly IDelegatingHandlerHandlerHouse _house; private readonly IDelegatingHandlerHandlerFactory _factory;
public HttpClientBuilder(IDelegatingHandlerHandlerHouse house) public HttpClientBuilder(IDelegatingHandlerHandlerFactory house)
{ {
_house = house; _factory = house;
} }
public IHttpClient Create(DownstreamReRoute request) public IHttpClient Create(DownstreamReRoute request)
@ -24,11 +24,9 @@ namespace Ocelot.Requester
private HttpMessageHandler CreateHttpMessageHandler(HttpMessageHandler httpMessageHandler, DownstreamReRoute request) private HttpMessageHandler CreateHttpMessageHandler(HttpMessageHandler httpMessageHandler, DownstreamReRoute request)
{ {
var provider = _house.Get(request);
var handlers = provider.Data.Get();
//todo handle error //todo handle error
var handlers = _factory.Get(request).Data;
handlers handlers
.Select(handler => handler) .Select(handler => handler)
.Reverse() .Reverse()

View File

@ -13,20 +13,20 @@ namespace Ocelot.Requester
{ {
private readonly IHttpClientCache _cacheHandlers; private readonly IHttpClientCache _cacheHandlers;
private readonly IOcelotLogger _logger; private readonly IOcelotLogger _logger;
private readonly IDelegatingHandlerHandlerHouse _house; private readonly IDelegatingHandlerHandlerFactory _factory;
public HttpClientHttpRequester(IOcelotLoggerFactory loggerFactory, public HttpClientHttpRequester(IOcelotLoggerFactory loggerFactory,
IHttpClientCache cacheHandlers, IHttpClientCache cacheHandlers,
IDelegatingHandlerHandlerHouse house) IDelegatingHandlerHandlerFactory house)
{ {
_logger = loggerFactory.CreateLogger<HttpClientHttpRequester>(); _logger = loggerFactory.CreateLogger<HttpClientHttpRequester>();
_cacheHandlers = cacheHandlers; _cacheHandlers = cacheHandlers;
_house = house; _factory = house;
} }
public async Task<Response<HttpResponseMessage>> GetResponse(DownstreamContext request) public async Task<Response<HttpResponseMessage>> GetResponse(DownstreamContext request)
{ {
var builder = new HttpClientBuilder(_house); var builder = new HttpClientBuilder(_factory);
var cacheKey = GetCacheKey(request); var cacheKey = GetCacheKey(request);

View File

@ -1,10 +0,0 @@
using Ocelot.Configuration;
using Ocelot.Responses;
namespace Ocelot.Requester
{
public interface IDelegatingHandlerHandlerHouse
{
Response<IDelegatingHandlerHandlerProvider> Get(DownstreamReRoute request);
}
}

View File

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
namespace Ocelot.Requester
{
public interface IDelegatingHandlerHandlerProvider
{
void Add(Func<DelegatingHandler> handler);
List<Func<DelegatingHandler>> Get();
}
}

View File

@ -1,10 +1,13 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using Ocelot.Configuration; using Ocelot.Configuration;
using Ocelot.Responses; using Ocelot.Responses;
namespace Ocelot.Requester namespace Ocelot.Requester
{ {
public interface IDelegatingHandlerHandlerProviderFactory public interface IDelegatingHandlerHandlerFactory
{ {
Response<IDelegatingHandlerHandlerProvider> Get(DownstreamReRoute request); Response<List<Func<DelegatingHandler>>> Get(DownstreamReRoute request);
} }
} }

View File

@ -1,5 +1,4 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ocelot.Values; using Ocelot.Values;
@ -14,16 +13,16 @@ namespace Ocelot.ServiceDiscovery
_configuration = configuration; _configuration = configuration;
} }
public async Task<List<Service>> Get() public Task<List<Service>> Get()
{ {
return new List<Service> return Task.FromResult(new List<Service>
{ {
new Service(_configuration.ServiceName, new Service(_configuration.ServiceName,
new ServiceHostAndPort(_configuration.HostName, _configuration.Port), new ServiceHostAndPort(_configuration.HostName, _configuration.Port),
"doesnt matter with service fabric", "doesnt matter with service fabric",
"doesnt matter with service fabric", "doesnt matter with service fabric",
new List<string>()) new List<string>())
}; });
} }
} }
} }

View File

@ -0,0 +1,116 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.AcceptanceTests
{
public class GzipTests : IDisposable
{
private IWebHost _builder;
private readonly Steps _steps;
public GzipTests()
{
_steps = new Steps();
}
[Fact]
public void should_return_response_200_with_simple_url()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51879,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Post" },
}
}
};
var input = "people";
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "/", 200, "Hello from Laura", "\"people\""))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.And(x => _steps.GivenThePostHasGzipContent(input))
.When(x => _steps.WhenIPostUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody, string expected)
{
_builder = new WebHostBuilder()
.UseUrls(baseUrl)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.Configure(app =>
{
app.UsePathBase(basePath);
app.Run(async context =>
{
if(context.Request.Headers.TryGetValue("Content-Encoding", out var contentEncoding))
{
contentEncoding.First().ShouldBe("gzip");
string text = null;
using (var decompress = new GZipStream(context.Request.Body, CompressionMode.Decompress))
{
using (var sr = new StreamReader(decompress)) {
text = sr.ReadToEnd();
}
}
if(text != expected)
{
throw new Exception("not gzipped");
}
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
}
else
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync("downstream path didnt match base path");
}
});
})
.Build();
_builder.Start();
}
public void Dispose()
{
_builder?.Dispose();
_steps.Dispose();
}
}
}

View File

@ -18,7 +18,6 @@ namespace Ocelot.AcceptanceTests
{ {
private IWebHost _builder; private IWebHost _builder;
private readonly Steps _steps; private readonly Steps _steps;
private string _downstreamPath;
public HeaderTests() public HeaderTests()
{ {
@ -221,13 +220,15 @@ namespace Ocelot.AcceptanceTests
.Configure(app => .Configure(app =>
{ {
app.UsePathBase(basePath); app.UsePathBase(basePath);
app.Run(async context => app.Run(context =>
{ {
context.Response.OnStarting(() => { context.Response.OnStarting(() => {
context.Response.Headers.Add(headerKey, headerValue); context.Response.Headers.Add(headerKey, headerValue);
context.Response.StatusCode = statusCode; context.Response.StatusCode = statusCode;
return Task.CompletedTask; return Task.CompletedTask;
}); });
return Task.CompletedTask;
}); });
}) })
.Build(); .Build();
@ -235,11 +236,6 @@ namespace Ocelot.AcceptanceTests
_builder.Start(); _builder.Start();
} }
internal void ThenTheDownstreamUrlPathShouldBe(string expectedDownstreamPath)
{
_downstreamPath.ShouldBe(expectedDownstreamPath);
}
public void Dispose() public void Dispose()
{ {
_builder?.Dispose(); _builder?.Dispose();

View File

@ -26,8 +26,9 @@ namespace Ocelot.AcceptanceTests
_steps = new Steps(); _steps = new Steps();
} }
[Fact] [Fact]
public void should_call_handlers() public void should_call_di_handlers()
{ {
var configuration = new FileConfiguration var configuration = new FileConfiguration
{ {
@ -42,7 +43,7 @@ namespace Ocelot.AcceptanceTests
new FileHostAndPort new FileHostAndPort
{ {
Host = "localhost", Host = "localhost",
Port = 61879, Port = 7187,
} }
}, },
UpstreamPathTemplate = "/", UpstreamPathTemplate = "/",
@ -51,27 +52,98 @@ namespace Ocelot.AcceptanceTests
} }
}; };
var handlerOne = new FakeHandler(); this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:7187", "/", 200, "Hello from Laura"))
var handlerTwo = new FakeHandler();
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:61879", "/", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningWithHandlers(handlerOne, handlerTwo)) .And(x => _steps.GivenOcelotIsRunningWithHandlersRegisteredInDi<FakeHandler, FakeHandlerTwo>())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.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"))
.And(x => ThenTheHandlersAreCalledCorrectly(handlerOne, handlerTwo)) .And(x => ThenTheHandlersAreCalledCorrectly())
.BDDfy(); .BDDfy();
} }
private void ThenTheHandlersAreCalledCorrectly(FakeHandler one, FakeHandler two)
[Fact]
public void should_call_di_handlers_with_dependency()
{ {
one.TimeCalled.ShouldBeLessThan(two.TimeCalled); var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 7188,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
var dependency = new FakeDependency();
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:7188", "/", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningWithHandlersRegisteredInDi<FakeHandlerWithDependency>(dependency))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.And(x => ThenTheDependencyIsCalled(dependency))
.BDDfy();
}
private void ThenTheDependencyIsCalled(FakeDependency dependency)
{
dependency.Called.ShouldBeTrue();
}
private void ThenTheHandlersAreCalledCorrectly()
{
FakeHandler.TimeCalled.ShouldBeLessThan(FakeHandlerTwo.TimeCalled);
}
public class FakeDependency
{
public bool Called;
}
class FakeHandlerWithDependency : DelegatingHandler
{
private FakeDependency _dependency;
public FakeHandlerWithDependency(FakeDependency dependency)
{
_dependency = dependency;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
_dependency.Called = true;
return await base.SendAsync(request, cancellationToken);
}
} }
class FakeHandler : DelegatingHandler class FakeHandler : DelegatingHandler
{ {
public DateTime TimeCalled { get; private set; } public static DateTime TimeCalled { get; private set; }
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
TimeCalled = DateTime.Now;
return await base.SendAsync(request, cancellationToken);
}
}
class FakeHandlerTwo : DelegatingHandler
{
public static DateTime TimeCalled { get; private set; }
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{ {

View File

@ -22,6 +22,9 @@ using Ocelot.Middleware;
using Shouldly; using Shouldly;
using ConfigurationBuilder = Microsoft.Extensions.Configuration.ConfigurationBuilder; using ConfigurationBuilder = Microsoft.Extensions.Configuration.ConfigurationBuilder;
using Ocelot.AcceptanceTests.Caching; using Ocelot.AcceptanceTests.Caching;
using System.IO.Compression;
using System.Text;
using static Ocelot.AcceptanceTests.HttpDelegatingHandlersTests;
namespace Ocelot.AcceptanceTests namespace Ocelot.AcceptanceTests
{ {
@ -172,10 +175,9 @@ namespace Ocelot.AcceptanceTests
_ocelotClient = _ocelotServer.CreateClient(); _ocelotClient = _ocelotServer.CreateClient();
} }
/// <summary> public void GivenOcelotIsRunningWithHandlersRegisteredInDi<TOne, TWo>()
/// This is annoying cos it should be in the constructor but we need to set up the file before calling startup so its a step. where TOne : DelegatingHandler
/// </summary> where TWo : DelegatingHandler
public void GivenOcelotIsRunningWithHandlers(DelegatingHandler handlerOne, DelegatingHandler handlerTwo)
{ {
_webHostBuilder = new WebHostBuilder(); _webHostBuilder = new WebHostBuilder();
@ -193,8 +195,40 @@ namespace Ocelot.AcceptanceTests
{ {
s.AddSingleton(_webHostBuilder); s.AddSingleton(_webHostBuilder);
s.AddOcelot() s.AddOcelot()
.AddDelegatingHandler(() => handlerOne) .AddDelegatingHandler<TOne>()
.AddDelegatingHandler(() => handlerTwo); .AddDelegatingHandler<TWo>();
})
.Configure(a =>
{
a.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}
public void GivenOcelotIsRunningWithHandlersRegisteredInDi<TOne>(FakeDependency dependency)
where TOne : DelegatingHandler
{
_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<FakeDependency>(dependency);
s.AddOcelot()
.AddDelegatingHandler<TOne>();
}) })
.Configure(a => .Configure(a =>
{ {
@ -582,6 +616,22 @@ namespace Ocelot.AcceptanceTests
_postContent = new StringContent(postcontent); _postContent = new StringContent(postcontent);
} }
public void GivenThePostHasGzipContent(object input)
{
string json = JsonConvert.SerializeObject(input);
byte[] jsonBytes = Encoding.UTF8.GetBytes(json);
MemoryStream ms = new MemoryStream();
using (GZipStream gzip = new GZipStream(ms, CompressionMode.Compress, true))
{
gzip.Write(jsonBytes, 0, jsonBytes.Length);
}
ms.Position = 0;
StreamContent content = new StreamContent(ms);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
content.Headers.ContentEncoding.Add("gzip");
_postContent = content;
}
public void ThenTheResponseBodyShouldBe(string expectedBody) public void ThenTheResponseBodyShouldBe(string expectedBody)
{ {
_response.Content.ReadAsStringAsync().Result.ShouldBe(expectedBody); _response.Content.ReadAsStringAsync().Result.ShouldBe(expectedBody);

View File

@ -0,0 +1,722 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using CacheManager.Core;
using IdentityServer4.AccessTokenValidation;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Ocelot.Configuration.File;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
using Shouldly;
using ConfigurationBuilder = Microsoft.Extensions.Configuration.ConfigurationBuilder;
using Ocelot.AcceptanceTests.Caching;
<<<<<<< HEAD
using static Ocelot.AcceptanceTests.HttpDelegatingHandlersTests;
||||||| merged common ancestors
=======
using System.IO.Compression;
using System.Text;
>>>>>>> develop
namespace Ocelot.AcceptanceTests
{
public class Steps : IDisposable
{
private TestServer _ocelotServer;
private HttpClient _ocelotClient;
private HttpResponseMessage _response;
private HttpContent _postContent;
private BearerToken _token;
public HttpClient OcelotClient => _ocelotClient;
public string RequestIdKey = "OcRequestId";
private readonly Random _random;
private IWebHostBuilder _webHostBuilder;
public Steps()
{
_random = new Random();
}
public void GivenThereIsAConfiguration(FileConfiguration fileConfiguration)
{
var configurationPath = TestConfiguration.ConfigurationPath;
var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration);
if (File.Exists(configurationPath))
{
File.Delete(configurationPath);
}
File.WriteAllText(configurationPath, jsonConfiguration);
}
public void GivenThereIsAConfiguration(FileConfiguration fileConfiguration, string configurationPath)
{
var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration);
if (File.Exists(configurationPath))
{
File.Delete(configurationPath);
}
File.WriteAllText(configurationPath, jsonConfiguration);
}
/// <summary>
/// This is annoying cos it should be in the constructor but we need to set up the file before calling startup so its a step.
/// </summary>
public void GivenOcelotIsRunning()
{
_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.AddOcelot();
})
.Configure(app =>
{
app.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}
internal void GivenOcelotIsRunningUsingButterfly(string butterflyUrl)
{
_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.AddOcelot()
.AddOpenTracing(option =>
{
//this is the url that the butterfly collector server is running on...
option.CollectorUrl = butterflyUrl;
option.Service = "Ocelot";
});
})
.Configure(app =>
{
app.Use(async (context, next) =>
{
await next.Invoke();
});
app.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}
/*
public void GivenIHaveAddedXForwardedForHeader(string value)
{
_ocelotClient.DefaultRequestHeaders.TryAddWithoutValidation("X-Forwarded-For", value);
}*/
public void GivenOcelotIsRunningWithMiddleareBeforePipeline<T>(Func<object, Task> callback)
{
_webHostBuilder = new WebHostBuilder();
_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.AddOcelot();
})
.Configure(app =>
{
app.UseMiddleware<T>(callback);
app.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}
public void GivenOcelotIsRunningWithHandlersRegisteredInDi<TOne, TWo>()
where TOne : DelegatingHandler
where TWo : DelegatingHandler
{
_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.AddOcelot()
.AddDelegatingHandler<TOne>()
.AddDelegatingHandler<TWo>();
})
.Configure(a =>
{
a.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}
public void GivenOcelotIsRunningWithHandlersRegisteredInDi<TOne>(FakeDependency dependency)
where TOne : DelegatingHandler
{
_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<FakeDependency>(dependency);
s.AddOcelot()
.AddDelegatingHandler<TOne>();
})
.Configure(a =>
{
a.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}
/// <summary>
/// This is annoying cos it should be in the constructor but we need to set up the file before calling startup so its a step.
/// </summary>
public void GivenOcelotIsRunning(Action<IdentityServerAuthenticationOptions> options, string authenticationProviderKey)
{
_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.AddOcelot();
s.AddAuthentication()
.AddIdentityServerAuthentication(authenticationProviderKey, options);
})
.Configure(app =>
{
app.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}
public void ThenTheResponseHeaderIs(string key, string value)
{
var header = _response.Headers.GetValues(key);
header.First().ShouldBe(value);
}
public void GivenOcelotIsRunningUsingJsonSerializedCache()
{
_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.AddOcelot()
.AddCacheManager((x) =>
{
x.WithMicrosoftLogging(log =>
{
log.AddConsole(LogLevel.Debug);
})
.WithJsonSerializer()
.WithHandle(typeof(InMemoryJsonHandle<>));
});
})
.Configure(app =>
{
app.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}
public void GivenOcelotIsRunningUsingConsulToStoreConfig()
{
_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.AddOcelot().AddStoreOcelotConfigurationInConsul();
})
.Configure(app =>
{
app.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}
public void GivenOcelotIsRunningUsingConsulToStoreConfigAndJsonSerializedCache()
{
_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.AddOcelot()
.AddCacheManager((x) =>
{
x.WithMicrosoftLogging(log =>
{
log.AddConsole(LogLevel.Debug);
})
.WithJsonSerializer()
.WithHandle(typeof(InMemoryJsonHandle<>));
})
.AddStoreOcelotConfigurationInConsul();
})
.Configure(app =>
{
app.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}
internal void ThenTheResponseShouldBe(FileConfiguration expecteds)
{
var response = JsonConvert.DeserializeObject<FileConfiguration>(_response.Content.ReadAsStringAsync().Result);
response.GlobalConfiguration.RequestIdKey.ShouldBe(expecteds.GlobalConfiguration.RequestIdKey);
response.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Host);
response.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Port);
for (var i = 0; i < response.ReRoutes.Count; i++)
{
for (var j = 0; j < response.ReRoutes[i].DownstreamHostAndPorts.Count; j++)
{
var result = response.ReRoutes[i].DownstreamHostAndPorts[j];
var expected = expecteds.ReRoutes[i].DownstreamHostAndPorts[j];
result.Host.ShouldBe(expected.Host);
result.Port.ShouldBe(expected.Port);
}
response.ReRoutes[i].DownstreamPathTemplate.ShouldBe(expecteds.ReRoutes[i].DownstreamPathTemplate);
response.ReRoutes[i].DownstreamScheme.ShouldBe(expecteds.ReRoutes[i].DownstreamScheme);
response.ReRoutes[i].UpstreamPathTemplate.ShouldBe(expecteds.ReRoutes[i].UpstreamPathTemplate);
response.ReRoutes[i].UpstreamHttpMethod.ShouldBe(expecteds.ReRoutes[i].UpstreamHttpMethod);
}
}
/// <summary>
/// This is annoying cos it should be in the constructor but we need to set up the file before calling startup so its a step.
/// </summary>
public void GivenOcelotIsRunning(OcelotPipelineConfiguration ocelotPipelineConfig)
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile("configuration.json")
.AddEnvironmentVariables();
var configuration = builder.Build();
_webHostBuilder = new WebHostBuilder();
_webHostBuilder.ConfigureServices(s =>
{
s.AddSingleton(_webHostBuilder);
});
_ocelotServer = new TestServer(_webHostBuilder
.UseConfiguration(configuration)
.ConfigureServices(s =>
{
Action<ConfigurationBuilderCachePart> settings = (x) =>
{
x.WithMicrosoftLogging(log =>
{
log.AddConsole(LogLevel.Debug);
})
.WithDictionaryHandle();
};
s.AddOcelot(configuration);
})
.ConfigureLogging(l =>
{
l.AddConsole();
l.AddDebug();
})
.Configure(a =>
{
a.UseOcelot(ocelotPipelineConfig).Wait();
}));
_ocelotClient = _ocelotServer.CreateClient();
}
public void GivenIHaveAddedATokenToMyRequest()
{
_ocelotClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _token.AccessToken);
}
public void GivenIHaveAToken(string url)
{
var tokenUrl = $"{url}/connect/token";
var formData = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("client_id", "client"),
new KeyValuePair<string, string>("client_secret", "secret"),
new KeyValuePair<string, string>("scope", "api"),
new KeyValuePair<string, string>("username", "test"),
new KeyValuePair<string, string>("password", "test"),
new KeyValuePair<string, string>("grant_type", "password")
};
var content = new FormUrlEncodedContent(formData);
using (var httpClient = new HttpClient())
{
var response = httpClient.PostAsync(tokenUrl, content).Result;
var responseContent = response.Content.ReadAsStringAsync().Result;
response.EnsureSuccessStatusCode();
_token = JsonConvert.DeserializeObject<BearerToken>(responseContent);
}
}
public void GivenIHaveATokenForApiReadOnlyScope(string url)
{
var tokenUrl = $"{url}/connect/token";
var formData = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("client_id", "client"),
new KeyValuePair<string, string>("client_secret", "secret"),
new KeyValuePair<string, string>("scope", "api.readOnly"),
new KeyValuePair<string, string>("username", "test"),
new KeyValuePair<string, string>("password", "test"),
new KeyValuePair<string, string>("grant_type", "password")
};
var content = new FormUrlEncodedContent(formData);
using (var httpClient = new HttpClient())
{
var response = httpClient.PostAsync(tokenUrl, content).Result;
var responseContent = response.Content.ReadAsStringAsync().Result;
response.EnsureSuccessStatusCode();
_token = JsonConvert.DeserializeObject<BearerToken>(responseContent);
}
}
public void GivenIHaveATokenForApi2(string url)
{
var tokenUrl = $"{url}/connect/token";
var formData = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("client_id", "client"),
new KeyValuePair<string, string>("client_secret", "secret"),
new KeyValuePair<string, string>("scope", "api2"),
new KeyValuePair<string, string>("username", "test"),
new KeyValuePair<string, string>("password", "test"),
new KeyValuePair<string, string>("grant_type", "password")
};
var content = new FormUrlEncodedContent(formData);
using (var httpClient = new HttpClient())
{
var response = httpClient.PostAsync(tokenUrl, content).Result;
var responseContent = response.Content.ReadAsStringAsync().Result;
response.EnsureSuccessStatusCode();
_token = JsonConvert.DeserializeObject<BearerToken>(responseContent);
}
}
public void GivenIHaveAnOcelotToken(string adminPath)
{
var tokenUrl = $"{adminPath}/connect/token";
var formData = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("client_id", "admin"),
new KeyValuePair<string, string>("client_secret", "secret"),
new KeyValuePair<string, string>("scope", "admin"),
new KeyValuePair<string, string>("username", "admin"),
new KeyValuePair<string, string>("password", "admin"),
new KeyValuePair<string, string>("grant_type", "password")
};
var content = new FormUrlEncodedContent(formData);
var response = _ocelotClient.PostAsync(tokenUrl, content).Result;
var responseContent = response.Content.ReadAsStringAsync().Result;
response.EnsureSuccessStatusCode();
_token = JsonConvert.DeserializeObject<BearerToken>(responseContent);
}
public void VerifyIdentiryServerStarted(string url)
{
using (var httpClient = new HttpClient())
{
var response = httpClient.GetAsync($"{url}/.well-known/openid-configuration").Result;
response.EnsureSuccessStatusCode();
}
}
public void WhenIGetUrlOnTheApiGateway(string url)
{
_response = _ocelotClient.GetAsync(url).Result;
}
public void GivenIAddAHeader(string key, string value)
{
_ocelotClient.DefaultRequestHeaders.Add(key, value);
}
public void WhenIGetUrlOnTheApiGatewayMultipleTimes(string url, int times)
{
var tasks = new Task[times];
for (int i = 0; i < times; i++)
{
var urlCopy = url;
tasks[i] = GetForServiceDiscoveryTest(urlCopy);
Thread.Sleep(_random.Next(40, 60));
}
Task.WaitAll(tasks);
}
private async Task GetForServiceDiscoveryTest(string url)
{
var response = await _ocelotClient.GetAsync(url);
var content = await response.Content.ReadAsStringAsync();
int count = int.Parse(content);
count.ShouldBeGreaterThan(0);
}
public void WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit(string url, int times)
{
for (int i = 0; i < times; i++)
{
var clientId = "ocelotclient1";
var request = new HttpRequestMessage(new HttpMethod("GET"), url);
request.Headers.Add("ClientId", clientId);
_response = _ocelotClient.SendAsync(request).Result;
}
}
public void WhenIGetUrlOnTheApiGateway(string url, string requestId)
{
_ocelotClient.DefaultRequestHeaders.TryAddWithoutValidation(RequestIdKey, requestId);
_response = _ocelotClient.GetAsync(url).Result;
}
public void WhenIPostUrlOnTheApiGateway(string url)
{
_response = _ocelotClient.PostAsync(url, _postContent).Result;
}
public void GivenThePostHasContent(string postcontent)
{
_postContent = new StringContent(postcontent);
}
public void GivenThePostHasGzipContent(object input)
{
string json = JsonConvert.SerializeObject(input);
byte[] jsonBytes = Encoding.UTF8.GetBytes(json);
MemoryStream ms = new MemoryStream();
using (GZipStream gzip = new GZipStream(ms, CompressionMode.Compress, true))
{
gzip.Write(jsonBytes, 0, jsonBytes.Length);
}
ms.Position = 0;
StreamContent content = new StreamContent(ms);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
content.Headers.ContentEncoding.Add("gzip");
_postContent = content;
}
public void ThenTheResponseBodyShouldBe(string expectedBody)
{
_response.Content.ReadAsStringAsync().Result.ShouldBe(expectedBody);
}
public void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode)
{
_response.StatusCode.ShouldBe(expectedHttpStatusCode);
}
public void ThenTheStatusCodeShouldBe(int expectedHttpStatusCode)
{
var responseStatusCode = (int)_response.StatusCode;
responseStatusCode.ShouldBe(expectedHttpStatusCode);
}
public void Dispose()
{
_ocelotClient?.Dispose();
_ocelotServer?.Dispose();
}
public void ThenTheRequestIdIsReturned()
{
_response.Headers.GetValues(RequestIdKey).First().ShouldNotBeNullOrEmpty();
}
public void ThenTheRequestIdIsReturned(string expected)
{
_response.Headers.GetValues(RequestIdKey).First().ShouldBe(expected);
}
public void ThenTheContentLengthIs(int expected)
{
_response.Content.Headers.ContentLength.ShouldBe(expected);
}
public void WhenIMakeLotsOfDifferentRequestsToTheApiGateway()
{
int numberOfRequests = 100;
var aggregateUrl = "/";
var aggregateExpected = "{\"Laura\":{Hello from Laura},\"Tom\":{Hello from Tom}}";
var tomUrl = "/tom";
var tomExpected = "{Hello from Tom}";
var lauraUrl = "/laura";
var lauraExpected = "{Hello from Laura}";
var random = new Random();
var aggregateTasks = new Task[numberOfRequests];
for (int i = 0; i < numberOfRequests; i++)
{
aggregateTasks[i] = Fire(aggregateUrl, aggregateExpected, random);
}
var tomTasks = new Task[numberOfRequests];
for (int i = 0; i < numberOfRequests; i++)
{
tomTasks[i] = Fire(tomUrl, tomExpected, random);
}
var lauraTasks = new Task[numberOfRequests];
for (int i = 0; i < numberOfRequests; i++)
{
lauraTasks[i] = Fire(lauraUrl, lauraExpected, random);
}
Task.WaitAll(lauraTasks);
Task.WaitAll(tomTasks);
Task.WaitAll(aggregateTasks);
}
private async Task Fire(string url, string expectedBody, Random random)
{
var request = new HttpRequestMessage(new HttpMethod("GET"), url);
await Task.Delay(random.Next(0, 2));
var response = await _ocelotClient.SendAsync(request);
var content = await response.Content.ReadAsStringAsync();
content.ShouldBe(expectedBody);
}
}
}

View File

@ -1,5 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<VersionPrefix>0.0.0-dev</VersionPrefix> <VersionPrefix>0.0.0-dev</VersionPrefix>
<TargetFramework>netcoreapp2.0</TargetFramework> <TargetFramework>netcoreapp2.0</TargetFramework>
@ -11,23 +10,19 @@
<RuntimeIdentifiers>osx.10.11-x64;osx.10.12-x64;win7-x64;win10-x64</RuntimeIdentifiers> <RuntimeIdentifiers>osx.10.11-x64;osx.10.12-x64;win7-x64;win10-x64</RuntimeIdentifiers>
<CodeAnalysisRuleSet>..\..\codeanalysis.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>..\..\codeanalysis.ruleset</CodeAnalysisRuleSet>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<None Update="Views;Areas\**\Views"> <None Update="Views;Areas\**\Views">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</None> </None>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Update="configuration.json;appsettings.json;idsrv3test.pfx"> <None Update="configuration.json;appsettings.json;idsrv3test.pfx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Ocelot\Ocelot.csproj"/> <ProjectReference Include="..\..\src\Ocelot\Ocelot.csproj"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0"/> <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0"/>
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.0"/> <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.0"/>
@ -43,5 +38,4 @@
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -6,6 +6,7 @@ namespace Ocelot.UnitTests.Authentication
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Moq; using Moq;
using Ocelot.Authentication.Middleware; using Ocelot.Authentication.Middleware;
@ -44,10 +45,11 @@ namespace Ocelot.UnitTests.Authentication
private void WhenICallTheMiddleware() private void WhenICallTheMiddleware()
{ {
_next = async (context) => { _next = (context) => {
byte[] byteArray = Encoding.ASCII.GetBytes("The user is authenticated"); byte[] byteArray = Encoding.ASCII.GetBytes("The user is authenticated");
MemoryStream stream = new MemoryStream(byteArray); var stream = new MemoryStream(byteArray);
context.HttpContext.Response.Body = stream; context.HttpContext.Response.Body = stream;
return Task.CompletedTask;
}; };
_middleware = new AuthenticationMiddleware(_next, _factory.Object); _middleware = new AuthenticationMiddleware(_next, _factory.Object);
_middleware.Invoke(_downstreamContext).GetAwaiter().GetResult(); _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
@ -55,10 +57,11 @@ namespace Ocelot.UnitTests.Authentication
private void GivenTheTestServerPipelineIsConfigured() private void GivenTheTestServerPipelineIsConfigured()
{ {
_next = async (context) => { _next = (context) => {
byte[] byteArray = Encoding.ASCII.GetBytes("The user is authenticated"); byte[] byteArray = Encoding.ASCII.GetBytes("The user is authenticated");
MemoryStream stream = new MemoryStream(byteArray); var stream = new MemoryStream(byteArray);
context.HttpContext.Response.Body = stream; context.HttpContext.Response.Body = stream;
return Task.CompletedTask;
}; };
} }

View File

@ -4,18 +4,17 @@ namespace Ocelot.UnitTests.Authorization
{ {
using System.Collections.Generic; using System.Collections.Generic;
using System.Security.Claims; using System.Security.Claims;
using System.Threading.Tasks;
using Moq; using Moq;
using Ocelot.Authorisation; using Ocelot.Authorisation;
using Ocelot.Authorisation.Middleware; using Ocelot.Authorisation.Middleware;
using Ocelot.Configuration.Builder; using Ocelot.Configuration.Builder;
using Ocelot.DownstreamRouteFinder;
using Ocelot.DownstreamRouteFinder.UrlMatcher; using Ocelot.DownstreamRouteFinder.UrlMatcher;
using Ocelot.Logging; using Ocelot.Logging;
using Ocelot.Responses; using Ocelot.Responses;
using TestStack.BDDfy; using TestStack.BDDfy;
using Xunit; using Xunit;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Ocelot.DownstreamRouteFinder.Middleware;
using Ocelot.Configuration; using Ocelot.Configuration;
public class AuthorisationMiddlewareTests public class AuthorisationMiddlewareTests
@ -36,9 +35,7 @@ namespace Ocelot.UnitTests.Authorization
_loggerFactory = new Mock<IOcelotLoggerFactory>(); _loggerFactory = new Mock<IOcelotLoggerFactory>();
_logger = new Mock<IOcelotLogger>(); _logger = new Mock<IOcelotLogger>();
_loggerFactory.Setup(x => x.CreateLogger<AuthorisationMiddleware>()).Returns(_logger.Object); _loggerFactory.Setup(x => x.CreateLogger<AuthorisationMiddleware>()).Returns(_logger.Object);
_next = async context => { _next = context => Task.CompletedTask;
//do nothing
};
_middleware = new AuthorisationMiddleware(_next, _authService.Object, _authScopesService.Object, _loggerFactory.Object); _middleware = new AuthorisationMiddleware(_next, _authService.Object, _authScopesService.Object, _loggerFactory.Object);
} }

View File

@ -10,6 +10,7 @@ namespace Ocelot.UnitTests.Cache
using Shouldly; using Shouldly;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks;
using Moq; using Moq;
using Ocelot.Cache; using Ocelot.Cache;
using Ocelot.Cache.Middleware; using Ocelot.Cache.Middleware;
@ -43,9 +44,7 @@ namespace Ocelot.UnitTests.Cache
_cacheManager = new OcelotCacheManagerCache<CachedResponse>(cacheManagerOutputCache); _cacheManager = new OcelotCacheManagerCache<CachedResponse>(cacheManagerOutputCache);
_downstreamContext = new DownstreamContext(new DefaultHttpContext()); _downstreamContext = new DownstreamContext(new DefaultHttpContext());
_downstreamContext.DownstreamRequest = new HttpRequestMessage(HttpMethod.Get, "https://some.url/blah?abcd=123"); _downstreamContext.DownstreamRequest = new HttpRequestMessage(HttpMethod.Get, "https://some.url/blah?abcd=123");
_next = async context => { _next = context => Task.CompletedTask;
//do nothing..
};
_middleware = new OutputCacheMiddleware(_next, _loggerFactory.Object, _cacheManager, _regionCreator); _middleware = new OutputCacheMiddleware(_next, _loggerFactory.Object, _cacheManager, _regionCreator);
} }

View File

@ -7,19 +7,16 @@ namespace Ocelot.UnitTests.Cache
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Http; using System.Net.Http;
using Microsoft.AspNetCore.Builder; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Moq; using Moq;
using Ocelot.Cache; using Ocelot.Cache;
using Ocelot.Cache.Middleware; using Ocelot.Cache.Middleware;
using Ocelot.Configuration; using Ocelot.Configuration;
using Ocelot.Configuration.Builder; using Ocelot.Configuration.Builder;
using Ocelot.DownstreamRouteFinder; using Ocelot.DownstreamRouteFinder;
using Ocelot.DownstreamRouteFinder.Middleware;
using Ocelot.DownstreamRouteFinder.UrlMatcher; using Ocelot.DownstreamRouteFinder.UrlMatcher;
using Ocelot.Logging; using Ocelot.Logging;
using Ocelot.Responses;
using TestStack.BDDfy; using TestStack.BDDfy;
using Xunit; using Xunit;
@ -42,10 +39,7 @@ namespace Ocelot.UnitTests.Cache
_loggerFactory = new Mock<IOcelotLoggerFactory>(); _loggerFactory = new Mock<IOcelotLoggerFactory>();
_logger = new Mock<IOcelotLogger>(); _logger = new Mock<IOcelotLogger>();
_loggerFactory.Setup(x => x.CreateLogger<OutputCacheMiddleware>()).Returns(_logger.Object); _loggerFactory.Setup(x => x.CreateLogger<OutputCacheMiddleware>()).Returns(_logger.Object);
_next = async context => { _next = context => Task.CompletedTask;
//do nothing
};
_downstreamContext.DownstreamRequest = new HttpRequestMessage(HttpMethod.Get, "https://some.url/blah?abcd=123"); _downstreamContext.DownstreamRequest = new HttpRequestMessage(HttpMethod.Get, "https://some.url/blah?abcd=123");
} }

View File

@ -3,6 +3,7 @@
namespace Ocelot.UnitTests.Claims namespace Ocelot.UnitTests.Claims
{ {
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Moq; using Moq;
using Ocelot.Claims; using Ocelot.Claims;
@ -32,9 +33,7 @@ namespace Ocelot.UnitTests.Claims
_loggerFactory = new Mock<IOcelotLoggerFactory>(); _loggerFactory = new Mock<IOcelotLoggerFactory>();
_logger = new Mock<IOcelotLogger>(); _logger = new Mock<IOcelotLogger>();
_loggerFactory.Setup(x => x.CreateLogger<ClaimsBuilderMiddleware>()).Returns(_logger.Object); _loggerFactory.Setup(x => x.CreateLogger<ClaimsBuilderMiddleware>()).Returns(_logger.Object);
_next = async context => { _next = context => Task.CompletedTask;
//do nothing
};
_middleware = new ClaimsBuilderMiddleware(_next, _loggerFactory.Object, _addHeaders.Object); _middleware = new ClaimsBuilderMiddleware(_next, _loggerFactory.Object, _addHeaders.Object);
} }

View File

@ -41,15 +41,13 @@ namespace Ocelot.UnitTests.DependencyInjection
private Exception _ex; private Exception _ex;
[Fact] [Fact]
public void should_add_delegating_handlers() public void should_add_delegating_handlers_with_di()
{ {
var fakeOne = new FakeDelegatingHandler(0);
var fakeTwo = new FakeDelegatingHandler(1);
this.Given(x => WhenISetUpOcelotServices()) this.Given(x => WhenISetUpOcelotServices())
.When(x => AddDelegate(fakeOne)) .When(x => AddDelegate<FakeDelegatingHandler>())
.And(x => AddDelegate(fakeTwo)) .And(x => AddDelegate<FakeDelegatingHandlerTwo>())
.Then(x => ThenTheProviderIsRegisteredAndReturnsHandlers()) .Then(x => ThenTheProviderIsRegisteredAndReturnsHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
.BDDfy(); .BDDfy();
} }
@ -164,15 +162,12 @@ namespace Ocelot.UnitTests.DependencyInjection
path.Path.ShouldBe("/administration"); path.Path.ShouldBe("/administration");
} }
private void ThenTheProviderIsRegisteredAndReturnsHandlers() private void ThenTheProviderIsRegisteredAndReturnsHandlers<TOne, TWo>()
{ {
_serviceProvider = _services.BuildServiceProvider(); _serviceProvider = _services.BuildServiceProvider();
var provider = _serviceProvider.GetService<IDelegatingHandlerHandlerProvider>(); var handlers = _serviceProvider.GetServices<DelegatingHandler>().ToList();
var handlers = provider.Get(); handlers[0].ShouldBeOfType<TOne>();
var handler = (FakeDelegatingHandler)handlers[0].Invoke(); handlers[1].ShouldBeOfType<TWo>();
handler.Order.ShouldBe(0);
handler = (FakeDelegatingHandler)handlers[1].Invoke();
handler.Order.ShouldBe(1);
} }
private void OnlyOneVersionOfEachCacheIsRegistered() private void OnlyOneVersionOfEachCacheIsRegistered()
@ -213,9 +208,9 @@ namespace Ocelot.UnitTests.DependencyInjection
} }
} }
private void AddDelegate(DelegatingHandler handler) private void AddDelegate<T>() where T : DelegatingHandler
{ {
_ocelotBuilder.AddDelegatingHandler(() => handler); _ocelotBuilder.AddDelegatingHandler<T>();
} }
private void ThenAnOcelotBuilderIsReturned() private void ThenAnOcelotBuilderIsReturned()

View File

@ -4,9 +4,8 @@ using Ocelot.Middleware.Multiplexer;
namespace Ocelot.UnitTests.DownstreamRouteFinder namespace Ocelot.UnitTests.DownstreamRouteFinder
{ {
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Builder; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Moq; using Moq;
using Ocelot.Configuration; using Ocelot.Configuration;
using Ocelot.Configuration.Builder; using Ocelot.Configuration.Builder;
@ -42,9 +41,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
_loggerFactory = new Mock<IOcelotLoggerFactory>(); _loggerFactory = new Mock<IOcelotLoggerFactory>();
_logger = new Mock<IOcelotLogger>(); _logger = new Mock<IOcelotLogger>();
_loggerFactory.Setup(x => x.CreateLogger<DownstreamRouteFinderMiddleware>()).Returns(_logger.Object); _loggerFactory.Setup(x => x.CreateLogger<DownstreamRouteFinderMiddleware>()).Returns(_logger.Object);
_next = async context => { _next = context => Task.CompletedTask;
//do nothing
};
_multiplexer = new Mock<IMultiplexer>(); _multiplexer = new Mock<IMultiplexer>();
_middleware = new DownstreamRouteFinderMiddleware(_next, _loggerFactory.Object, _finder.Object, _provider.Object, _multiplexer.Object); _middleware = new DownstreamRouteFinderMiddleware(_next, _loggerFactory.Object, _finder.Object, _provider.Object, _multiplexer.Object);
} }

View File

@ -6,23 +6,19 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Http; using System.Net.Http;
using Microsoft.AspNetCore.Builder; using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Moq; using Moq;
using Ocelot.Configuration.Builder; using Ocelot.Configuration.Builder;
using Ocelot.DownstreamRouteFinder; using Ocelot.DownstreamRouteFinder;
using Ocelot.DownstreamRouteFinder.UrlMatcher; using Ocelot.DownstreamRouteFinder.UrlMatcher;
using Ocelot.DownstreamUrlCreator;
using Ocelot.DownstreamUrlCreator.Middleware; using Ocelot.DownstreamUrlCreator.Middleware;
using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer; using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer;
using Ocelot.Infrastructure.RequestData;
using Ocelot.Logging; using Ocelot.Logging;
using Ocelot.Responses; using Ocelot.Responses;
using Ocelot.Values; using Ocelot.Values;
using TestStack.BDDfy; using TestStack.BDDfy;
using Xunit; using Xunit;
using Shouldly; using Shouldly;
using Ocelot.DownstreamRouteFinder.Middleware;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
public class DownstreamUrlCreatorMiddlewareTests public class DownstreamUrlCreatorMiddlewareTests
@ -43,9 +39,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator
_loggerFactory.Setup(x => x.CreateLogger<DownstreamUrlCreatorMiddleware>()).Returns(_logger.Object); _loggerFactory.Setup(x => x.CreateLogger<DownstreamUrlCreatorMiddleware>()).Returns(_logger.Object);
_downstreamUrlTemplateVariableReplacer = new Mock<IDownstreamPathPlaceholderReplacer>(); _downstreamUrlTemplateVariableReplacer = new Mock<IDownstreamPathPlaceholderReplacer>();
_downstreamContext.DownstreamRequest = new HttpRequestMessage(HttpMethod.Get, "https://my.url/abc/?q=123"); _downstreamContext.DownstreamRequest = new HttpRequestMessage(HttpMethod.Get, "https://my.url/abc/?q=123");
_next = async context => { _next = context => Task.CompletedTask;
//do nothing
};
} }
[Fact] [Fact]

View File

@ -11,11 +11,12 @@ using Ocelot.Configuration.Builder;
using Ocelot.Headers; using Ocelot.Headers;
using System.Net.Http; using System.Net.Http;
using Ocelot.Authorisation.Middleware; using Ocelot.Authorisation.Middleware;
using Ocelot.DownstreamRouteFinder.Middleware;
using Ocelot.Middleware; using Ocelot.Middleware;
namespace Ocelot.UnitTests.Headers namespace Ocelot.UnitTests.Headers
{ {
using System.Threading.Tasks;
public class HttpHeadersTransformationMiddlewareTests public class HttpHeadersTransformationMiddlewareTests
{ {
private Mock<IHttpContextRequestHeaderReplacer> _preReplacer; private Mock<IHttpContextRequestHeaderReplacer> _preReplacer;
@ -34,9 +35,7 @@ namespace Ocelot.UnitTests.Headers
_loggerFactory = new Mock<IOcelotLoggerFactory>(); _loggerFactory = new Mock<IOcelotLoggerFactory>();
_logger = new Mock<IOcelotLogger>(); _logger = new Mock<IOcelotLogger>();
_loggerFactory.Setup(x => x.CreateLogger<AuthorisationMiddleware>()).Returns(_logger.Object); _loggerFactory.Setup(x => x.CreateLogger<AuthorisationMiddleware>()).Returns(_logger.Object);
_next = async context => { _next = context => Task.CompletedTask;
//do nothing
};
_middleware = new HttpHeadersTransformationMiddleware(_next, _loggerFactory.Object, _preReplacer.Object, _postReplacer.Object); _middleware = new HttpHeadersTransformationMiddleware(_next, _loggerFactory.Object, _preReplacer.Object, _postReplacer.Object);
} }

View File

@ -4,14 +4,12 @@ namespace Ocelot.UnitTests.Headers
{ {
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Http; using System.Net.Http;
using Microsoft.AspNetCore.Builder; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Moq; using Moq;
using Ocelot.Configuration; using Ocelot.Configuration;
using Ocelot.Configuration.Builder; using Ocelot.Configuration.Builder;
using Ocelot.DownstreamRouteFinder; using Ocelot.DownstreamRouteFinder;
using Ocelot.DownstreamRouteFinder.Middleware;
using Ocelot.DownstreamRouteFinder.UrlMatcher; using Ocelot.DownstreamRouteFinder.UrlMatcher;
using Ocelot.Headers; using Ocelot.Headers;
using Ocelot.Headers.Middleware; using Ocelot.Headers.Middleware;
@ -37,9 +35,7 @@ namespace Ocelot.UnitTests.Headers
_loggerFactory = new Mock<IOcelotLoggerFactory>(); _loggerFactory = new Mock<IOcelotLoggerFactory>();
_logger = new Mock<IOcelotLogger>(); _logger = new Mock<IOcelotLogger>();
_loggerFactory.Setup(x => x.CreateLogger<HttpRequestHeadersBuilderMiddleware>()).Returns(_logger.Object); _loggerFactory.Setup(x => x.CreateLogger<HttpRequestHeadersBuilderMiddleware>()).Returns(_logger.Object);
_next = async context => { _next = context => Task.CompletedTask;
//do nothing
};
_middleware = new HttpRequestHeadersBuilderMiddleware(_next, _loggerFactory.Object, _addHeaders.Object); _middleware = new HttpRequestHeadersBuilderMiddleware(_next, _loggerFactory.Object, _addHeaders.Object);
_downstreamContext.DownstreamRequest = new HttpRequestMessage(); _downstreamContext.DownstreamRequest = new HttpRequestMessage();
} }

View File

@ -19,12 +19,13 @@ namespace Ocelot.UnitTests.LoadBalancer
private readonly LoadBalancerHouse _loadBalancerHouse; private readonly LoadBalancerHouse _loadBalancerHouse;
private Response<ILoadBalancer> _getResult; private Response<ILoadBalancer> _getResult;
private readonly Mock<ILoadBalancerFactory> _factory; private readonly Mock<ILoadBalancerFactory> _factory;
private ServiceProviderConfiguration _serviceProviderConfig; private readonly ServiceProviderConfiguration _serviceProviderConfig;
public LoadBalancerHouseTests() public LoadBalancerHouseTests()
{ {
_factory = new Mock<ILoadBalancerFactory>(); _factory = new Mock<ILoadBalancerFactory>();
_loadBalancerHouse = new LoadBalancerHouse(_factory.Object); _loadBalancerHouse = new LoadBalancerHouse(_factory.Object);
_serviceProviderConfig = new ServiceProviderConfiguration("myType","myHost",123);
} }
[Fact] [Fact]

View File

@ -4,6 +4,7 @@ namespace Ocelot.UnitTests.LoadBalancer
{ {
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Moq; using Moq;
using Ocelot.Configuration; using Ocelot.Configuration;
@ -43,9 +44,7 @@ namespace Ocelot.UnitTests.LoadBalancer
_loggerFactory = new Mock<IOcelotLoggerFactory>(); _loggerFactory = new Mock<IOcelotLoggerFactory>();
_logger = new Mock<IOcelotLogger>(); _logger = new Mock<IOcelotLogger>();
_loggerFactory.Setup(x => x.CreateLogger<LoadBalancingMiddleware>()).Returns(_logger.Object); _loggerFactory.Setup(x => x.CreateLogger<LoadBalancingMiddleware>()).Returns(_logger.Object);
_next = async context => { _next = context => Task.CompletedTask;
//do nothing
};
_downstreamContext.DownstreamRequest = _downstreamRequest; _downstreamContext.DownstreamRequest = _downstreamRequest;
} }

View File

@ -24,7 +24,7 @@ namespace Ocelot.UnitTests.Middleware
{ {
_aggregator = new Mock<IResponseAggregator>(); _aggregator = new Mock<IResponseAggregator>();
_context = new DownstreamContext(new DefaultHttpContext()); _context = new DownstreamContext(new DefaultHttpContext());
_pipeline = async context => { _count++; }; _pipeline = context => Task.FromResult(_count++);
_multiplexer = new Multiplexer(_aggregator.Object); _multiplexer = new Multiplexer(_aggregator.Object);
} }

View File

@ -4,7 +4,6 @@ namespace Ocelot.UnitTests.QueryStrings
{ {
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Http; using System.Net.Http;
using Microsoft.Extensions.DependencyInjection;
using Moq; using Moq;
using Ocelot.Configuration; using Ocelot.Configuration;
using Ocelot.Configuration.Builder; using Ocelot.Configuration.Builder;
@ -17,9 +16,8 @@ namespace Ocelot.UnitTests.QueryStrings
using TestStack.BDDfy; using TestStack.BDDfy;
using Xunit; using Xunit;
using System.Security.Claims; using System.Security.Claims;
using Microsoft.AspNetCore.Builder;
using Ocelot.DownstreamRouteFinder.Middleware;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
public class QueryStringBuilderMiddlewareTests public class QueryStringBuilderMiddlewareTests
{ {
@ -36,9 +34,7 @@ namespace Ocelot.UnitTests.QueryStrings
_loggerFactory = new Mock<IOcelotLoggerFactory>(); _loggerFactory = new Mock<IOcelotLoggerFactory>();
_logger = new Mock<IOcelotLogger>(); _logger = new Mock<IOcelotLogger>();
_loggerFactory.Setup(x => x.CreateLogger<QueryStringBuilderMiddleware>()).Returns(_logger.Object); _loggerFactory.Setup(x => x.CreateLogger<QueryStringBuilderMiddleware>()).Returns(_logger.Object);
_next = async context => { _next = context => Task.CompletedTask;
//do nothing
};
_addQueries = new Mock<IAddQueriesToRequest>(); _addQueries = new Mock<IAddQueriesToRequest>();
_downstreamContext.DownstreamRequest = new HttpRequestMessage(); _downstreamContext.DownstreamRequest = new HttpRequestMessage();
_middleware = new QueryStringBuilderMiddleware(_next, _loggerFactory.Object, _addQueries.Object); _middleware = new QueryStringBuilderMiddleware(_next, _loggerFactory.Object, _addQueries.Object);

View File

@ -15,9 +15,9 @@ namespace Ocelot.UnitTests.RateLimit
using Shouldly; using Shouldly;
using TestStack.BDDfy; using TestStack.BDDfy;
using Xunit; using Xunit;
using Ocelot.DownstreamRouteFinder.Middleware;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using System.IO; using System.IO;
using System.Threading.Tasks;
public class ClientRateLimitMiddlewareTests public class ClientRateLimitMiddlewareTests
{ {
@ -42,8 +42,7 @@ namespace Ocelot.UnitTests.RateLimit
_loggerFactory = new Mock<IOcelotLoggerFactory>(); _loggerFactory = new Mock<IOcelotLoggerFactory>();
_logger = new Mock<IOcelotLogger>(); _logger = new Mock<IOcelotLogger>();
_loggerFactory.Setup(x => x.CreateLogger<ClientRateLimitMiddleware>()).Returns(_logger.Object); _loggerFactory.Setup(x => x.CreateLogger<ClientRateLimitMiddleware>()).Returns(_logger.Object);
_next = async (context) => { _next = context => Task.CompletedTask;
};
_middleware = new ClientRateLimitMiddleware(_next, _loggerFactory.Object, _rateLimitCounterHandler); _middleware = new ClientRateLimitMiddleware(_next, _loggerFactory.Object, _rateLimitCounterHandler);
} }

View File

@ -15,6 +15,7 @@
using System; using System;
using System.IO; using System.IO;
using System.Text; using System.Text;
using System.Security.Cryptography;
public class RequestMapperTests public class RequestMapperTests
{ {
@ -118,19 +119,151 @@
} }
[Fact] [Fact]
public void Should_map_content_type_header() public void Should_handle_no_content()
{ {
this.Given(_ => GivenTheInputRequestHasNoContent())
.And(_ => GivenTheInputRequestHasMethod("GET"))
.And(_ => GivenTheInputRequestHasAValidUri())
.When(_ => WhenMapped())
.Then(_ => ThenNoErrorIsReturned())
.And(_ => ThenTheMappedRequestHasNoContent())
.BDDfy();
}
[Fact]
public void Should_map_content_headers()
{
byte[] md5bytes = new byte[0];
using (var md5 = MD5.Create())
{
md5bytes = md5.ComputeHash(Encoding.UTF8.GetBytes("some md5"));
}
this.Given(_ => GivenTheInputRequestHasContent("This is my content")) this.Given(_ => GivenTheInputRequestHasContent("This is my content"))
.And(_ => GivenTheContentTypeIs("application/json")) .And(_ => GivenTheContentTypeIs("application/json"))
.And(_ => GivenTheContentEncodingIs("gzip, compress"))
.And(_ => GivenTheContentLanguageIs("english"))
.And(_ => GivenTheContentLocationIs("/my-receipts/38"))
.And(_ => GivenTheContentRangeIs("bytes 1-2/*"))
.And(_ => GivenTheContentDispositionIs("inline"))
.And(_ => GivenTheContentMD5Is(md5bytes))
.And(_ => GivenTheInputRequestHasMethod("GET")) .And(_ => GivenTheInputRequestHasMethod("GET"))
.And(_ => GivenTheInputRequestHasAValidUri()) .And(_ => GivenTheInputRequestHasAValidUri())
.When(_ => WhenMapped()) .When(_ => WhenMapped())
.Then(_ => ThenNoErrorIsReturned()) .Then(_ => ThenNoErrorIsReturned())
.And(_ => ThenTheMappedRequestHasContentTypeHeader("application/json")) .And(_ => ThenTheMappedRequestHasContentTypeHeader("application/json"))
.And(_ => ThenTheMappedRequestHasContentEncodingHeader("gzip", "compress"))
.And(_ => ThenTheMappedRequestHasContentLanguageHeader("english"))
.And(_ => ThenTheMappedRequestHasContentLocationHeader("/my-receipts/38"))
.And(_ => ThenTheMappedRequestHasContentMD5Header(md5bytes))
.And(_ => ThenTheMappedRequestHasContentRangeHeader())
.And(_ => ThenTheMappedRequestHasContentDispositionHeader("inline"))
.And(_ => ThenTheMappedRequestHasContentSize("This is my content".Length)) .And(_ => ThenTheMappedRequestHasContentSize("This is my content".Length))
.And(_ => ThenTheContentHeadersAreNotAddedToNonContentHeaders())
.BDDfy(); .BDDfy();
} }
[Fact]
public void should_not_add_content_headers()
{
this.Given(_ => GivenTheInputRequestHasContent("This is my content"))
.And(_ => GivenTheContentTypeIs("application/json"))
.And(_ => GivenTheInputRequestHasMethod("POST"))
.And(_ => GivenTheInputRequestHasAValidUri())
.When(_ => WhenMapped())
.Then(_ => ThenNoErrorIsReturned())
.And(_ => ThenTheMappedRequestHasContentTypeHeader("application/json"))
.And(_ => ThenTheMappedRequestHasContentSize("This is my content".Length))
.And(_ => ThenTheOtherContentTypeHeadersAreNotMapped())
.BDDfy();
}
private void ThenTheContentHeadersAreNotAddedToNonContentHeaders()
{
_mappedRequest.Data.Headers.ShouldNotContain(x => x.Key == "Content-Disposition");
_mappedRequest.Data.Headers.ShouldNotContain(x => x.Key == "Content-ContentMD5");
_mappedRequest.Data.Headers.ShouldNotContain(x => x.Key == "Content-ContentRange");
_mappedRequest.Data.Headers.ShouldNotContain(x => x.Key == "Content-ContentLanguage");
_mappedRequest.Data.Headers.ShouldNotContain(x => x.Key == "Content-ContentEncoding");
_mappedRequest.Data.Headers.ShouldNotContain(x => x.Key == "Content-ContentLocation");
_mappedRequest.Data.Headers.ShouldNotContain(x => x.Key == "Content-Length");
_mappedRequest.Data.Headers.ShouldNotContain(x => x.Key == "Content-Type");
}
private void ThenTheOtherContentTypeHeadersAreNotMapped()
{
_mappedRequest.Data.Content.Headers.ContentDisposition.ShouldBeNull();
_mappedRequest.Data.Content.Headers.ContentMD5.ShouldBeNull();
_mappedRequest.Data.Content.Headers.ContentRange.ShouldBeNull();
_mappedRequest.Data.Content.Headers.ContentLanguage.ShouldBeEmpty();
_mappedRequest.Data.Content.Headers.ContentEncoding.ShouldBeEmpty();
_mappedRequest.Data.Content.Headers.ContentLocation.ShouldBeNull();
}
private void ThenTheMappedRequestHasContentDispositionHeader(string expected)
{
_mappedRequest.Data.Content.Headers.ContentDisposition.DispositionType.ShouldBe(expected);
}
private void GivenTheContentDispositionIs(string input)
{
_inputRequest.Headers.Add("Content-Disposition", input);
}
private void ThenTheMappedRequestHasContentMD5Header(byte[] expected)
{
_mappedRequest.Data.Content.Headers.ContentMD5.ShouldBe(expected);
}
private void GivenTheContentMD5Is(byte[] input)
{
var base64 = Convert.ToBase64String(input);
_inputRequest.Headers.Add("Content-MD5", base64);
}
private void ThenTheMappedRequestHasContentRangeHeader()
{
_mappedRequest.Data.Content.Headers.ContentRange.From.ShouldBe(1);
_mappedRequest.Data.Content.Headers.ContentRange.To.ShouldBe(2);
}
private void GivenTheContentRangeIs(string input)
{
_inputRequest.Headers.Add("Content-Range", input);
}
private void ThenTheMappedRequestHasContentLocationHeader(string expected)
{
_mappedRequest.Data.Content.Headers.ContentLocation.OriginalString.ShouldBe(expected);
}
private void GivenTheContentLocationIs(string input)
{
_inputRequest.Headers.Add("Content-Location", input);
}
private void ThenTheMappedRequestHasContentLanguageHeader(string expected)
{
_mappedRequest.Data.Content.Headers.ContentLanguage.First().ShouldBe(expected);
}
private void GivenTheContentLanguageIs(string input)
{
_inputRequest.Headers.Add("Content-Language", input);
}
private void ThenTheMappedRequestHasContentEncodingHeader(string expected, string expectedTwo)
{
_mappedRequest.Data.Content.Headers.ContentEncoding.ToArray()[0].ShouldBe(expected);
_mappedRequest.Data.Content.Headers.ContentEncoding.ToArray()[1].ShouldBe(expectedTwo);
}
private void GivenTheContentEncodingIs(string input)
{
_inputRequest.Headers.Add("Content-Encoding", input);
}
private void GivenTheContentTypeIs(string contentType) private void GivenTheContentTypeIs(string contentType)
{ {
_inputRequest.ContentType = contentType; _inputRequest.ContentType = contentType;
@ -146,18 +279,6 @@
_mappedRequest.Data.Content.Headers.ContentLength.ShouldBe(expected); _mappedRequest.Data.Content.Headers.ContentLength.ShouldBe(expected);
} }
[Fact]
public void Should_handle_no_content()
{
this.Given(_ => GivenTheInputRequestHasNoContent())
.And(_ => GivenTheInputRequestHasMethod("GET"))
.And(_ => GivenTheInputRequestHasAValidUri())
.When(_ => WhenMapped())
.Then(_ => ThenNoErrorIsReturned())
.And(_ => ThenTheMappedRequestHasNoContent())
.BDDfy();
}
private void GivenTheInputRequestHasMethod(string method) private void GivenTheInputRequestHasMethod(string method)
{ {
_inputRequest.Method = method; _inputRequest.Method = method;

View File

@ -9,6 +9,7 @@ namespace Ocelot.UnitTests.RequestId
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks;
using Moq; using Moq;
using Ocelot.Configuration.Builder; using Ocelot.Configuration.Builder;
using Ocelot.DownstreamRouteFinder; using Ocelot.DownstreamRouteFinder;
@ -40,8 +41,10 @@ namespace Ocelot.UnitTests.RequestId
_loggerFactory = new Mock<IOcelotLoggerFactory>(); _loggerFactory = new Mock<IOcelotLoggerFactory>();
_logger = new Mock<IOcelotLogger>(); _logger = new Mock<IOcelotLogger>();
_loggerFactory.Setup(x => x.CreateLogger<ReRouteRequestIdMiddleware>()).Returns(_logger.Object); _loggerFactory.Setup(x => x.CreateLogger<ReRouteRequestIdMiddleware>()).Returns(_logger.Object);
_next = async context => { _next = context =>
{
context.HttpContext.Response.Headers.Add("LSRequestId", context.HttpContext.TraceIdentifier); context.HttpContext.Response.Headers.Add("LSRequestId", context.HttpContext.TraceIdentifier);
return Task.CompletedTask;
}; };
_middleware = new ReRouteRequestIdMiddleware(_next, _loggerFactory.Object, _repo.Object); _middleware = new ReRouteRequestIdMiddleware(_next, _loggerFactory.Object, _repo.Object);
_downstreamContext.DownstreamRequest = _downstreamRequest; _downstreamContext.DownstreamRequest = _downstreamRequest;

View File

@ -1,137 +0,0 @@
using System;
using System.Net.Http;
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Errors;
using Ocelot.Requester;
using Ocelot.Responses;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Requester
{
public class DelegatingHandlerHandlerHouseTests
{
private readonly DelegatingHandlerHandlerHouse _house;
private Mock<IDelegatingHandlerHandlerProviderFactory> _factory;
private readonly Mock<IDelegatingHandlerHandlerProvider> _provider;
private DownstreamReRoute _request;
private Response<IDelegatingHandlerHandlerProvider> _result;
public DelegatingHandlerHandlerHouseTests()
{
_provider = new Mock<IDelegatingHandlerHandlerProvider>();
_factory = new Mock<IDelegatingHandlerHandlerProviderFactory>();
_house = new DelegatingHandlerHandlerHouse(_factory.Object);
}
[Fact]
public void should_create_and_store_provider()
{
var reRoute = new DownstreamReRouteBuilder().WithIsQos(true)
.WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false)).WithReRouteKey("key").Build();
this.Given(x => GivenTheRequest(reRoute))
.And(x => GivenTheProviderReturns())
.When(x => WhenIGet())
.Then(x => ThenTheFactoryIsCalled(1))
.And(x => ThenTheProviderIsNotNull())
.BDDfy();
}
[Fact]
public void should_get_provider()
{
var reRoute = new DownstreamReRouteBuilder().WithIsQos(true)
.WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false)).WithReRouteKey("key").Build();
this.Given(x => GivenTheRequest(reRoute))
.And(x => GivenTheProviderReturns())
.And(x => WhenIGet())
.And(x => GivenTheFactoryIsCleared())
.When(x => WhenIGet())
.Then(x => ThenTheFactoryIsCalled(0))
.And(x => ThenTheProviderIsNotNull())
.BDDfy();
}
[Fact]
public void should_return_error()
{
var reRoute = new DownstreamReRouteBuilder().WithIsQos(true)
.WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false)).WithReRouteKey("key").Build();
this.Given(x => GivenTheRequest(reRoute))
.And(x => GivenTheProviderThrows())
.When(x => WhenIGet())
.And(x => ThenAnErrorIsReturned())
.BDDfy();
}
[Fact]
public void should_return_error_if_factory_errors()
{
var reRoute = new DownstreamReRouteBuilder().WithIsQos(true)
.WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false)).WithReRouteKey("key").Build();
this.Given(x => GivenTheRequest(reRoute))
.And(x => GivenTheProviderReturnsError())
.When(x => WhenIGet())
.Then(x => ThenAnUnknownErrorIsReturned())
.BDDfy();
}
private void ThenAnUnknownErrorIsReturned()
{
_result.IsError.ShouldBeTrue();
}
private void ThenAnErrorIsReturned()
{
_result.IsError.ShouldBeTrue();
_result.Errors[0].ShouldBeOfType<UnableToFindDelegatingHandlerProviderError>();
}
private void GivenTheProviderThrows()
{
_factory.Setup(x => x.Get(It.IsAny<DownstreamReRoute>())).Throws<Exception>();
}
private void GivenTheFactoryIsCleared()
{
_factory = new Mock<IDelegatingHandlerHandlerProviderFactory>();
}
private void ThenTheProviderIsNotNull()
{
_result.Data.ShouldBe(_provider.Object);
}
private void WhenIGet()
{
_result = _house.Get(_request);
}
private void GivenTheRequest(DownstreamReRoute request)
{
_request = request;
}
private void GivenTheProviderReturns()
{
_factory.Setup(x => x.Get(It.IsAny<DownstreamReRoute>())).Returns(new OkResponse<IDelegatingHandlerHandlerProvider>(_provider.Object));
}
private void GivenTheProviderReturnsError()
{
_factory.Setup(x => x.Get(It.IsAny<DownstreamReRoute>())).Returns(new ErrorResponse<IDelegatingHandlerHandlerProvider>(It.IsAny<Error>()));
}
private void ThenTheFactoryIsCalled(int times)
{
_factory.Verify(x => x.Get(_request), Times.Exactly(times));
}
}
}

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Http; using System.Net.Http;
using Microsoft.Extensions.DependencyInjection;
using Moq; using Moq;
using Ocelot.Configuration; using Ocelot.Configuration;
using Ocelot.Configuration.Builder; using Ocelot.Configuration.Builder;
@ -17,45 +18,30 @@ namespace Ocelot.UnitTests.Requester
{ {
public class DelegatingHandlerHandlerProviderFactoryTests public class DelegatingHandlerHandlerProviderFactoryTests
{ {
private readonly DelegatingHandlerHandlerProviderFactory _factory; private DelegatingHandlerHandlerFactory _factory;
private Mock<IOcelotLoggerFactory> _loggerFactory; private Mock<IOcelotLoggerFactory> _loggerFactory;
private DownstreamReRoute _request; private DownstreamReRoute _request;
private Response<IDelegatingHandlerHandlerProvider> _provider; private Response<List<Func<DelegatingHandler>>> _provider;
private readonly Mock<IDelegatingHandlerHandlerProvider> _allRoutesProvider;
private readonly Mock<IQosProviderHouse> _qosProviderHouse; private readonly Mock<IQosProviderHouse> _qosProviderHouse;
private readonly Mock<ITracingHandlerFactory> _tracingFactory; private readonly Mock<ITracingHandlerFactory> _tracingFactory;
private IServiceProvider _serviceProvider;
public DelegatingHandlerHandlerProviderFactoryTests() public DelegatingHandlerHandlerProviderFactoryTests()
{ {
_tracingFactory = new Mock<ITracingHandlerFactory>(); _tracingFactory = new Mock<ITracingHandlerFactory>();
_qosProviderHouse = new Mock<IQosProviderHouse>(); _qosProviderHouse = new Mock<IQosProviderHouse>();
_allRoutesProvider = new Mock<IDelegatingHandlerHandlerProvider>();
_loggerFactory = new Mock<IOcelotLoggerFactory>(); _loggerFactory = new Mock<IOcelotLoggerFactory>();
_factory = new DelegatingHandlerHandlerProviderFactory(_loggerFactory.Object, _allRoutesProvider.Object, _tracingFactory.Object, _qosProviderHouse.Object);
}
private void GivenTheQosProviderHouseReturns(Response<IQoSProvider> qosProvider)
{
_qosProviderHouse
.Setup(x => x.Get(It.IsAny<DownstreamReRoute>()))
.Returns(qosProvider);
} }
[Fact] [Fact]
public void should_all_from_all_routes_provider_and_qos() public void should_all_from_all_routes_provider_and_qos()
{ {
var handlers = new List<Func<DelegatingHandler>>
{
() => new FakeDelegatingHandler(0),
() => new FakeDelegatingHandler(1)
};
var reRoute = new DownstreamReRouteBuilder().WithIsQos(true) var reRoute = new DownstreamReRouteBuilder().WithIsQos(true)
.WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false)).WithReRouteKey("").Build(); .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false)).WithReRouteKey("").Build();
this.Given(x => GivenTheFollowingRequest(reRoute)) this.Given(x => GivenTheFollowingRequest(reRoute))
.And(x => GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(It.IsAny<PollyQoSProvider>()))) .And(x => GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(It.IsAny<PollyQoSProvider>())))
.And(x => GivenTheAllRoutesProviderReturns(handlers)) .And(x => GivenTheServiceProviderReturns<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
.When(x => WhenIGet()) .When(x => WhenIGet())
.Then(x => ThenThereIsDelegatesInProvider(3)) .Then(x => ThenThereIsDelegatesInProvider(3))
.And(x => ThenTheDelegatesAreAddedCorrectly()) .And(x => ThenTheDelegatesAreAddedCorrectly())
@ -70,7 +56,7 @@ namespace Ocelot.UnitTests.Requester
.WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false)).WithReRouteKey("").Build(); .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false)).WithReRouteKey("").Build();
this.Given(x => GivenTheFollowingRequest(reRoute)) this.Given(x => GivenTheFollowingRequest(reRoute))
.And(x => GivenTheAllRoutesProviderReturns()) .And(x => GivenTheServiceProviderReturnsNothing())
.When(x => WhenIGet()) .When(x => WhenIGet())
.Then(x => ThenNoDelegatesAreInTheProvider()) .Then(x => ThenNoDelegatesAreInTheProvider())
.BDDfy(); .BDDfy();
@ -84,7 +70,7 @@ namespace Ocelot.UnitTests.Requester
this.Given(x => GivenTheFollowingRequest(reRoute)) this.Given(x => GivenTheFollowingRequest(reRoute))
.And(x => GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(It.IsAny<PollyQoSProvider>()))) .And(x => GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(It.IsAny<PollyQoSProvider>())))
.And(x => GivenTheAllRoutesProviderReturns()) .And(x => GivenTheServiceProviderReturnsNothing())
.When(x => WhenIGet()) .When(x => WhenIGet())
.Then(x => ThenThereIsDelegatesInProvider(1)) .Then(x => ThenThereIsDelegatesInProvider(1))
.And(x => ThenItIsPolly(0)) .And(x => ThenItIsPolly(0))
@ -99,12 +85,28 @@ namespace Ocelot.UnitTests.Requester
this.Given(x => GivenTheFollowingRequest(reRoute)) this.Given(x => GivenTheFollowingRequest(reRoute))
.And(x => GivenTheQosProviderHouseReturns(new ErrorResponse<IQoSProvider>(It.IsAny<Error>()))) .And(x => GivenTheQosProviderHouseReturns(new ErrorResponse<IQoSProvider>(It.IsAny<Error>())))
.And(x => GivenTheAllRoutesProviderReturns()) .And(x => GivenTheServiceProviderReturnsNothing())
.When(x => WhenIGet()) .When(x => WhenIGet())
.Then(x => ThenAnErrorIsReturned()) .Then(x => ThenAnErrorIsReturned())
.BDDfy(); .BDDfy();
} }
private void GivenTheServiceProviderReturns<TOne, TTwo>()
where TOne : DelegatingHandler
where TTwo : DelegatingHandler
{
IServiceCollection services = new ServiceCollection();
services.AddSingleton<DelegatingHandler, TOne>();
services.AddSingleton<DelegatingHandler, TTwo>();
_serviceProvider = services.BuildServiceProvider();
}
private void GivenTheServiceProviderReturnsNothing()
{
IServiceCollection services = new ServiceCollection();
_serviceProvider = services.BuildServiceProvider();
}
private void ThenAnErrorIsReturned() private void ThenAnErrorIsReturned()
{ {
_provider.IsError.ShouldBeTrue(); _provider.IsError.ShouldBeTrue();
@ -112,29 +114,27 @@ namespace Ocelot.UnitTests.Requester
private void ThenTheDelegatesAreAddedCorrectly() private void ThenTheDelegatesAreAddedCorrectly()
{ {
var delegates = _provider.Data.Get(); var delegates = _provider.Data;
var del = delegates[0].Invoke(); var del = delegates[0].Invoke();
var handler = (FakeDelegatingHandler) del; var handler = (FakeDelegatingHandler) del;
handler.Order.ShouldBe(0); handler.Order.ShouldBe(1);
del = delegates[1].Invoke(); del = delegates[1].Invoke();
handler = (FakeDelegatingHandler)del; var handlerTwo = (FakeDelegatingHandlerTwo) del;
handler.Order.ShouldBe(1); handlerTwo.Order.ShouldBe(2);
} }
private void GivenTheAllRoutesProviderReturns() private void GivenTheQosProviderHouseReturns(Response<IQoSProvider> qosProvider)
{ {
_allRoutesProvider.Setup(x => x.Get()).Returns(new List<Func<DelegatingHandler>>()); _qosProviderHouse
} .Setup(x => x.Get(It.IsAny<DownstreamReRoute>()))
.Returns(qosProvider);
private void GivenTheAllRoutesProviderReturns(List<Func<DelegatingHandler>> handlers)
{
_allRoutesProvider.Setup(x => x.Get()).Returns(handlers);
} }
private void ThenItIsPolly(int i) private void ThenItIsPolly(int i)
{ {
var delegates = _provider.Data.Get(); var delegates = _provider.Data;
var del = delegates[i].Invoke(); var del = delegates[i].Invoke();
del.ShouldBeOfType<PollyCircuitBreakingDelegatingHandler>(); del.ShouldBeOfType<PollyCircuitBreakingDelegatingHandler>();
} }
@ -142,7 +142,7 @@ namespace Ocelot.UnitTests.Requester
private void ThenThereIsDelegatesInProvider(int count) private void ThenThereIsDelegatesInProvider(int count)
{ {
_provider.ShouldNotBeNull(); _provider.ShouldNotBeNull();
_provider.Data.Get().Count.ShouldBe(count); _provider.Data.Count.ShouldBe(count);
} }
private void GivenTheFollowingRequest(DownstreamReRoute request) private void GivenTheFollowingRequest(DownstreamReRoute request)
@ -152,13 +152,14 @@ namespace Ocelot.UnitTests.Requester
private void WhenIGet() private void WhenIGet()
{ {
_factory = new DelegatingHandlerHandlerFactory(_loggerFactory.Object, _tracingFactory.Object, _qosProviderHouse.Object, _serviceProvider);
_provider = _factory.Get(_request); _provider = _factory.Get(_request);
} }
private void ThenNoDelegatesAreInTheProvider() private void ThenNoDelegatesAreInTheProvider()
{ {
_provider.ShouldNotBeNull(); _provider.ShouldNotBeNull();
_provider.Data.Get().Count.ShouldBe(0); _provider.Data.Count.ShouldBe(0);
} }
} }
} }

View File

@ -1,62 +0,0 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using Ocelot.Requester;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Requester
{
public class DelegatingHandlerHandlerProviderTests
{
private readonly DelegatingHandlerHandlerProvider _provider;
private List<Func<DelegatingHandler>> _handlers;
public DelegatingHandlerHandlerProviderTests()
{
_provider = new DelegatingHandlerHandlerProvider();
}
[Fact]
public void should_return_empty_list()
{
this.When(x => WhenIGet())
.Then(x => ThenAnEmptyListIsReturned())
.BDDfy();
}
[Fact]
public void should_get_delegating_handlers_in_order_first_in_first_out()
{
this.Given(x => GivenTheHandlers())
.When(x => WhenIGet())
.Then(x => ThenTheHandlersAreReturnedInOrder())
.BDDfy();
}
private void ThenAnEmptyListIsReturned()
{
_handlers.Count.ShouldBe(0);
}
private void ThenTheHandlersAreReturnedInOrder()
{
var handler = (FakeDelegatingHandler)_handlers[0].Invoke();
handler.Order.ShouldBe(0);
handler = (FakeDelegatingHandler)_handlers[1].Invoke();
handler.Order.ShouldBe(1);
}
private void WhenIGet()
{
_handlers = _provider.Get();
}
private void GivenTheHandlers()
{
_provider.Add(() => new FakeDelegatingHandler(0));
_provider.Add(() => new FakeDelegatingHandler(1));
}
}
}

View File

@ -9,6 +9,7 @@ namespace Ocelot.UnitTests.Requester
{ {
public FakeDelegatingHandler() public FakeDelegatingHandler()
{ {
Order = 1;
} }
public FakeDelegatingHandler(int order) public FakeDelegatingHandler(int order)
@ -16,6 +17,24 @@ namespace Ocelot.UnitTests.Requester
Order = order; Order = order;
} }
public int Order {get;private set;}
public DateTime TimeCalled {get;private set;}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
TimeCalled = DateTime.Now;
return Task.FromResult(new HttpResponseMessage());
}
}
public class FakeDelegatingHandlerTwo : DelegatingHandler
{
public FakeDelegatingHandlerTwo()
{
Order = 2;
}
public int Order {get;private set;} public int Order {get;private set;}
public DateTime TimeCalled {get;private set;} public DateTime TimeCalled {get;private set;}

View File

@ -15,25 +15,22 @@ namespace Ocelot.UnitTests.Requester
public class HttpClientBuilderTests public class HttpClientBuilderTests
{ {
private readonly HttpClientBuilder _builder; private readonly HttpClientBuilder _builder;
private readonly Mock<IDelegatingHandlerHandlerHouse> _house; private readonly Mock<IDelegatingHandlerHandlerFactory> _factory;
private readonly Mock<IDelegatingHandlerHandlerProvider> _provider;
private IHttpClient _httpClient; private IHttpClient _httpClient;
private HttpResponseMessage _response; private HttpResponseMessage _response;
private DownstreamReRoute _request; private DownstreamReRoute _request;
public HttpClientBuilderTests() public HttpClientBuilderTests()
{ {
_provider = new Mock<IDelegatingHandlerHandlerProvider>(); _factory = new Mock<IDelegatingHandlerHandlerFactory>();
_house = new Mock<IDelegatingHandlerHandlerHouse>(); _builder = new HttpClientBuilder(_factory.Object);
_builder = new HttpClientBuilder(_house.Object);
} }
[Fact] [Fact]
public void should_build_http_client() public void should_build_http_client()
{ {
this.Given(x => GivenTheProviderReturns()) this.Given(x => GivenTheFactoryReturns())
.And(x => GivenARequest()) .And(x => GivenARequest())
.And(x => GivenTheHouseReturns())
.When(x => WhenIBuild()) .When(x => WhenIBuild())
.Then(x => ThenTheHttpClientShouldNotBeNull()) .Then(x => ThenTheHttpClientShouldNotBeNull())
.BDDfy(); .BDDfy();
@ -51,9 +48,8 @@ namespace Ocelot.UnitTests.Requester
() => fakeTwo () => fakeTwo
}; };
this.Given(x => GivenTheProviderReturns(handlers)) this.Given(x => GivenTheFactoryReturns(handlers))
.And(x => GivenARequest()) .And(x => GivenARequest())
.And(x => GivenTheHouseReturns())
.And(x => WhenIBuild()) .And(x => WhenIBuild())
.When(x => WhenICallTheClient()) .When(x => WhenICallTheClient())
.Then(x => ThenTheFakeAreHandledInOrder(fakeOne, fakeTwo)) .Then(x => ThenTheFakeAreHandledInOrder(fakeOne, fakeTwo))
@ -69,13 +65,6 @@ namespace Ocelot.UnitTests.Requester
_request = reRoute; _request = reRoute;
} }
private void GivenTheHouseReturns()
{
_house
.Setup(x => x.Get(It.IsAny<DownstreamReRoute>()))
.Returns(new OkResponse<IDelegatingHandlerHandlerProvider>(_provider.Object));
}
private void ThenSomethingIsReturned() private void ThenSomethingIsReturned()
{ {
_response.ShouldNotBeNull(); _response.ShouldNotBeNull();
@ -91,18 +80,20 @@ namespace Ocelot.UnitTests.Requester
fakeOne.TimeCalled.ShouldBeGreaterThan(fakeTwo.TimeCalled); fakeOne.TimeCalled.ShouldBeGreaterThan(fakeTwo.TimeCalled);
} }
private void GivenTheProviderReturns() private void GivenTheFactoryReturns()
{ {
_provider var handlers = new List<Func<DelegatingHandler>>(){ () => new FakeDelegatingHandler()};
.Setup(x => x.Get())
.Returns(new List<Func<DelegatingHandler>>(){ () => new FakeDelegatingHandler()}); _factory
.Setup(x => x.Get(It.IsAny<DownstreamReRoute>()))
.Returns(new OkResponse<List<Func<DelegatingHandler>>>(handlers));
} }
private void GivenTheProviderReturns(List<Func<DelegatingHandler>> handlers) private void GivenTheFactoryReturns(List<Func<DelegatingHandler>> handlers)
{ {
_provider _factory
.Setup(x => x.Get()) .Setup(x => x.Get(It.IsAny<DownstreamReRoute>()))
.Returns(handlers); .Returns(new OkResponse<List<Func<DelegatingHandler>>>(handlers));
} }
private void WhenIBuild() private void WhenIBuild()

View File

@ -18,8 +18,7 @@ namespace Ocelot.UnitTests.Requester
public class HttpClientHttpRequesterTest public class HttpClientHttpRequesterTest
{ {
private readonly Mock<IHttpClientCache> _cacheHandlers; private readonly Mock<IHttpClientCache> _cacheHandlers;
private Mock<IDelegatingHandlerHandlerHouse> _house; private Mock<IDelegatingHandlerHandlerFactory> _house;
private Mock<IDelegatingHandlerHandlerProvider> _provider;
private Response<HttpResponseMessage> _response; private Response<HttpResponseMessage> _response;
private readonly HttpClientHttpRequester _httpClientRequester; private readonly HttpClientHttpRequester _httpClientRequester;
private DownstreamContext _request; private DownstreamContext _request;
@ -28,10 +27,8 @@ namespace Ocelot.UnitTests.Requester
public HttpClientHttpRequesterTest() public HttpClientHttpRequesterTest()
{ {
_provider = new Mock<IDelegatingHandlerHandlerProvider>(); _house = new Mock<IDelegatingHandlerHandlerFactory>();
_provider.Setup(x => x.Get()).Returns(new List<Func<DelegatingHandler>>()); _house.Setup(x => x.Get(It.IsAny<DownstreamReRoute>())).Returns(new OkResponse<List<Func<DelegatingHandler>>>(new List<Func<DelegatingHandler>>()));
_house = new Mock<IDelegatingHandlerHandlerHouse>();
_house.Setup(x => x.Get(It.IsAny<DownstreamReRoute>())).Returns(new OkResponse<IDelegatingHandlerHandlerProvider>(_provider.Object));
_logger = new Mock<IOcelotLogger>(); _logger = new Mock<IOcelotLogger>();
_loggerFactory = new Mock<IOcelotLoggerFactory>(); _loggerFactory = new Mock<IOcelotLoggerFactory>();
_loggerFactory _loggerFactory

View File

@ -13,6 +13,7 @@ namespace Ocelot.UnitTests.Requester
using TestStack.BDDfy; using TestStack.BDDfy;
using Xunit; using Xunit;
using Shouldly; using Shouldly;
using System.Threading.Tasks;
public class HttpRequesterMiddlewareTests public class HttpRequesterMiddlewareTests
{ {
@ -30,9 +31,7 @@ namespace Ocelot.UnitTests.Requester
_loggerFactory = new Mock<IOcelotLoggerFactory>(); _loggerFactory = new Mock<IOcelotLoggerFactory>();
_logger = new Mock<IOcelotLogger>(); _logger = new Mock<IOcelotLogger>();
_loggerFactory.Setup(x => x.CreateLogger<HttpRequesterMiddleware>()).Returns(_logger.Object); _loggerFactory.Setup(x => x.CreateLogger<HttpRequesterMiddleware>()).Returns(_logger.Object);
_next = async context => { _next = context => Task.CompletedTask;
//do nothing
};
_middleware = new HttpRequesterMiddleware(_next, _loggerFactory.Object, _requester.Object); _middleware = new HttpRequesterMiddleware(_next, _loggerFactory.Object, _requester.Object);
} }

View File

@ -5,6 +5,7 @@ namespace Ocelot.UnitTests.Responder
{ {
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks;
using Moq; using Moq;
using Ocelot.DownstreamRouteFinder.Finder; using Ocelot.DownstreamRouteFinder.Finder;
using Ocelot.Errors; using Ocelot.Errors;
@ -32,9 +33,7 @@ namespace Ocelot.UnitTests.Responder
_loggerFactory = new Mock<IOcelotLoggerFactory>(); _loggerFactory = new Mock<IOcelotLoggerFactory>();
_logger = new Mock<IOcelotLogger>(); _logger = new Mock<IOcelotLogger>();
_loggerFactory.Setup(x => x.CreateLogger<ResponderMiddleware>()).Returns(_logger.Object); _loggerFactory.Setup(x => x.CreateLogger<ResponderMiddleware>()).Returns(_logger.Object);
_next = async context => { _next = context => Task.CompletedTask;
//do nothing
};
_middleware = new ResponderMiddleware(_next, _responder.Object, _loggerFactory.Object, _codeMapper.Object); _middleware = new ResponderMiddleware(_next, _responder.Object, _loggerFactory.Object, _codeMapper.Object);
} }