mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-04-22 06:42:50 +08:00
Merge branch 'release-3.0.3'
This commit is contained in:
commit
065a013433
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio 15
|
||||||
VisualStudioVersion = 15.0.26730.15
|
VisualStudioVersion = 15.0.27130.2024
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{5CFB79B7-C9DC-45A4-9A75-625D92471702}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{5CFB79B7-C9DC-45A4-9A75-625D92471702}"
|
||||||
EndProject
|
EndProject
|
||||||
|
@ -158,14 +158,15 @@ if(-Not $SkipToolPackageRestore.IsPresent) {
|
|||||||
if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or
|
if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or
|
||||||
($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) {
|
($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) {
|
||||||
Write-Verbose -Message "Missing or changed package.config hash..."
|
Write-Verbose -Message "Missing or changed package.config hash..."
|
||||||
Remove-Item * -Recurse -Exclude packages.config,nuget.exe
|
Get-ChildItem -Exclude packages.config,nuget.exe,Cake.Bakery |
|
||||||
|
Remove-Item -Recurse
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Verbose -Message "Restoring tools from NuGet..."
|
Write-Verbose -Message "Restoring tools from NuGet..."
|
||||||
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`""
|
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`""
|
||||||
|
|
||||||
if ($LASTEXITCODE -ne 0) {
|
if ($LASTEXITCODE -ne 0) {
|
||||||
Throw "An error occured while restoring NuGet tools."
|
Throw "An error occurred while restoring NuGet tools."
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -185,7 +186,7 @@ if (Test-Path $ADDINS_PACKAGES_CONFIG) {
|
|||||||
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$ADDINS_DIR`""
|
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$ADDINS_DIR`""
|
||||||
|
|
||||||
if ($LASTEXITCODE -ne 0) {
|
if ($LASTEXITCODE -ne 0) {
|
||||||
Throw "An error occured while restoring NuGet addins."
|
Throw "An error occurred while restoring NuGet addins."
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Verbose -Message ($NuGetOutput | out-string)
|
Write-Verbose -Message ($NuGetOutput | out-string)
|
||||||
@ -202,7 +203,7 @@ if (Test-Path $MODULES_PACKAGES_CONFIG) {
|
|||||||
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$MODULES_DIR`""
|
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$MODULES_DIR`""
|
||||||
|
|
||||||
if ($LASTEXITCODE -ne 0) {
|
if ($LASTEXITCODE -ne 0) {
|
||||||
Throw "An error occured while restoring NuGet modules."
|
Throw "An error occurred while restoring NuGet modules."
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Verbose -Message ($NuGetOutput | out-string)
|
Write-Verbose -Message ($NuGetOutput | out-string)
|
||||||
|
@ -61,7 +61,8 @@ Here is an example ReRoute configuration, You don't need to set all of these thi
|
|||||||
},
|
},
|
||||||
"HttpHandlerOptions": {
|
"HttpHandlerOptions": {
|
||||||
"AllowAutoRedirect": true,
|
"AllowAutoRedirect": true,
|
||||||
"UseCookieContainer": true
|
"UseCookieContainer": true,
|
||||||
|
"UseTracing": true
|
||||||
},
|
},
|
||||||
"UseServiceDiscovery": false
|
"UseServiceDiscovery": false
|
||||||
}
|
}
|
||||||
|
43
docs/features/delegatinghandlers.rst
Normal file
43
docs/features/delegatinghandlers.rst
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
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.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
^^^^^^
|
||||||
|
|
||||||
|
In order to add delegating handlers to the HttpClient transport you need to do the following.
|
||||||
|
|
||||||
|
.. code-block:: csharp
|
||||||
|
|
||||||
|
services.AddOcelot()
|
||||||
|
.AddDelegatingHandler(() => new FakeHandler())
|
||||||
|
.AddDelegatingHandler(() => new FakeHandler());
|
||||||
|
|
||||||
|
Or for singleton like behaviour..
|
||||||
|
|
||||||
|
.. code-block:: csharp
|
||||||
|
|
||||||
|
var handlerOne = new FakeHandler();
|
||||||
|
var handlerTwo = new FakeHandler();
|
||||||
|
|
||||||
|
services.AddOcelot()
|
||||||
|
.AddDelegatingHandler(() => handlerOne)
|
||||||
|
.AddDelegatingHandler(() => handlerTwo);
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
In order to create a class that can be used a delegating handler it must look as follows
|
||||||
|
|
||||||
|
.. code-block:: csharp
|
||||||
|
|
||||||
|
public class FakeHandler : DelegatingHandler
|
||||||
|
{
|
||||||
|
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
//do stuff and optionally call the base handler..
|
||||||
|
return await base.SendAsync(request, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Hopefully other people will find this feature useful!
|
31
docs/features/tracing.rst
Normal file
31
docs/features/tracing.rst
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
Tracing
|
||||||
|
=======
|
||||||
|
|
||||||
|
Ocelot providers tracing functionality from the excellent `Butterfly <https://github.com/ButterflyAPM>`_ project.
|
||||||
|
|
||||||
|
In order to use the tracing please read the Butterfly documentation.
|
||||||
|
|
||||||
|
In ocelot you need to do the following if you wish to trace a ReRoute.
|
||||||
|
|
||||||
|
In your ConfigureServices method
|
||||||
|
|
||||||
|
.. code-block:: csharp
|
||||||
|
|
||||||
|
services
|
||||||
|
.AddOcelot(Configuration)
|
||||||
|
.AddOpenTracing(option =>
|
||||||
|
{
|
||||||
|
//this is the url that the butterfly collector server is running on...
|
||||||
|
option.CollectorUrl = "http://localhost:9618";
|
||||||
|
option.Service = "Ocelot";
|
||||||
|
});
|
||||||
|
|
||||||
|
Then in your configuration.json add the following to the ReRoute you want to trace..
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
"HttpHandlerOptions": {
|
||||||
|
"UseTracing": true
|
||||||
|
},
|
||||||
|
|
||||||
|
Ocelot will now send tracing information to Butterfly when this ReRoute is called.
|
@ -30,9 +30,12 @@ Thanks for taking a look at the Ocelot documentation. Please use the left hand n
|
|||||||
features/headerstransformation
|
features/headerstransformation
|
||||||
features/claimstransformation
|
features/claimstransformation
|
||||||
features/logging
|
features/logging
|
||||||
|
features/tracing
|
||||||
features/requestid
|
features/requestid
|
||||||
features/middlewareinjection
|
features/middlewareinjection
|
||||||
features/loadbalancer
|
features/loadbalancer
|
||||||
|
features/delegatinghandlers
|
||||||
|
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"projects": [ "src", "test" ],
|
"projects": [ "src", "test" ],
|
||||||
"sdk": {
|
"sdk": {
|
||||||
"version": "2.0.2"
|
"version": "2.1.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,7 +7,7 @@ namespace Ocelot.Configuration.Creator
|
|||||||
public HttpHandlerOptions Create(FileReRoute fileReRoute)
|
public HttpHandlerOptions Create(FileReRoute fileReRoute)
|
||||||
{
|
{
|
||||||
return new HttpHandlerOptions(fileReRoute.HttpHandlerOptions.AllowAutoRedirect,
|
return new HttpHandlerOptions(fileReRoute.HttpHandlerOptions.AllowAutoRedirect,
|
||||||
fileReRoute.HttpHandlerOptions.UseCookieContainer);
|
fileReRoute.HttpHandlerOptions.UseCookieContainer, fileReRoute.HttpHandlerOptions.UseTracing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,5 +11,7 @@
|
|||||||
public bool AllowAutoRedirect { get; set; }
|
public bool AllowAutoRedirect { get; set; }
|
||||||
|
|
||||||
public bool UseCookieContainer { get; set; }
|
public bool UseCookieContainer { get; set; }
|
||||||
|
|
||||||
|
public bool UseTracing { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,11 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class HttpHandlerOptions
|
public class HttpHandlerOptions
|
||||||
{
|
{
|
||||||
public HttpHandlerOptions(bool allowAutoRedirect, bool useCookieContainer)
|
public HttpHandlerOptions(bool allowAutoRedirect, bool useCookieContainer, bool useTracing)
|
||||||
{
|
{
|
||||||
AllowAutoRedirect = allowAutoRedirect;
|
AllowAutoRedirect = allowAutoRedirect;
|
||||||
UseCookieContainer = useCookieContainer;
|
UseCookieContainer = useCookieContainer;
|
||||||
|
UseTracing = useTracing;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -21,5 +22,10 @@
|
|||||||
/// Specify is handler has to use a cookie container
|
/// Specify is handler has to use a cookie container
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool UseCookieContainer { get; private set; }
|
public bool UseCookieContainer { get; private set; }
|
||||||
|
|
||||||
|
// <summary>
|
||||||
|
/// Specify is handler has to use a opentracing
|
||||||
|
/// </summary>
|
||||||
|
public bool UseTracing { get; private set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
namespace Ocelot.DependencyInjection
|
||||||
|
{
|
||||||
|
public interface IOcelotAdministrationBuilder
|
||||||
|
{
|
||||||
|
IOcelotAdministrationBuilder AddRafty();
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
|
using Butterfly.Client.AspNetCore;
|
||||||
using CacheManager.Core;
|
using CacheManager.Core;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
|
||||||
namespace Ocelot.DependencyInjection
|
namespace Ocelot.DependencyInjection
|
||||||
{
|
{
|
||||||
@ -7,6 +9,8 @@ namespace Ocelot.DependencyInjection
|
|||||||
{
|
{
|
||||||
IOcelotBuilder AddStoreOcelotConfigurationInConsul();
|
IOcelotBuilder AddStoreOcelotConfigurationInConsul();
|
||||||
IOcelotBuilder AddCacheManager(Action<ConfigurationBuilderCachePart> settings);
|
IOcelotBuilder AddCacheManager(Action<ConfigurationBuilderCachePart> settings);
|
||||||
|
IOcelotBuilder AddOpenTracing(Action<ButterflyOptions> settings);
|
||||||
IOcelotAdministrationBuilder AddAdministration(string path, string secret);
|
IOcelotAdministrationBuilder AddAdministration(string path, string secret);
|
||||||
|
IOcelotBuilder AddDelegatingHandler(Func<DelegatingHandler> delegatingHandler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Ocelot.Raft;
|
||||||
|
using Rafty.Concensus;
|
||||||
|
using Rafty.FiniteStateMachine;
|
||||||
|
using Rafty.Infrastructure;
|
||||||
|
using Rafty.Log;
|
||||||
|
|
||||||
|
namespace Ocelot.DependencyInjection
|
||||||
|
{
|
||||||
|
public class OcelotAdministrationBuilder : IOcelotAdministrationBuilder
|
||||||
|
{
|
||||||
|
private readonly IServiceCollection _services;
|
||||||
|
private readonly IConfiguration _configurationRoot;
|
||||||
|
|
||||||
|
public OcelotAdministrationBuilder(IServiceCollection services, IConfiguration configurationRoot)
|
||||||
|
{
|
||||||
|
_configurationRoot = configurationRoot;
|
||||||
|
_services = services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IOcelotAdministrationBuilder AddRafty()
|
||||||
|
{
|
||||||
|
var settings = new InMemorySettings(4000, 5000, 100, 5000);
|
||||||
|
_services.AddSingleton<ILog, SqlLiteLog>();
|
||||||
|
_services.AddSingleton<IFiniteStateMachine, OcelotFiniteStateMachine>();
|
||||||
|
_services.AddSingleton<ISettings>(settings);
|
||||||
|
_services.AddSingleton<IPeersProvider, FilePeersProvider>();
|
||||||
|
_services.AddSingleton<INode, Node>();
|
||||||
|
_services.Configure<FilePeers>(_configurationRoot);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -35,7 +35,6 @@ using Ocelot.ServiceDiscovery;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IdentityModel.Tokens.Jwt;
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
using System.Net.Http;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using IdentityServer4.AccessTokenValidation;
|
using IdentityServer4.AccessTokenValidation;
|
||||||
@ -46,19 +45,16 @@ using Ocelot.Configuration.Builder;
|
|||||||
using FileConfigurationProvider = Ocelot.Configuration.Provider.FileConfigurationProvider;
|
using FileConfigurationProvider = Ocelot.Configuration.Provider.FileConfigurationProvider;
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Ocelot.Raft;
|
using System.Net.Http;
|
||||||
using Rafty.Concensus;
|
using Butterfly.Client.AspNetCore;
|
||||||
using Rafty.FiniteStateMachine;
|
|
||||||
using Rafty.Infrastructure;
|
|
||||||
using Rafty.Log;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace Ocelot.DependencyInjection
|
namespace Ocelot.DependencyInjection
|
||||||
{
|
{
|
||||||
public class OcelotBuilder : IOcelotBuilder
|
public class OcelotBuilder : IOcelotBuilder
|
||||||
{
|
{
|
||||||
private IServiceCollection _services;
|
private readonly IServiceCollection _services;
|
||||||
private IConfiguration _configurationRoot;
|
private readonly IConfiguration _configurationRoot;
|
||||||
|
private IDelegatingHandlerHandlerProvider _provider;
|
||||||
|
|
||||||
public OcelotBuilder(IServiceCollection services, IConfiguration configurationRoot)
|
public OcelotBuilder(IServiceCollection services, IConfiguration configurationRoot)
|
||||||
{
|
{
|
||||||
@ -123,6 +119,9 @@ 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<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
|
||||||
_services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
_services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||||
@ -143,6 +142,11 @@ namespace Ocelot.DependencyInjection
|
|||||||
_services.AddMiddlewareAnalysis();
|
_services.AddMiddlewareAnalysis();
|
||||||
_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.AddTransient<ITracingHandler, NoTracingHandler>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IOcelotAdministrationBuilder AddAdministration(string path, string secret)
|
public IOcelotAdministrationBuilder AddAdministration(string path, string secret)
|
||||||
@ -162,6 +166,19 @@ namespace Ocelot.DependencyInjection
|
|||||||
return new OcelotAdministrationBuilder(_services, _configurationRoot);
|
return new OcelotAdministrationBuilder(_services, _configurationRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IOcelotBuilder AddDelegatingHandler(Func<DelegatingHandler> delegatingHandler)
|
||||||
|
{
|
||||||
|
_provider.Add(delegatingHandler);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IOcelotBuilder AddOpenTracing(Action<ButterflyOptions> settings)
|
||||||
|
{
|
||||||
|
_services.AddTransient<ITracingHandler, OcelotHttpTracingHandler>();
|
||||||
|
_services.AddButterfly(settings);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public IOcelotBuilder AddStoreOcelotConfigurationInConsul()
|
public IOcelotBuilder AddStoreOcelotConfigurationInConsul()
|
||||||
{
|
{
|
||||||
var serviceDiscoveryPort = _configurationRoot.GetValue("GlobalConfiguration:ServiceDiscoveryProvider:Port", 0);
|
var serviceDiscoveryPort = _configurationRoot.GetValue("GlobalConfiguration:ServiceDiscoveryProvider:Port", 0);
|
||||||
@ -275,33 +292,4 @@ namespace Ocelot.DependencyInjection
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IOcelotAdministrationBuilder
|
|
||||||
{
|
|
||||||
IOcelotAdministrationBuilder AddRafty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class OcelotAdministrationBuilder : IOcelotAdministrationBuilder
|
|
||||||
{
|
|
||||||
private IServiceCollection _services;
|
|
||||||
private IConfiguration _configurationRoot;
|
|
||||||
|
|
||||||
public OcelotAdministrationBuilder(IServiceCollection services, IConfiguration configurationRoot)
|
|
||||||
{
|
|
||||||
_configurationRoot = configurationRoot;
|
|
||||||
_services = services;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IOcelotAdministrationBuilder AddRafty()
|
|
||||||
{
|
|
||||||
var settings = new InMemorySettings(4000, 5000, 100, 5000);
|
|
||||||
_services.AddSingleton<ILog, SqlLiteLog>();
|
|
||||||
_services.AddSingleton<IFiniteStateMachine, OcelotFiniteStateMachine>();
|
|
||||||
_services.AddSingleton<ISettings>(settings);
|
|
||||||
_services.AddSingleton<IPeersProvider, FilePeersProvider>();
|
|
||||||
_services.AddSingleton<INode, Node>();
|
|
||||||
_services.Configure<FilePeers>(_configurationRoot);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
using Ocelot.Configuration.Provider;
|
|
||||||
using Ocelot.DownstreamRouteFinder.UrlMatcher;
|
using Ocelot.DownstreamRouteFinder.UrlMatcher;
|
||||||
using Ocelot.Errors;
|
using Ocelot.Errors;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
|
@ -62,7 +62,7 @@ namespace Ocelot.Errors.Middleware
|
|||||||
private async Task TrySetGlobalRequestId(HttpContext context)
|
private async Task TrySetGlobalRequestId(HttpContext context)
|
||||||
{
|
{
|
||||||
//try and get the global request id and set it for logs...
|
//try and get the global request id and set it for logs...
|
||||||
//shoudl this basically be immutable per request...i guess it should!
|
//should this basically be immutable per request...i guess it should!
|
||||||
//first thing is get config
|
//first thing is get config
|
||||||
var configuration = await _configProvider.Get();
|
var configuration = await _configProvider.Get();
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
UnmappableRequestError,
|
UnmappableRequestError,
|
||||||
RateLimitOptionsError,
|
RateLimitOptionsError,
|
||||||
PathTemplateDoesntStartWithForwardSlash,
|
PathTemplateDoesntStartWithForwardSlash,
|
||||||
FileValidationFailedError
|
FileValidationFailedError,
|
||||||
|
UnableToFindDelegatingHandlerProviderError
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Ocelot.Configuration.Provider;
|
|
||||||
using Ocelot.Infrastructure.RequestData;
|
using Ocelot.Infrastructure.RequestData;
|
||||||
using Ocelot.LoadBalancer.LoadBalancers;
|
using Ocelot.LoadBalancer.LoadBalancers;
|
||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
@ -46,11 +45,14 @@ namespace Ocelot.LoadBalancer.Middleware
|
|||||||
}
|
}
|
||||||
|
|
||||||
var uriBuilder = new UriBuilder(DownstreamRequest.RequestUri);
|
var uriBuilder = new UriBuilder(DownstreamRequest.RequestUri);
|
||||||
|
|
||||||
uriBuilder.Host = hostAndPort.Data.DownstreamHost;
|
uriBuilder.Host = hostAndPort.Data.DownstreamHost;
|
||||||
|
|
||||||
if (hostAndPort.Data.DownstreamPort > 0)
|
if (hostAndPort.Data.DownstreamPort > 0)
|
||||||
{
|
{
|
||||||
uriBuilder.Port = hostAndPort.Data.DownstreamPort;
|
uriBuilder.Port = hostAndPort.Data.DownstreamPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
DownstreamRequest.RequestUri = uriBuilder.Uri;
|
DownstreamRequest.RequestUri = uriBuilder.Uri;
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.Extensions.DiagnosticAdapter;
|
using Microsoft.Extensions.DiagnosticAdapter;
|
||||||
|
using Butterfly.Client.AspNetCore;
|
||||||
|
using Butterfly.OpenTracing;
|
||||||
|
|
||||||
namespace Ocelot.Logging
|
namespace Ocelot.Logging
|
||||||
{
|
{
|
||||||
@ -17,6 +19,7 @@ namespace Ocelot.Logging
|
|||||||
public virtual void OnMiddlewareStarting(HttpContext httpContext, string name)
|
public virtual void OnMiddlewareStarting(HttpContext httpContext, string name)
|
||||||
{
|
{
|
||||||
_logger.LogTrace($"MiddlewareStarting: {name}; {httpContext.Request.Path}");
|
_logger.LogTrace($"MiddlewareStarting: {name}; {httpContext.Request.Path}");
|
||||||
|
Event(httpContext, $"MiddlewareStarting: {name}; {httpContext.Request.Path}");
|
||||||
}
|
}
|
||||||
|
|
||||||
[DiagnosticName("Microsoft.AspNetCore.MiddlewareAnalysis.MiddlewareException")]
|
[DiagnosticName("Microsoft.AspNetCore.MiddlewareAnalysis.MiddlewareException")]
|
||||||
@ -29,6 +32,13 @@ namespace Ocelot.Logging
|
|||||||
public virtual void OnMiddlewareFinished(HttpContext httpContext, string name)
|
public virtual void OnMiddlewareFinished(HttpContext httpContext, string name)
|
||||||
{
|
{
|
||||||
_logger.LogTrace($"MiddlewareFinished: {name}; {httpContext.Response.StatusCode}");
|
_logger.LogTrace($"MiddlewareFinished: {name}; {httpContext.Response.StatusCode}");
|
||||||
|
Event(httpContext, $"MiddlewareFinished: {name}; {httpContext.Response.StatusCode}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Event(HttpContext httpContext, string @event)
|
||||||
|
{
|
||||||
|
var span = httpContext.GetSpan();
|
||||||
|
span?.Log(LogField.CreateNew().Event(@event));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,24 +23,25 @@
|
|||||||
<DebugSymbols>True</DebugSymbols>
|
<DebugSymbols>True</DebugSymbols>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FluentValidation" Version="7.2.1"/>
|
<PackageReference Include="Butterfly.Client.AspNetCore" Version="0.0.5" />
|
||||||
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="2.1.0"/>
|
<PackageReference Include="FluentValidation" Version="7.2.1" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0"/>
|
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="2.1.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.0"/>
|
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.0.0"/>
|
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0"/>
|
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DiagnosticAdapter" Version="2.0.0"/>
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0"/>
|
<PackageReference Include="Microsoft.Extensions.DiagnosticAdapter" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.0.0"/>
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.0"/>
|
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.0.0"/>
|
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.0" />
|
||||||
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.0"/>
|
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.0.0" />
|
||||||
<PackageReference Include="CacheManager.Core" Version="1.1.1"/>
|
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.0" />
|
||||||
<PackageReference Include="CacheManager.Microsoft.Extensions.Configuration" Version="1.1.1"/>
|
<PackageReference Include="CacheManager.Core" Version="1.1.1" />
|
||||||
<PackageReference Include="CacheManager.Microsoft.Extensions.Logging" Version="1.1.1"/>
|
<PackageReference Include="CacheManager.Microsoft.Extensions.Configuration" Version="1.1.1" />
|
||||||
<PackageReference Include="Consul" Version="0.7.2.3"/>
|
<PackageReference Include="CacheManager.Microsoft.Extensions.Logging" Version="1.1.1" />
|
||||||
<PackageReference Include="Polly" Version="5.3.1"/>
|
<PackageReference Include="Consul" Version="0.7.2.3" />
|
||||||
<PackageReference Include="IdentityServer4" Version="2.0.2"/>
|
<PackageReference Include="Polly" Version="5.3.1" />
|
||||||
<PackageReference Include="Rafty" Version="0.4.2"/>
|
<PackageReference Include="IdentityServer4" Version="2.0.2" />
|
||||||
|
<PackageReference Include="Rafty" Version="0.4.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -12,9 +12,11 @@ namespace Ocelot.Request.Builder
|
|||||||
bool isQos,
|
bool isQos,
|
||||||
IQoSProvider qosProvider,
|
IQoSProvider qosProvider,
|
||||||
bool useCookieContainer,
|
bool useCookieContainer,
|
||||||
bool allowAutoRedirect)
|
bool allowAutoRedirect,
|
||||||
|
string reRouteKey,
|
||||||
|
bool isTracing)
|
||||||
{
|
{
|
||||||
return new OkResponse<Request>(new Request(httpRequestMessage, isQos, qosProvider, allowAutoRedirect, useCookieContainer));
|
return new OkResponse<Request>(new Request(httpRequestMessage, isQos, qosProvider, allowAutoRedirect, useCookieContainer, reRouteKey, isTracing));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -13,6 +13,8 @@
|
|||||||
bool isQos,
|
bool isQos,
|
||||||
IQoSProvider qosProvider,
|
IQoSProvider qosProvider,
|
||||||
bool useCookieContainer,
|
bool useCookieContainer,
|
||||||
bool allowAutoRedirect);
|
bool allowAutoRedirect,
|
||||||
|
string reRouteKe,
|
||||||
|
bool isTracing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,16 +46,17 @@ namespace Ocelot.Request.Middleware
|
|||||||
DownstreamRoute.ReRoute.IsQos,
|
DownstreamRoute.ReRoute.IsQos,
|
||||||
qosProvider.Data,
|
qosProvider.Data,
|
||||||
DownstreamRoute.ReRoute.HttpHandlerOptions.UseCookieContainer,
|
DownstreamRoute.ReRoute.HttpHandlerOptions.UseCookieContainer,
|
||||||
DownstreamRoute.ReRoute.HttpHandlerOptions.AllowAutoRedirect);
|
DownstreamRoute.ReRoute.HttpHandlerOptions.AllowAutoRedirect,
|
||||||
|
DownstreamRoute.ReRoute.ReRouteKey,
|
||||||
|
DownstreamRoute.ReRoute.HttpHandlerOptions.UseTracing);
|
||||||
|
|
||||||
if (buildResult.IsError)
|
if (buildResult.IsError)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("IRequestCreator returned an error, setting pipeline error");
|
_logger.LogDebug("IRequestCreator returned an error, setting pipeline error");
|
||||||
|
|
||||||
SetPipelineError(buildResult.Errors);
|
SetPipelineError(buildResult.Errors);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogDebug("setting upstream request");
|
_logger.LogDebug("setting upstream request");
|
||||||
|
|
||||||
SetUpstreamRequestForThisRequest(buildResult.Data);
|
SetUpstreamRequestForThisRequest(buildResult.Data);
|
||||||
|
@ -10,19 +10,26 @@ namespace Ocelot.Request
|
|||||||
bool isQos,
|
bool isQos,
|
||||||
IQoSProvider qosProvider,
|
IQoSProvider qosProvider,
|
||||||
bool allowAutoRedirect,
|
bool allowAutoRedirect,
|
||||||
bool useCookieContainer)
|
bool useCookieContainer,
|
||||||
|
string reRouteKey,
|
||||||
|
bool isTracing
|
||||||
|
)
|
||||||
{
|
{
|
||||||
HttpRequestMessage = httpRequestMessage;
|
HttpRequestMessage = httpRequestMessage;
|
||||||
IsQos = isQos;
|
IsQos = isQos;
|
||||||
QosProvider = qosProvider;
|
QosProvider = qosProvider;
|
||||||
AllowAutoRedirect = allowAutoRedirect;
|
AllowAutoRedirect = allowAutoRedirect;
|
||||||
UseCookieContainer = useCookieContainer;
|
UseCookieContainer = useCookieContainer;
|
||||||
|
ReRouteKey = reRouteKey;
|
||||||
|
IsTracing = isTracing;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpRequestMessage HttpRequestMessage { get; private set; }
|
public HttpRequestMessage HttpRequestMessage { get; private set; }
|
||||||
public bool IsQos { get; private set; }
|
public bool IsQos { get; private set; }
|
||||||
|
public bool IsTracing { get; private set; }
|
||||||
public IQoSProvider QosProvider { get; private set; }
|
public IQoSProvider QosProvider { get; private set; }
|
||||||
public bool AllowAutoRedirect { get; private set; }
|
public bool AllowAutoRedirect { get; private set; }
|
||||||
public bool UseCookieContainer { get; private set; }
|
public bool UseCookieContainer { get; private set; }
|
||||||
|
public string ReRouteKey { get; private set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
49
src/Ocelot/Requester/DelegatingHandlerHandlerHouse.cs
Normal file
49
src/Ocelot/Requester/DelegatingHandlerHandlerHouse.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
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(Request.Request 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
provider = _factory.Get(request);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
src/Ocelot/Requester/DelegatingHandlerHandlerProvider.cs
Normal file
28
src/Ocelot/Requester/DelegatingHandlerHandlerProvider.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
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>>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
using System.Net.Http;
|
||||||
|
using Ocelot.Logging;
|
||||||
|
|
||||||
|
namespace Ocelot.Requester
|
||||||
|
{
|
||||||
|
public class DelegatingHandlerHandlerProviderFactory : IDelegatingHandlerHandlerProviderFactory
|
||||||
|
{
|
||||||
|
private readonly ITracingHandler _tracingHandler;
|
||||||
|
private readonly IOcelotLoggerFactory _loggerFactory;
|
||||||
|
private readonly IDelegatingHandlerHandlerProvider _allRoutesProvider;
|
||||||
|
|
||||||
|
public DelegatingHandlerHandlerProviderFactory(IOcelotLoggerFactory loggerFactory, IDelegatingHandlerHandlerProvider allRoutesProvider, ITracingHandler tracingHandler)
|
||||||
|
{
|
||||||
|
_tracingHandler = tracingHandler;
|
||||||
|
_loggerFactory = loggerFactory;
|
||||||
|
_allRoutesProvider = allRoutesProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IDelegatingHandlerHandlerProvider Get(Request.Request request)
|
||||||
|
{
|
||||||
|
var handlersAppliedToAll = _allRoutesProvider.Get();
|
||||||
|
|
||||||
|
var provider = new DelegatingHandlerHandlerProvider();
|
||||||
|
|
||||||
|
foreach (var handler in handlersAppliedToAll)
|
||||||
|
{
|
||||||
|
provider.Add(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.IsTracing)
|
||||||
|
{
|
||||||
|
provider.Add(() => (DelegatingHandler)_tracingHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.IsQos)
|
||||||
|
{
|
||||||
|
provider.Add(() => new PollyCircuitBreakingDelegatingHandler(request.QosProvider, _loggerFactory));
|
||||||
|
}
|
||||||
|
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,39 +1,33 @@
|
|||||||
using System;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Ocelot.Logging;
|
|
||||||
using Ocelot.Requester.QoS;
|
|
||||||
|
|
||||||
namespace Ocelot.Requester
|
namespace Ocelot.Requester
|
||||||
{
|
{
|
||||||
internal class HttpClientBuilder : IHttpClientBuilder
|
public class HttpClientBuilder : IHttpClientBuilder
|
||||||
{
|
{
|
||||||
private readonly Dictionary<int, Func<DelegatingHandler>> _handlers = new Dictionary<int, Func<DelegatingHandler>>();
|
private readonly IDelegatingHandlerHandlerHouse _house;
|
||||||
|
|
||||||
public IHttpClientBuilder WithQos(IQoSProvider qosProvider, IOcelotLogger logger)
|
public HttpClientBuilder(IDelegatingHandlerHandlerHouse house)
|
||||||
{
|
{
|
||||||
_handlers.Add(5000, () => new PollyCircuitBreakingDelegatingHandler(qosProvider, logger));
|
_house = house;
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IHttpClient Create(bool useCookies, bool allowAutoRedirect)
|
public IHttpClient Create(Request.Request request)
|
||||||
{
|
{
|
||||||
var httpclientHandler = new HttpClientHandler { AllowAutoRedirect = allowAutoRedirect, UseCookies = useCookies};
|
var httpclientHandler = new HttpClientHandler { AllowAutoRedirect = request.AllowAutoRedirect, UseCookies = request.UseCookieContainer};
|
||||||
|
|
||||||
var client = new HttpClient(CreateHttpMessageHandler(httpclientHandler));
|
var client = new HttpClient(CreateHttpMessageHandler(httpclientHandler, request));
|
||||||
|
|
||||||
return new HttpClientWrapper(client);
|
return new HttpClientWrapper(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
private HttpMessageHandler CreateHttpMessageHandler(HttpMessageHandler httpMessageHandler)
|
private HttpMessageHandler CreateHttpMessageHandler(HttpMessageHandler httpMessageHandler, Request.Request request)
|
||||||
{
|
{
|
||||||
_handlers
|
var provider = _house.Get(request);
|
||||||
.OrderByDescending(handler => handler.Key)
|
|
||||||
.Select(handler => handler.Value)
|
//todo handle error
|
||||||
|
provider.Data.Get()
|
||||||
|
.Select(handler => handler)
|
||||||
.Reverse()
|
.Reverse()
|
||||||
.ToList()
|
.ToList()
|
||||||
.ForEach(handler =>
|
.ForEach(handler =>
|
||||||
@ -45,22 +39,4 @@ namespace Ocelot.Requester
|
|||||||
return httpMessageHandler;
|
return httpMessageHandler;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This class was made to make unit testing easier when HttpClient is used.
|
|
||||||
/// </summary>
|
|
||||||
internal class HttpClientWrapper : IHttpClient
|
|
||||||
{
|
|
||||||
public HttpClient Client { get; }
|
|
||||||
|
|
||||||
public HttpClientWrapper(HttpClient client)
|
|
||||||
{
|
|
||||||
Client = client;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)
|
|
||||||
{
|
|
||||||
return Client.SendAsync(request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,8 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Ocelot.Configuration;
|
|
||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
using Polly.CircuitBreaker;
|
using Polly.CircuitBreaker;
|
||||||
@ -14,21 +12,24 @@ namespace Ocelot.Requester
|
|||||||
{
|
{
|
||||||
private readonly IHttpClientCache _cacheHandlers;
|
private readonly IHttpClientCache _cacheHandlers;
|
||||||
private readonly IOcelotLogger _logger;
|
private readonly IOcelotLogger _logger;
|
||||||
|
private readonly IDelegatingHandlerHandlerHouse _house;
|
||||||
|
|
||||||
public HttpClientHttpRequester(IOcelotLoggerFactory loggerFactory,
|
public HttpClientHttpRequester(IOcelotLoggerFactory loggerFactory,
|
||||||
IHttpClientCache cacheHandlers)
|
IHttpClientCache cacheHandlers,
|
||||||
|
IDelegatingHandlerHandlerHouse house)
|
||||||
{
|
{
|
||||||
_logger = loggerFactory.CreateLogger<HttpClientHttpRequester>();
|
_logger = loggerFactory.CreateLogger<HttpClientHttpRequester>();
|
||||||
_cacheHandlers = cacheHandlers;
|
_cacheHandlers = cacheHandlers;
|
||||||
|
_house = house;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Response<HttpResponseMessage>> GetResponse(Request.Request request)
|
public async Task<Response<HttpResponseMessage>> GetResponse(Request.Request request)
|
||||||
{
|
{
|
||||||
var builder = new HttpClientBuilder();
|
var builder = new HttpClientBuilder(_house);
|
||||||
|
|
||||||
var cacheKey = GetCacheKey(request, builder);
|
var cacheKey = GetCacheKey(request);
|
||||||
|
|
||||||
var httpClient = GetHttpClient(cacheKey, builder, request.UseCookieContainer, request.AllowAutoRedirect);
|
var httpClient = GetHttpClient(cacheKey, builder, request);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -56,24 +57,24 @@ namespace Ocelot.Requester
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IHttpClient GetHttpClient(string cacheKey, IHttpClientBuilder builder, bool useCookieContainer, bool allowAutoRedirect)
|
private IHttpClient GetHttpClient(string cacheKey, IHttpClientBuilder builder, Request.Request request)
|
||||||
{
|
{
|
||||||
var httpClient = _cacheHandlers.Get(cacheKey);
|
var httpClient = _cacheHandlers.Get(cacheKey);
|
||||||
|
|
||||||
if (httpClient == null)
|
if (httpClient == null)
|
||||||
{
|
{
|
||||||
httpClient = builder.Create(useCookieContainer, allowAutoRedirect);
|
httpClient = builder.Create(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
return httpClient;
|
return httpClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetCacheKey(Request.Request request, IHttpClientBuilder builder)
|
private string GetCacheKey(Request.Request request)
|
||||||
{
|
{
|
||||||
string baseUrl = $"{request.HttpRequestMessage.RequestUri.Scheme}://{request.HttpRequestMessage.RequestUri.Authority}";
|
var baseUrl = $"{request.HttpRequestMessage.RequestUri.Scheme}://{request.HttpRequestMessage.RequestUri.Authority}";
|
||||||
|
|
||||||
if (request.IsQos)
|
if (request.IsQos)
|
||||||
{
|
{
|
||||||
builder.WithQos(request.QosProvider, _logger);
|
|
||||||
baseUrl = $"{baseUrl}{request.QosProvider.CircuitBreaker.CircuitBreakerPolicy.PolicyKey}";
|
baseUrl = $"{baseUrl}{request.QosProvider.CircuitBreaker.CircuitBreakerPolicy.PolicyKey}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
23
src/Ocelot/Requester/HttpClientWrapper.cs
Normal file
23
src/Ocelot/Requester/HttpClientWrapper.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ocelot.Requester
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This class was made to make unit testing easier when HttpClient is used.
|
||||||
|
/// </summary>
|
||||||
|
internal class HttpClientWrapper : IHttpClient
|
||||||
|
{
|
||||||
|
public HttpClient Client { get; }
|
||||||
|
|
||||||
|
public HttpClientWrapper(HttpClient client)
|
||||||
|
{
|
||||||
|
Client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)
|
||||||
|
{
|
||||||
|
return Client.SendAsync(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
src/Ocelot/Requester/IDelegatingHandlerHandlerHouse.cs
Normal file
9
src/Ocelot/Requester/IDelegatingHandlerHandlerHouse.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using Ocelot.Responses;
|
||||||
|
|
||||||
|
namespace Ocelot.Requester
|
||||||
|
{
|
||||||
|
public interface IDelegatingHandlerHandlerHouse
|
||||||
|
{
|
||||||
|
Response<IDelegatingHandlerHandlerProvider> Get(Request.Request request);
|
||||||
|
}
|
||||||
|
}
|
12
src/Ocelot/Requester/IDelegatingHandlerHandlerProvider.cs
Normal file
12
src/Ocelot/Requester/IDelegatingHandlerHandlerProvider.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
namespace Ocelot.Requester
|
||||||
|
{
|
||||||
|
public interface IDelegatingHandlerHandlerProviderFactory
|
||||||
|
{
|
||||||
|
IDelegatingHandlerHandlerProvider Get(Request.Request request);
|
||||||
|
}
|
||||||
|
}
|
@ -1,27 +1,14 @@
|
|||||||
using System;
|
using System.Net.Http;
|
||||||
using System.Collections.Generic;
|
using Ocelot.Configuration;
|
||||||
using System.Linq;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Ocelot.Logging;
|
|
||||||
using Ocelot.Requester.QoS;
|
|
||||||
using System.Net;
|
|
||||||
|
|
||||||
namespace Ocelot.Requester
|
namespace Ocelot.Requester
|
||||||
{
|
{
|
||||||
public interface IHttpClientBuilder
|
public interface IHttpClientBuilder
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets a PollyCircuitBreakingDelegatingHandler .
|
|
||||||
/// </summary>
|
|
||||||
IHttpClientBuilder WithQos(IQoSProvider qosProvider, IOcelotLogger logger);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates the <see cref="HttpClient"/>
|
/// Creates the <see cref="HttpClient"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="useCookies">Defines if http client should use cookie container</param>
|
/// <param name="request"></param>
|
||||||
/// <param name="allowAutoRedirect">Defines if http client should allow auto redirect</param>
|
IHttpClient Create(Request.Request request);
|
||||||
IHttpClient Create(bool useCookies, bool allowAutoRedirect);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,5 @@ namespace Ocelot.Requester
|
|||||||
public interface IHttpRequester
|
public interface IHttpRequester
|
||||||
{
|
{
|
||||||
Task<Response<HttpResponseMessage>> GetResponse(Request.Request request);
|
Task<Response<HttpResponseMessage>> GetResponse(Request.Request request);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Ocelot.Infrastructure.RequestData;
|
using Ocelot.Infrastructure.RequestData;
|
||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
using Ocelot.Middleware;
|
using Ocelot.Middleware;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Ocelot.Requester.Middleware
|
namespace Ocelot.Requester.Middleware
|
||||||
{
|
{
|
||||||
@ -16,7 +15,8 @@ namespace Ocelot.Requester.Middleware
|
|||||||
public HttpRequesterMiddleware(RequestDelegate next,
|
public HttpRequesterMiddleware(RequestDelegate next,
|
||||||
IOcelotLoggerFactory loggerFactory,
|
IOcelotLoggerFactory loggerFactory,
|
||||||
IHttpRequester requester,
|
IHttpRequester requester,
|
||||||
IRequestScopedDataRepository requestScopedDataRepository)
|
IRequestScopedDataRepository requestScopedDataRepository
|
||||||
|
)
|
||||||
:base(requestScopedDataRepository)
|
:base(requestScopedDataRepository)
|
||||||
{
|
{
|
||||||
_next = next;
|
_next = next;
|
||||||
|
71
src/Ocelot/Requester/OcelotHttpTracingHandler.cs
Normal file
71
src/Ocelot/Requester/OcelotHttpTracingHandler.cs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Butterfly.Client.Tracing;
|
||||||
|
using Butterfly.OpenTracing;
|
||||||
|
|
||||||
|
namespace Ocelot.Requester
|
||||||
|
{
|
||||||
|
public interface ITracingHandler
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NoTracingHandler : DelegatingHandler, ITracingHandler
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class OcelotHttpTracingHandler : DelegatingHandler, ITracingHandler
|
||||||
|
{
|
||||||
|
private readonly IServiceTracer _tracer;
|
||||||
|
private const string prefix_spanId = "ot-spanId";
|
||||||
|
|
||||||
|
public OcelotHttpTracingHandler(IServiceTracer tracer, HttpMessageHandler httpMessageHandler = null)
|
||||||
|
{
|
||||||
|
_tracer = tracer ?? throw new ArgumentNullException(nameof(tracer));
|
||||||
|
InnerHandler = httpMessageHandler ?? new HttpClientHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return _tracer.ChildTraceAsync($"httpclient {request.Method}", DateTimeOffset.UtcNow, span => TracingSendAsync(span, request, cancellationToken));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual async Task<HttpResponseMessage> TracingSendAsync(ISpan span, HttpRequestMessage request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
IEnumerable<string> traceIdVals = null;
|
||||||
|
if (request.Headers.TryGetValues(prefix_spanId, out traceIdVals))
|
||||||
|
{
|
||||||
|
request.Headers.Remove(prefix_spanId);
|
||||||
|
request.Headers.TryAddWithoutValidation(prefix_spanId, span.SpanContext.SpanId);
|
||||||
|
};
|
||||||
|
|
||||||
|
span.Tags.Client().Component("HttpClient")
|
||||||
|
.HttpMethod(request.Method.Method)
|
||||||
|
.HttpUrl(request.RequestUri.OriginalString)
|
||||||
|
.HttpHost(request.RequestUri.Host)
|
||||||
|
.HttpPath(request.RequestUri.PathAndQuery)
|
||||||
|
.PeerAddress(request.RequestUri.OriginalString)
|
||||||
|
.PeerHostName(request.RequestUri.Host)
|
||||||
|
.PeerPort(request.RequestUri.Port);
|
||||||
|
|
||||||
|
_tracer.Tracer.Inject(span.SpanContext, request.Headers, (c, k, v) =>
|
||||||
|
{
|
||||||
|
if (!c.Contains(k))
|
||||||
|
{
|
||||||
|
c.Add(k, v);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
span.Log(LogField.CreateNew().ClientSend());
|
||||||
|
|
||||||
|
var responseMessage = await base.SendAsync(request, cancellationToken);
|
||||||
|
|
||||||
|
span.Log(LogField.CreateNew().ClientReceive());
|
||||||
|
|
||||||
|
return responseMessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -16,10 +16,10 @@ namespace Ocelot.Requester
|
|||||||
|
|
||||||
public PollyCircuitBreakingDelegatingHandler(
|
public PollyCircuitBreakingDelegatingHandler(
|
||||||
IQoSProvider qoSProvider,
|
IQoSProvider qoSProvider,
|
||||||
IOcelotLogger logger)
|
IOcelotLoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
_qoSProvider = qoSProvider;
|
_qoSProvider = qoSProvider;
|
||||||
_logger = logger;
|
_logger = loggerFactory.CreateLogger<PollyCircuitBreakingDelegatingHandler>();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
using Ocelot.Errors;
|
||||||
|
|
||||||
|
namespace Ocelot.Requester
|
||||||
|
{
|
||||||
|
public class UnableToFindDelegatingHandlerProviderError : Error
|
||||||
|
{
|
||||||
|
public UnableToFindDelegatingHandlerProviderError(string message)
|
||||||
|
: base(message, OcelotErrorCode.UnableToFindDelegatingHandlerProviderError)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,10 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Ocelot.Errors;
|
using Ocelot.Errors;
|
||||||
using Ocelot.Infrastructure.RequestData;
|
using Ocelot.Infrastructure.RequestData;
|
||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
using Ocelot.Middleware;
|
using Ocelot.Middleware;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Ocelot.Responder.Middleware
|
namespace Ocelot.Responder.Middleware
|
||||||
{
|
{
|
||||||
@ -22,7 +22,8 @@ namespace Ocelot.Responder.Middleware
|
|||||||
IHttpResponder responder,
|
IHttpResponder responder,
|
||||||
IOcelotLoggerFactory loggerFactory,
|
IOcelotLoggerFactory loggerFactory,
|
||||||
IRequestScopedDataRepository requestScopedDataRepository,
|
IRequestScopedDataRepository requestScopedDataRepository,
|
||||||
IErrorsToHttpStatusCodeMapper codeMapper)
|
IErrorsToHttpStatusCodeMapper codeMapper
|
||||||
|
)
|
||||||
:base(requestScopedDataRepository)
|
:base(requestScopedDataRepository)
|
||||||
{
|
{
|
||||||
_next = next;
|
_next = next;
|
||||||
@ -40,7 +41,6 @@ namespace Ocelot.Responder.Middleware
|
|||||||
{
|
{
|
||||||
var errors = PipelineErrors;
|
var errors = PipelineErrors;
|
||||||
_logger.LogError($"{PipelineErrors.Count} pipeline errors found in {MiddlewareName}. Setting error response status code");
|
_logger.LogError($"{PipelineErrors.Count} pipeline errors found in {MiddlewareName}. Setting error response status code");
|
||||||
|
|
||||||
SetErrorResponse(context, errors);
|
SetErrorResponse(context, errors);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -4,6 +4,7 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Consul;
|
using Consul;
|
||||||
using Ocelot.Infrastructure.Extensions;
|
using Ocelot.Infrastructure.Extensions;
|
||||||
|
using Ocelot.Logging;
|
||||||
using Ocelot.Values;
|
using Ocelot.Values;
|
||||||
|
|
||||||
namespace Ocelot.ServiceDiscovery
|
namespace Ocelot.ServiceDiscovery
|
||||||
@ -11,13 +12,18 @@ namespace Ocelot.ServiceDiscovery
|
|||||||
public class ConsulServiceDiscoveryProvider : IServiceDiscoveryProvider
|
public class ConsulServiceDiscoveryProvider : IServiceDiscoveryProvider
|
||||||
{
|
{
|
||||||
private readonly ConsulRegistryConfiguration _consulConfig;
|
private readonly ConsulRegistryConfiguration _consulConfig;
|
||||||
|
private readonly IOcelotLogger _logger;
|
||||||
private readonly ConsulClient _consul;
|
private readonly ConsulClient _consul;
|
||||||
private const string VersionPrefix = "version-";
|
private const string VersionPrefix = "version-";
|
||||||
|
|
||||||
public ConsulServiceDiscoveryProvider(ConsulRegistryConfiguration consulRegistryConfiguration)
|
public ConsulServiceDiscoveryProvider(ConsulRegistryConfiguration consulRegistryConfiguration, IOcelotLoggerFactory factory)
|
||||||
{
|
{;
|
||||||
|
_logger = factory.CreateLogger<ConsulServiceDiscoveryProvider>();
|
||||||
|
|
||||||
var consulHost = string.IsNullOrEmpty(consulRegistryConfiguration?.HostName) ? "localhost" : consulRegistryConfiguration.HostName;
|
var consulHost = string.IsNullOrEmpty(consulRegistryConfiguration?.HostName) ? "localhost" : consulRegistryConfiguration.HostName;
|
||||||
|
|
||||||
var consulPort = consulRegistryConfiguration?.Port ?? 8500;
|
var consulPort = consulRegistryConfiguration?.Port ?? 8500;
|
||||||
|
|
||||||
_consulConfig = new ConsulRegistryConfiguration(consulHost, consulPort, consulRegistryConfiguration?.KeyOfServiceInConsul);
|
_consulConfig = new ConsulRegistryConfiguration(consulHost, consulPort, consulRegistryConfiguration?.KeyOfServiceInConsul);
|
||||||
|
|
||||||
_consul = new ConsulClient(config =>
|
_consul = new ConsulClient(config =>
|
||||||
@ -30,7 +36,19 @@ namespace Ocelot.ServiceDiscovery
|
|||||||
{
|
{
|
||||||
var queryResult = await _consul.Health.Service(_consulConfig.KeyOfServiceInConsul, string.Empty, true);
|
var queryResult = await _consul.Health.Service(_consulConfig.KeyOfServiceInConsul, string.Empty, true);
|
||||||
|
|
||||||
var services = queryResult.Response.Select(BuildService);
|
var services = new List<Service>();
|
||||||
|
|
||||||
|
foreach (var serviceEntry in queryResult.Response)
|
||||||
|
{
|
||||||
|
if (IsValid(serviceEntry))
|
||||||
|
{
|
||||||
|
services.Add(BuildService(serviceEntry));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogError($"Unable to use service Address: {serviceEntry.Service.Address} and Port: {serviceEntry.Service.Port} as it is invalid. Address must contain host only e.g. localhost and port must be greater than 0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return services.ToList();
|
return services.ToList();
|
||||||
}
|
}
|
||||||
@ -45,6 +63,16 @@ namespace Ocelot.ServiceDiscovery
|
|||||||
serviceEntry.Service.Tags ?? Enumerable.Empty<string>());
|
serviceEntry.Service.Tags ?? Enumerable.Empty<string>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsValid(ServiceEntry serviceEntry)
|
||||||
|
{
|
||||||
|
if (serviceEntry.Service.Address.Contains("http://") || serviceEntry.Service.Address.Contains("https://") || serviceEntry.Service.Port <= 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private string GetVersionFromStrings(IEnumerable<string> strings)
|
private string GetVersionFromStrings(IEnumerable<string> strings)
|
||||||
{
|
{
|
||||||
return strings
|
return strings
|
||||||
|
@ -1,11 +1,19 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
|
using Ocelot.Logging;
|
||||||
using Ocelot.Values;
|
using Ocelot.Values;
|
||||||
|
|
||||||
namespace Ocelot.ServiceDiscovery
|
namespace Ocelot.ServiceDiscovery
|
||||||
{
|
{
|
||||||
public class ServiceDiscoveryProviderFactory : IServiceDiscoveryProviderFactory
|
public class ServiceDiscoveryProviderFactory : IServiceDiscoveryProviderFactory
|
||||||
{
|
{
|
||||||
|
private readonly IOcelotLoggerFactory _factory;
|
||||||
|
|
||||||
|
public ServiceDiscoveryProviderFactory(IOcelotLoggerFactory factory)
|
||||||
|
{
|
||||||
|
_factory = factory;
|
||||||
|
}
|
||||||
|
|
||||||
public IServiceDiscoveryProvider Get(ServiceProviderConfiguration serviceConfig, ReRoute reRoute)
|
public IServiceDiscoveryProvider Get(ServiceProviderConfiguration serviceConfig, ReRoute reRoute)
|
||||||
{
|
{
|
||||||
if (reRoute.UseServiceDiscovery)
|
if (reRoute.UseServiceDiscovery)
|
||||||
@ -28,7 +36,7 @@ namespace Ocelot.ServiceDiscovery
|
|||||||
private IServiceDiscoveryProvider GetServiceDiscoveryProvider(string keyOfServiceInConsul, string providerHostName, int providerPort)
|
private IServiceDiscoveryProvider GetServiceDiscoveryProvider(string keyOfServiceInConsul, string providerHostName, int providerPort)
|
||||||
{
|
{
|
||||||
var consulRegistryConfiguration = new ConsulRegistryConfiguration(providerHostName, providerPort, keyOfServiceInConsul);
|
var consulRegistryConfiguration = new ConsulRegistryConfiguration(providerHostName, providerPort, keyOfServiceInConsul);
|
||||||
return new ConsulServiceDiscoveryProvider(consulRegistryConfiguration);
|
return new ConsulServiceDiscoveryProvider(consulRegistryConfiguration, _factory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
116
test/Ocelot.AcceptanceTests/HttpDelegatingHandlersTests.cs
Normal file
116
test/Ocelot.AcceptanceTests/HttpDelegatingHandlersTests.cs
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
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 HttpDelegatingHandlersTests
|
||||||
|
{
|
||||||
|
private IWebHost _builder;
|
||||||
|
private readonly Steps _steps;
|
||||||
|
private string _downstreamPath;
|
||||||
|
|
||||||
|
public HttpDelegatingHandlersTests()
|
||||||
|
{
|
||||||
|
_steps = new Steps();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_call_handlers()
|
||||||
|
{
|
||||||
|
var configuration = new FileConfiguration
|
||||||
|
{
|
||||||
|
ReRoutes = new List<FileReRoute>
|
||||||
|
{
|
||||||
|
new FileReRoute
|
||||||
|
{
|
||||||
|
DownstreamPathTemplate = "/",
|
||||||
|
DownstreamScheme = "http",
|
||||||
|
DownstreamHostAndPorts = new List<FileHostAndPort>
|
||||||
|
{
|
||||||
|
new FileHostAndPort
|
||||||
|
{
|
||||||
|
Host = "localhost",
|
||||||
|
Port = 61879,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
UpstreamPathTemplate = "/",
|
||||||
|
UpstreamHttpMethod = new List<string> { "Get" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var handlerOne = new FakeHandler();
|
||||||
|
var handlerTwo = new FakeHandler();
|
||||||
|
|
||||||
|
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:61879", "/", 200, "Hello from Laura"))
|
||||||
|
.And(x => _steps.GivenThereIsAConfiguration(configuration))
|
||||||
|
.And(x => _steps.GivenOcelotIsRunningWithHandlers(handlerOne, handlerTwo))
|
||||||
|
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
|
||||||
|
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
||||||
|
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
|
||||||
|
.And(x => ThenTheHandlersAreCalledCorrectly(handlerOne, handlerTwo))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenTheHandlersAreCalledCorrectly(FakeHandler one, FakeHandler two)
|
||||||
|
{
|
||||||
|
one.TimeCalled.ShouldBeLessThan(two.TimeCalled);
|
||||||
|
}
|
||||||
|
|
||||||
|
class FakeHandler : DelegatingHandler
|
||||||
|
{
|
||||||
|
|
||||||
|
public DateTime TimeCalled { get; private set; }
|
||||||
|
|
||||||
|
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
TimeCalled = DateTime.Now;
|
||||||
|
return await base.SendAsync(request, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody)
|
||||||
|
{
|
||||||
|
_builder = new WebHostBuilder()
|
||||||
|
.UseUrls(baseUrl)
|
||||||
|
.UseKestrel()
|
||||||
|
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||||
|
.UseIISIntegration()
|
||||||
|
.Configure(app =>
|
||||||
|
{
|
||||||
|
app.UsePathBase(basePath);
|
||||||
|
app.Run(async context =>
|
||||||
|
{
|
||||||
|
_downstreamPath = !string.IsNullOrEmpty(context.Request.PathBase.Value) ? context.Request.PathBase.Value : context.Request.Path.Value;
|
||||||
|
|
||||||
|
if (_downstreamPath != basePath)
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = statusCode;
|
||||||
|
await context.Response.WriteAsync("downstream path didnt match base path");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = statusCode;
|
||||||
|
await context.Response.WriteAsync(responseBody);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
_builder.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -88,6 +88,38 @@ namespace Ocelot.AcceptanceTests
|
|||||||
_ocelotClient = _ocelotServer.CreateClient();
|
_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 GivenOcelotIsRunningWithHandlers(DelegatingHandler handlerOne, DelegatingHandler handlerTwo)
|
||||||
|
{
|
||||||
|
_webHostBuilder = new WebHostBuilder();
|
||||||
|
|
||||||
|
_webHostBuilder.ConfigureServices(s =>
|
||||||
|
{
|
||||||
|
s.AddSingleton(_webHostBuilder);
|
||||||
|
s.AddOcelot()
|
||||||
|
.AddDelegatingHandler(() => handlerOne)
|
||||||
|
.AddDelegatingHandler(() => handlerTwo);
|
||||||
|
});
|
||||||
|
_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();
|
||||||
|
}).Configure(a =>
|
||||||
|
{
|
||||||
|
a.UseOcelot().Wait();
|
||||||
|
});
|
||||||
|
|
||||||
|
_ocelotServer = new TestServer(_webHostBuilder);
|
||||||
|
|
||||||
|
_ocelotClient = _ocelotServer.CreateClient();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <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.
|
/// 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>
|
/// </summary>
|
||||||
|
@ -41,7 +41,8 @@ namespace Ocelot.IntegrationTests
|
|||||||
services
|
services
|
||||||
.AddOcelot(Configuration)
|
.AddOcelot(Configuration)
|
||||||
.AddAdministration("/administration", "secret")
|
.AddAdministration("/administration", "secret")
|
||||||
.AddRafty();
|
.AddRafty()
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
public virtual void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
||||||
|
@ -1,13 +1,7 @@
|
|||||||
using System;
|
|
||||||
using CacheManager.Core;
|
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Ocelot.DependencyInjection;
|
using Ocelot.DependencyInjection;
|
||||||
using Ocelot.Middleware;
|
using Ocelot.Middleware;
|
||||||
using ConfigurationBuilder = Microsoft.Extensions.Configuration.ConfigurationBuilder;
|
|
||||||
|
|
||||||
namespace Ocelot.ManualTest
|
namespace Ocelot.ManualTest
|
||||||
{
|
{
|
||||||
@ -15,11 +9,6 @@ namespace Ocelot.ManualTest
|
|||||||
{
|
{
|
||||||
public void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
Action<ConfigurationBuilderCachePart> settings = (x) =>
|
|
||||||
{
|
|
||||||
x.WithDictionaryHandle();
|
|
||||||
};
|
|
||||||
|
|
||||||
services.AddAuthentication()
|
services.AddAuthentication()
|
||||||
.AddJwtBearer("TestKey", x =>
|
.AddJwtBearer("TestKey", x =>
|
||||||
{
|
{
|
||||||
@ -28,7 +17,15 @@ namespace Ocelot.ManualTest
|
|||||||
});
|
});
|
||||||
|
|
||||||
services.AddOcelot()
|
services.AddOcelot()
|
||||||
.AddCacheManager(settings)
|
.AddCacheManager(x =>
|
||||||
|
{
|
||||||
|
x.WithDictionaryHandle();
|
||||||
|
})
|
||||||
|
.AddOpenTracing(option =>
|
||||||
|
{
|
||||||
|
option.CollectorUrl = "http://localhost:9618";
|
||||||
|
option.Service = "Ocelot.ManualTest";
|
||||||
|
})
|
||||||
.AddAdministration("/administration", "secret");
|
.AddAdministration("/administration", "secret");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,22 @@
|
|||||||
{
|
{
|
||||||
"ReRoutes": [
|
"ReRoutes": [
|
||||||
|
{
|
||||||
|
"DownstreamPathTemplate": "/api/values",
|
||||||
|
"DownstreamScheme": "http",
|
||||||
|
"UpstreamPathTemplate": "/api/values",
|
||||||
|
"UpstreamHttpMethod": [ "Get" ],
|
||||||
|
"DownstreamHostAndPorts": [
|
||||||
|
{
|
||||||
|
"Host": "localhost",
|
||||||
|
"Port": 5001
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"HttpHandlerOptions": {
|
||||||
|
"AllowAutoRedirect": true,
|
||||||
|
"UseCookieContainer": true,
|
||||||
|
"UseTracing": true
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"DownstreamPathTemplate": "/",
|
"DownstreamPathTemplate": "/",
|
||||||
"DownstreamScheme": "http",
|
"DownstreamScheme": "http",
|
||||||
@ -57,6 +74,11 @@
|
|||||||
],
|
],
|
||||||
"UpstreamPathTemplate": "/posts",
|
"UpstreamPathTemplate": "/posts",
|
||||||
"UpstreamHttpMethod": [ "Get" ],
|
"UpstreamHttpMethod": [ "Get" ],
|
||||||
|
"HttpHandlerOptions": {
|
||||||
|
"AllowAutoRedirect": true,
|
||||||
|
"UseCookieContainer": true,
|
||||||
|
"UseTracing": true
|
||||||
|
},
|
||||||
"QoSOptions": {
|
"QoSOptions": {
|
||||||
"ExceptionsAllowedBeforeBreaking": 3,
|
"ExceptionsAllowedBeforeBreaking": 3,
|
||||||
"DurationOfBreak": 10,
|
"DurationOfBreak": 10,
|
||||||
@ -75,6 +97,11 @@
|
|||||||
"UpstreamPathTemplate": "/posts/{postId}",
|
"UpstreamPathTemplate": "/posts/{postId}",
|
||||||
"UpstreamHttpMethod": [ "Get" ],
|
"UpstreamHttpMethod": [ "Get" ],
|
||||||
"RequestIdKey": "ReRouteRequestId",
|
"RequestIdKey": "ReRouteRequestId",
|
||||||
|
"HttpHandlerOptions": {
|
||||||
|
"AllowAutoRedirect": true,
|
||||||
|
"UseCookieContainer": true,
|
||||||
|
"UseTracing": true
|
||||||
|
},
|
||||||
"QoSOptions": {
|
"QoSOptions": {
|
||||||
"ExceptionsAllowedBeforeBreaking": 3,
|
"ExceptionsAllowedBeforeBreaking": 3,
|
||||||
"DurationOfBreak": 10,
|
"DurationOfBreak": 10,
|
||||||
@ -92,6 +119,11 @@
|
|||||||
],
|
],
|
||||||
"UpstreamPathTemplate": "/posts/{postId}/comments",
|
"UpstreamPathTemplate": "/posts/{postId}/comments",
|
||||||
"UpstreamHttpMethod": [ "Get" ],
|
"UpstreamHttpMethod": [ "Get" ],
|
||||||
|
"HttpHandlerOptions": {
|
||||||
|
"AllowAutoRedirect": true,
|
||||||
|
"UseCookieContainer": true,
|
||||||
|
"UseTracing": true
|
||||||
|
},
|
||||||
"QoSOptions": {
|
"QoSOptions": {
|
||||||
"ExceptionsAllowedBeforeBreaking": 3,
|
"ExceptionsAllowedBeforeBreaking": 3,
|
||||||
"DurationOfBreak": 10,
|
"DurationOfBreak": 10,
|
||||||
@ -282,6 +314,6 @@
|
|||||||
],
|
],
|
||||||
|
|
||||||
"GlobalConfiguration": {
|
"GlobalConfiguration": {
|
||||||
"RequestIdKey": "OcRequestId"
|
"RequestIdKey": "ot-traceid"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -471,7 +471,7 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
{
|
{
|
||||||
var reRouteOptions = new ReRouteOptionsBuilder()
|
var reRouteOptions = new ReRouteOptionsBuilder()
|
||||||
.Build();
|
.Build();
|
||||||
var httpHandlerOptions = new HttpHandlerOptions(true, true);
|
var httpHandlerOptions = new HttpHandlerOptions(true, true,false);
|
||||||
|
|
||||||
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
|
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
|
||||||
{
|
{
|
||||||
|
@ -23,7 +23,7 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
public void should_create_options_with_useCookie_and_allowAutoRedirect_true_as_default()
|
public void should_create_options_with_useCookie_and_allowAutoRedirect_true_as_default()
|
||||||
{
|
{
|
||||||
var fileReRoute = new FileReRoute();
|
var fileReRoute = new FileReRoute();
|
||||||
var expectedOptions = new HttpHandlerOptions(true, true);
|
var expectedOptions = new HttpHandlerOptions(true, true, false);
|
||||||
|
|
||||||
this.Given(x => GivenTheFollowing(fileReRoute))
|
this.Given(x => GivenTheFollowing(fileReRoute))
|
||||||
.When(x => WhenICreateHttpHandlerOptions())
|
.When(x => WhenICreateHttpHandlerOptions())
|
||||||
@ -39,11 +39,12 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
HttpHandlerOptions = new FileHttpHandlerOptions
|
HttpHandlerOptions = new FileHttpHandlerOptions
|
||||||
{
|
{
|
||||||
AllowAutoRedirect = false,
|
AllowAutoRedirect = false,
|
||||||
UseCookieContainer = false
|
UseCookieContainer = false,
|
||||||
|
UseTracing = false
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var expectedOptions = new HttpHandlerOptions(false, false);
|
var expectedOptions = new HttpHandlerOptions(false, false, false);
|
||||||
|
|
||||||
this.Given(x => GivenTheFollowing(fileReRoute))
|
this.Given(x => GivenTheFollowing(fileReRoute))
|
||||||
.When(x => WhenICreateHttpHandlerOptions())
|
.When(x => WhenICreateHttpHandlerOptions())
|
||||||
@ -66,6 +67,7 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
_httpHandlerOptions.ShouldNotBeNull();
|
_httpHandlerOptions.ShouldNotBeNull();
|
||||||
_httpHandlerOptions.AllowAutoRedirect.ShouldBe(options.AllowAutoRedirect);
|
_httpHandlerOptions.AllowAutoRedirect.ShouldBe(options.AllowAutoRedirect);
|
||||||
_httpHandlerOptions.UseCookieContainer.ShouldBe(options.UseCookieContainer);
|
_httpHandlerOptions.UseCookieContainer.ShouldBe(options.UseCookieContainer);
|
||||||
|
_httpHandlerOptions.UseTracing.ShouldBe(options.UseTracing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text;
|
|
||||||
using CacheManager.Core;
|
using CacheManager.Core;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Hosting.Internal;
|
using Microsoft.AspNetCore.Hosting.Internal;
|
||||||
@ -13,8 +12,10 @@ using Ocelot.Configuration;
|
|||||||
using Ocelot.Configuration.File;
|
using Ocelot.Configuration.File;
|
||||||
using Ocelot.Configuration.Setter;
|
using Ocelot.Configuration.Setter;
|
||||||
using Ocelot.DependencyInjection;
|
using Ocelot.DependencyInjection;
|
||||||
using Ocelot.Logging;
|
using Ocelot.Requester;
|
||||||
|
using Ocelot.UnitTests.Requester;
|
||||||
using Shouldly;
|
using Shouldly;
|
||||||
|
using System;
|
||||||
using TestStack.BDDfy;
|
using TestStack.BDDfy;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
@ -22,11 +23,11 @@ namespace Ocelot.UnitTests.DependencyInjection
|
|||||||
{
|
{
|
||||||
public class OcelotBuilderTests
|
public class OcelotBuilderTests
|
||||||
{
|
{
|
||||||
private IServiceCollection _services;
|
private readonly IServiceCollection _services;
|
||||||
private IServiceProvider _serviceProvider;
|
private IServiceProvider _serviceProvider;
|
||||||
private IConfiguration _configRoot;
|
private readonly IConfiguration _configRoot;
|
||||||
private IOcelotBuilder _ocelotBuilder;
|
private IOcelotBuilder _ocelotBuilder;
|
||||||
private int _maxRetries;
|
private readonly int _maxRetries;
|
||||||
|
|
||||||
public OcelotBuilderTests()
|
public OcelotBuilderTests()
|
||||||
{
|
{
|
||||||
@ -40,6 +41,19 @@ namespace Ocelot.UnitTests.DependencyInjection
|
|||||||
}
|
}
|
||||||
private Exception _ex;
|
private Exception _ex;
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_add_delegating_handlers()
|
||||||
|
{
|
||||||
|
var fakeOne = new FakeDelegatingHandler(0);
|
||||||
|
var fakeTwo = new FakeDelegatingHandler(1);
|
||||||
|
|
||||||
|
this.Given(x => WhenISetUpOcelotServices())
|
||||||
|
.When(x => AddDelegate(fakeOne))
|
||||||
|
.And(x => AddDelegate(fakeTwo))
|
||||||
|
.Then(x => ThenTheProviderIsRegisteredAndReturnsHandlers())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_set_up_services()
|
public void should_set_up_services()
|
||||||
{
|
{
|
||||||
@ -76,7 +90,7 @@ namespace Ocelot.UnitTests.DependencyInjection
|
|||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_set_up_rafty()
|
public void should_set_up_rafty()
|
||||||
{
|
{
|
||||||
this.Given(x => WhenISetUpOcelotServices())
|
this.Given(x => WhenISetUpOcelotServices())
|
||||||
@ -96,6 +110,16 @@ namespace Ocelot.UnitTests.DependencyInjection
|
|||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_set_up_tracing()
|
||||||
|
{
|
||||||
|
this.Given(x => WhenISetUpOcelotServices())
|
||||||
|
.When(x => WhenISetUpOpentracing())
|
||||||
|
.When(x => WhenIAccessOcelotHttpTracingHandler())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_set_up_without_passing_in_config()
|
public void should_set_up_without_passing_in_config()
|
||||||
{
|
{
|
||||||
@ -111,6 +135,17 @@ namespace Ocelot.UnitTests.DependencyInjection
|
|||||||
path.Path.ShouldBe("/administration");
|
path.Path.ShouldBe("/administration");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ThenTheProviderIsRegisteredAndReturnsHandlers()
|
||||||
|
{
|
||||||
|
_serviceProvider = _services.BuildServiceProvider();
|
||||||
|
var provider = _serviceProvider.GetService<IDelegatingHandlerHandlerProvider>();
|
||||||
|
var handlers = provider.Get();
|
||||||
|
var handler = (FakeDelegatingHandler)handlers[0].Invoke();
|
||||||
|
handler.Order.ShouldBe(0);
|
||||||
|
handler = (FakeDelegatingHandler)handlers[1].Invoke();
|
||||||
|
handler.Order.ShouldBe(1);
|
||||||
|
}
|
||||||
|
|
||||||
private void OnlyOneVersionOfEachCacheIsRegistered()
|
private void OnlyOneVersionOfEachCacheIsRegistered()
|
||||||
{
|
{
|
||||||
var outputCache = _services.Single(x => x.ServiceType == typeof(IOcelotCache<CachedResponse>));
|
var outputCache = _services.Single(x => x.ServiceType == typeof(IOcelotCache<CachedResponse>));
|
||||||
@ -149,6 +184,11 @@ namespace Ocelot.UnitTests.DependencyInjection
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void AddDelegate(DelegatingHandler handler)
|
||||||
|
{
|
||||||
|
_ocelotBuilder.AddDelegatingHandler(() => handler);
|
||||||
|
}
|
||||||
|
|
||||||
private void ThenAnOcelotBuilderIsReturned()
|
private void ThenAnOcelotBuilderIsReturned()
|
||||||
{
|
{
|
||||||
_ocelotBuilder.ShouldBeOfType<OcelotBuilder>();
|
_ocelotBuilder.ShouldBeOfType<OcelotBuilder>();
|
||||||
@ -193,6 +233,24 @@ namespace Ocelot.UnitTests.DependencyInjection
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void WhenISetUpOpentracing()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_ocelotBuilder.AddOpenTracing(
|
||||||
|
option =>
|
||||||
|
{
|
||||||
|
option.CollectorUrl = "http://localhost:9618";
|
||||||
|
option.Service = "Ocelot.ManualTest";
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_ex = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void WhenIAccessLoggerFactory()
|
private void WhenIAccessLoggerFactory()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -205,6 +263,18 @@ namespace Ocelot.UnitTests.DependencyInjection
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void WhenIAccessOcelotHttpTracingHandler()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var tracingHandler = _serviceProvider.GetService<OcelotHttpTracingHandler>();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_ex = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void WhenIValidateScopes()
|
private void WhenIValidateScopes()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
using Ocelot.Requester.QoS;
|
using Ocelot.Requester.QoS;
|
||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Ocelot.Errors;
|
||||||
|
|
||||||
public class HttpRequestBuilderMiddlewareTests : ServerHostedMiddlewareTest
|
public class HttpRequestBuilderMiddlewareTests : ServerHostedMiddlewareTest
|
||||||
{
|
{
|
||||||
@ -51,18 +52,39 @@
|
|||||||
new ReRouteBuilder()
|
new ReRouteBuilder()
|
||||||
.WithRequestIdKey("LSRequestId")
|
.WithRequestIdKey("LSRequestId")
|
||||||
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
||||||
.WithHttpHandlerOptions(new HttpHandlerOptions(true, true))
|
.WithHttpHandlerOptions(new HttpHandlerOptions(true, true,false))
|
||||||
.Build());
|
.Build());
|
||||||
|
|
||||||
this.Given(x => x.GivenTheDownStreamUrlIs("any old string"))
|
this.Given(x => x.GivenTheDownStreamUrlIs("any old string"))
|
||||||
.And(x => x.GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(new NoQoSProvider())))
|
.And(x => x.GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(new NoQoSProvider())))
|
||||||
.And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
|
.And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
|
||||||
.And(x => x.GivenTheRequestBuilderReturns(new Ocelot.Request.Request(new HttpRequestMessage(), true, new NoQoSProvider(), false, false)))
|
.And(x => x.GivenTheRequestBuilderReturns(new Ocelot.Request.Request(new HttpRequestMessage(), true, new NoQoSProvider(), false, false, "", false)))
|
||||||
.When(x => x.WhenICallTheMiddleware())
|
.When(x => x.WhenICallTheMiddleware())
|
||||||
.Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly())
|
.Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly())
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_call_scoped_data_repository_QosProviderError()
|
||||||
|
{
|
||||||
|
|
||||||
|
var downstreamRoute = new DownstreamRoute(new List<PlaceholderNameAndValue>(),
|
||||||
|
new ReRouteBuilder()
|
||||||
|
.WithRequestIdKey("LSRequestId")
|
||||||
|
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
||||||
|
.WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true))
|
||||||
|
.Build());
|
||||||
|
|
||||||
|
this.Given(x => x.GivenTheDownStreamUrlIs("any old string"))
|
||||||
|
.And(x => x.GivenTheQosProviderHouseReturns(new ErrorResponse<IQoSProvider>(It.IsAny<Error>())))
|
||||||
|
.And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
|
||||||
|
.And(x => x.GivenTheRequestBuilderReturns(new Ocelot.Request.Request(new HttpRequestMessage(), true, new NoQoSProvider(), false, false, "", false)))
|
||||||
|
.When(x => x.WhenICallTheMiddleware())
|
||||||
|
.Then(x => x.ThenTheScopedDataRepositoryQosProviderError())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services)
|
protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
|
services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
|
||||||
@ -109,6 +131,8 @@
|
|||||||
It.IsAny<bool>(),
|
It.IsAny<bool>(),
|
||||||
It.IsAny<IQoSProvider>(),
|
It.IsAny<IQoSProvider>(),
|
||||||
It.IsAny<bool>(),
|
It.IsAny<bool>(),
|
||||||
|
It.IsAny<bool>(),
|
||||||
|
It.IsAny<string>(),
|
||||||
It.IsAny<bool>()))
|
It.IsAny<bool>()))
|
||||||
.ReturnsAsync(_request);
|
.ReturnsAsync(_request);
|
||||||
}
|
}
|
||||||
@ -118,5 +142,11 @@
|
|||||||
_scopedRepository
|
_scopedRepository
|
||||||
.Verify(x => x.Add("Request", _request.Data), Times.Once());
|
.Verify(x => x.Add("Request", _request.Data), Times.Once());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ThenTheScopedDataRepositoryQosProviderError()
|
||||||
|
{
|
||||||
|
_scopedRepository
|
||||||
|
.Verify(x => x.Add("OcelotMiddlewareError", true), Times.Once());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
namespace Ocelot.UnitTests.Request
|
namespace Ocelot.UnitTests.Request
|
||||||
{
|
{
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
|
||||||
@ -17,8 +17,9 @@
|
|||||||
private readonly HttpRequestMessage _requestMessage;
|
private readonly HttpRequestMessage _requestMessage;
|
||||||
private readonly bool _useCookieContainer;
|
private readonly bool _useCookieContainer;
|
||||||
private readonly bool _allowAutoRedirect;
|
private readonly bool _allowAutoRedirect;
|
||||||
|
|
||||||
private Response<Ocelot.Request.Request> _response;
|
private Response<Ocelot.Request.Request> _response;
|
||||||
|
private string _reRouteKey;
|
||||||
|
private readonly bool _useTracing;
|
||||||
|
|
||||||
public HttpRequestCreatorTests()
|
public HttpRequestCreatorTests()
|
||||||
{
|
{
|
||||||
@ -39,6 +40,7 @@
|
|||||||
.Then(x => x.ThenTheRequestContainsTheIsQos())
|
.Then(x => x.ThenTheRequestContainsTheIsQos())
|
||||||
.Then(x => x.ThenTheRequestContainsTheQosProvider())
|
.Then(x => x.ThenTheRequestContainsTheQosProvider())
|
||||||
.Then(x => x.ThenTheRequestContainsUseCookieContainer())
|
.Then(x => x.ThenTheRequestContainsUseCookieContainer())
|
||||||
|
.Then(x => x.ThenTheRequestContainsUseTracing())
|
||||||
.Then(x => x.ThenTheRequestContainsAllowAutoRedirect())
|
.Then(x => x.ThenTheRequestContainsAllowAutoRedirect())
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
@ -46,7 +48,7 @@
|
|||||||
private void WhenIBuildARequest()
|
private void WhenIBuildARequest()
|
||||||
{
|
{
|
||||||
_response = _requestCreator.Build(_requestMessage,
|
_response = _requestCreator.Build(_requestMessage,
|
||||||
_isQos, _qoSProvider, _useCookieContainer, _allowAutoRedirect)
|
_isQos, _qoSProvider, _useCookieContainer, _allowAutoRedirect, _reRouteKey, _useTracing)
|
||||||
.GetAwaiter()
|
.GetAwaiter()
|
||||||
.GetResult();
|
.GetResult();
|
||||||
}
|
}
|
||||||
@ -71,6 +73,11 @@
|
|||||||
_response.Data.UseCookieContainer.ShouldBe(_useCookieContainer);
|
_response.Data.UseCookieContainer.ShouldBe(_useCookieContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ThenTheRequestContainsUseTracing()
|
||||||
|
{
|
||||||
|
_response.Data.IsTracing.ShouldBe(_useTracing);
|
||||||
|
}
|
||||||
|
|
||||||
private void ThenTheRequestContainsAllowAutoRedirect()
|
private void ThenTheRequestContainsAllowAutoRedirect()
|
||||||
{
|
{
|
||||||
_response.Data.AllowAutoRedirect.ShouldBe(_allowAutoRedirect);
|
_response.Data.AllowAutoRedirect.ShouldBe(_allowAutoRedirect);
|
||||||
|
@ -0,0 +1,108 @@
|
|||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using Moq;
|
||||||
|
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 Ocelot.Request.Request _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 request = new Ocelot.Request.Request(new HttpRequestMessage(), true, null, true, true, "key", false);
|
||||||
|
|
||||||
|
this.Given(x => GivenTheRequest(request))
|
||||||
|
.And(x => GivenTheProviderReturns())
|
||||||
|
.When(x => WhenIGet())
|
||||||
|
.Then(x => ThenTheFactoryIsCalled(1))
|
||||||
|
.And(x => ThenTheProviderIsNotNull())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_get_provider()
|
||||||
|
{
|
||||||
|
var request = new Ocelot.Request.Request(new HttpRequestMessage(), true, null, true, true, "key", false);
|
||||||
|
|
||||||
|
this.Given(x => GivenTheRequest(request))
|
||||||
|
.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 request = new Ocelot.Request.Request(new HttpRequestMessage(), true, null, true, true, "key", false);
|
||||||
|
|
||||||
|
this.Given(x => GivenTheRequest(request))
|
||||||
|
.And(x => GivenTheProviderThrows())
|
||||||
|
.When(x => WhenIGet())
|
||||||
|
.And(x => ThenAnErrorIsReturned())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenAnErrorIsReturned()
|
||||||
|
{
|
||||||
|
_result.IsError.ShouldBeTrue();
|
||||||
|
_result.Errors[0].ShouldBeOfType<UnableToFindDelegatingHandlerProviderError>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenTheProviderThrows()
|
||||||
|
{
|
||||||
|
_factory.Setup(x => x.Get(It.IsAny<Ocelot.Request.Request>())).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(Ocelot.Request.Request request)
|
||||||
|
{
|
||||||
|
_request = request;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenTheProviderReturns()
|
||||||
|
{
|
||||||
|
_factory.Setup(x => x.Get(It.IsAny<Ocelot.Request.Request>())).Returns(_provider.Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenTheFactoryIsCalled(int times)
|
||||||
|
{
|
||||||
|
_factory.Verify(x => x.Get(_request), Times.Exactly(times));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,124 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net.Http;
|
||||||
|
using Moq;
|
||||||
|
using Ocelot.Logging;
|
||||||
|
using Ocelot.Requester;
|
||||||
|
using Shouldly;
|
||||||
|
using TestStack.BDDfy;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Ocelot.UnitTests.Requester
|
||||||
|
{
|
||||||
|
public class DelegatingHandlerHandlerProviderFactoryTests
|
||||||
|
{
|
||||||
|
private readonly DelegatingHandlerHandlerProviderFactory _factory;
|
||||||
|
private Mock<IOcelotLoggerFactory> _loggerFactory;
|
||||||
|
private Ocelot.Request.Request _request;
|
||||||
|
private IDelegatingHandlerHandlerProvider _provider;
|
||||||
|
private readonly Mock<IDelegatingHandlerHandlerProvider> _allRoutesProvider;
|
||||||
|
|
||||||
|
public DelegatingHandlerHandlerProviderFactoryTests()
|
||||||
|
{
|
||||||
|
_allRoutesProvider = new Mock<IDelegatingHandlerHandlerProvider>();
|
||||||
|
_loggerFactory = new Mock<IOcelotLoggerFactory>();
|
||||||
|
_factory = new DelegatingHandlerHandlerProviderFactory(_loggerFactory.Object, _allRoutesProvider.Object, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_all_from_all_routes_provider_and_qos()
|
||||||
|
{
|
||||||
|
var handlers = new List<Func<DelegatingHandler>>
|
||||||
|
{
|
||||||
|
() => new FakeDelegatingHandler(0),
|
||||||
|
() => new FakeDelegatingHandler(1)
|
||||||
|
};
|
||||||
|
|
||||||
|
var request = new Ocelot.Request.Request(new HttpRequestMessage(), true, null, true, true, "", false);
|
||||||
|
|
||||||
|
this.Given(x => GivenTheFollowingRequest(request))
|
||||||
|
.And(x => GivenTheAllRoutesProviderReturns(handlers))
|
||||||
|
.When(x => WhenIGet())
|
||||||
|
.Then(x => ThenThereIsDelegatesInProvider(3))
|
||||||
|
.And(x => ThenTheDelegatesAreAddedCorrectly())
|
||||||
|
.And(x => ThenItIsPolly(2))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_return_provider_with_no_delegates()
|
||||||
|
{
|
||||||
|
var request = new Ocelot.Request.Request(new HttpRequestMessage(), false, null, true, true, "", false);
|
||||||
|
|
||||||
|
this.Given(x => GivenTheFollowingRequest(request))
|
||||||
|
.And(x => GivenTheAllRoutesProviderReturns())
|
||||||
|
.When(x => WhenIGet())
|
||||||
|
.Then(x => ThenNoDelegatesAreInTheProvider())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_return_provider_with_qos_delegate()
|
||||||
|
{
|
||||||
|
var request = new Ocelot.Request.Request(new HttpRequestMessage(), true, null, true, true, "", false);
|
||||||
|
|
||||||
|
this.Given(x => GivenTheFollowingRequest(request))
|
||||||
|
.And(x => GivenTheAllRoutesProviderReturns())
|
||||||
|
.When(x => WhenIGet())
|
||||||
|
.Then(x => ThenThereIsDelegatesInProvider(1))
|
||||||
|
.And(x => ThenItIsPolly(0))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenTheDelegatesAreAddedCorrectly()
|
||||||
|
{
|
||||||
|
var delegates = _provider.Get();
|
||||||
|
var del = delegates[0].Invoke();
|
||||||
|
var handler = (FakeDelegatingHandler) del;
|
||||||
|
handler.Order.ShouldBe(0);
|
||||||
|
|
||||||
|
del = delegates[1].Invoke();
|
||||||
|
handler = (FakeDelegatingHandler)del;
|
||||||
|
handler.Order.ShouldBe(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenTheAllRoutesProviderReturns()
|
||||||
|
{
|
||||||
|
_allRoutesProvider.Setup(x => x.Get()).Returns(new List<Func<DelegatingHandler>>());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenTheAllRoutesProviderReturns(List<Func<DelegatingHandler>> handlers)
|
||||||
|
{
|
||||||
|
_allRoutesProvider.Setup(x => x.Get()).Returns(handlers);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenItIsPolly(int i)
|
||||||
|
{
|
||||||
|
var delegates = _provider.Get();
|
||||||
|
var del = delegates[i].Invoke();
|
||||||
|
del.ShouldBeOfType<PollyCircuitBreakingDelegatingHandler>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenThereIsDelegatesInProvider(int count)
|
||||||
|
{
|
||||||
|
_provider.ShouldNotBeNull();
|
||||||
|
_provider.Get().Count.ShouldBe(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenTheFollowingRequest(Ocelot.Request.Request request)
|
||||||
|
{
|
||||||
|
_request = request;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WhenIGet()
|
||||||
|
{
|
||||||
|
_provider = _factory.Get(_request);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenNoDelegatesAreInTheProvider()
|
||||||
|
{
|
||||||
|
_provider.ShouldNotBeNull();
|
||||||
|
_provider.Get().Count.ShouldBe(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
test/Ocelot.UnitTests/Requester/FakeDelegatingHandler.cs
Normal file
28
test/Ocelot.UnitTests/Requester/FakeDelegatingHandler.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ocelot.UnitTests.Requester
|
||||||
|
{
|
||||||
|
public class FakeDelegatingHandler : DelegatingHandler
|
||||||
|
{
|
||||||
|
public FakeDelegatingHandler()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public FakeDelegatingHandler(int order)
|
||||||
|
{
|
||||||
|
Order = order;
|
||||||
|
}
|
||||||
|
public int Order {get;private set;}
|
||||||
|
public DateTime TimeCalled {get;private set;}
|
||||||
|
|
||||||
|
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
TimeCalled = DateTime.Now;
|
||||||
|
return new HttpResponseMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
114
test/Ocelot.UnitTests/Requester/HttpClientBuilderTests.cs
Normal file
114
test/Ocelot.UnitTests/Requester/HttpClientBuilderTests.cs
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net.Http;
|
||||||
|
using Moq;
|
||||||
|
using Ocelot.Requester;
|
||||||
|
using Ocelot.Responses;
|
||||||
|
using Shouldly;
|
||||||
|
using TestStack.BDDfy;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Ocelot.UnitTests.Requester
|
||||||
|
{
|
||||||
|
public class HttpClientBuilderTests
|
||||||
|
{
|
||||||
|
private readonly HttpClientBuilder _builder;
|
||||||
|
private readonly Mock<IDelegatingHandlerHandlerHouse> _house;
|
||||||
|
private readonly Mock<IDelegatingHandlerHandlerProvider> _provider;
|
||||||
|
private IHttpClientBuilder _builderResult;
|
||||||
|
private IHttpClient _httpClient;
|
||||||
|
private HttpResponseMessage _response;
|
||||||
|
private Ocelot.Request.Request _request;
|
||||||
|
|
||||||
|
public HttpClientBuilderTests()
|
||||||
|
{
|
||||||
|
_provider = new Mock<IDelegatingHandlerHandlerProvider>();
|
||||||
|
_house = new Mock<IDelegatingHandlerHandlerHouse>();
|
||||||
|
_builder = new HttpClientBuilder(_house.Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_build_http_client()
|
||||||
|
{
|
||||||
|
this.Given(x => GivenTheProviderReturns())
|
||||||
|
.And(x => GivenARequest())
|
||||||
|
.And(x => GivenTheHouseReturns())
|
||||||
|
.When(x => WhenIBuild())
|
||||||
|
.Then(x => ThenTheHttpClientShouldNotBeNull())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_call_delegating_handlers_in_order()
|
||||||
|
{
|
||||||
|
var fakeOne = new FakeDelegatingHandler();
|
||||||
|
var fakeTwo = new FakeDelegatingHandler();
|
||||||
|
|
||||||
|
var handlers = new List<Func<DelegatingHandler>>()
|
||||||
|
{
|
||||||
|
() => fakeOne,
|
||||||
|
() => fakeTwo
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Given(x => GivenTheProviderReturns(handlers))
|
||||||
|
.And(x => GivenARequest())
|
||||||
|
.And(x => GivenTheHouseReturns())
|
||||||
|
.And(x => WhenIBuild())
|
||||||
|
.When(x => WhenICallTheClient())
|
||||||
|
.Then(x => ThenTheFakeAreHandledInOrder(fakeOne, fakeTwo))
|
||||||
|
.And(x => ThenSomethingIsReturned())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenARequest()
|
||||||
|
{
|
||||||
|
_request = new Ocelot.Request.Request(null, false, null, false, false, "", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenTheHouseReturns()
|
||||||
|
{
|
||||||
|
_house
|
||||||
|
.Setup(x => x.Get(It.IsAny<Ocelot.Request.Request>()))
|
||||||
|
.Returns(new OkResponse<IDelegatingHandlerHandlerProvider>(_provider.Object));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenSomethingIsReturned()
|
||||||
|
{
|
||||||
|
_response.ShouldNotBeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WhenICallTheClient()
|
||||||
|
{
|
||||||
|
_response = _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, "http://test.com")).GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenTheFakeAreHandledInOrder(FakeDelegatingHandler fakeOne, FakeDelegatingHandler fakeTwo)
|
||||||
|
{
|
||||||
|
fakeOne.TimeCalled.ShouldBeGreaterThan(fakeTwo.TimeCalled);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenTheProviderReturns()
|
||||||
|
{
|
||||||
|
_provider
|
||||||
|
.Setup(x => x.Get())
|
||||||
|
.Returns(new List<Func<DelegatingHandler>>(){ () => new FakeDelegatingHandler()});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenTheProviderReturns(List<Func<DelegatingHandler>> handlers)
|
||||||
|
{
|
||||||
|
_provider
|
||||||
|
.Setup(x => x.Get())
|
||||||
|
.Returns(handlers);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WhenIBuild()
|
||||||
|
{
|
||||||
|
_httpClient = _builder.Create(_request);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenTheHttpClientShouldNotBeNull()
|
||||||
|
{
|
||||||
|
_httpClient.ShouldNotBeNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Moq;
|
||||||
|
using Ocelot.Logging;
|
||||||
|
using Ocelot.Requester;
|
||||||
|
using Ocelot.Requester.QoS;
|
||||||
|
using Ocelot.Responses;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Text;
|
||||||
|
using TestStack.BDDfy;
|
||||||
|
using Xunit;
|
||||||
|
using Shouldly;
|
||||||
|
|
||||||
|
namespace Ocelot.UnitTests.Requester
|
||||||
|
{
|
||||||
|
public class HttpClientHttpRequesterTest
|
||||||
|
{
|
||||||
|
private readonly Mock<IHttpClientCache> _cacheHandlers;
|
||||||
|
private Mock<IDelegatingHandlerHandlerHouse> _house;
|
||||||
|
private Mock<IDelegatingHandlerHandlerProvider> _provider;
|
||||||
|
private Response<HttpResponseMessage> _response;
|
||||||
|
private readonly HttpClientHttpRequester _httpClientRequester;
|
||||||
|
private Ocelot.Request.Request _request;
|
||||||
|
private Mock<IOcelotLoggerFactory> _loggerFactory;
|
||||||
|
private Mock<IOcelotLogger> _logger;
|
||||||
|
|
||||||
|
public HttpClientHttpRequesterTest()
|
||||||
|
{
|
||||||
|
_provider = new Mock<IDelegatingHandlerHandlerProvider>();
|
||||||
|
_provider.Setup(x => x.Get()).Returns(new List<Func<DelegatingHandler>>());
|
||||||
|
_house = new Mock<IDelegatingHandlerHandlerHouse>();
|
||||||
|
_house.Setup(x => x.Get(It.IsAny<Ocelot.Request.Request>())).Returns(new OkResponse<IDelegatingHandlerHandlerProvider>(_provider.Object));
|
||||||
|
_logger = new Mock<IOcelotLogger>();
|
||||||
|
_loggerFactory = new Mock<IOcelotLoggerFactory>();
|
||||||
|
_loggerFactory
|
||||||
|
.Setup(x => x.CreateLogger<HttpClientHttpRequester>())
|
||||||
|
.Returns(_logger.Object);
|
||||||
|
_cacheHandlers = new Mock<IHttpClientCache>();
|
||||||
|
_httpClientRequester = new HttpClientHttpRequester(_loggerFactory.Object, _cacheHandlers.Object, _house.Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_call_request_correctly()
|
||||||
|
{
|
||||||
|
this.Given(x=>x.GivenTheRequestIs(new Ocelot.Request.Request(new HttpRequestMessage() { RequestUri = new Uri("http://www.bbc.co.uk") }, false, new NoQoSProvider(), false, false, "", false)))
|
||||||
|
.When(x=>x.WhenIGetResponse())
|
||||||
|
.Then(x => x.ThenTheResponseIsCalledCorrectly())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_call_request_unable_to_complete_request()
|
||||||
|
{
|
||||||
|
this.Given(x => x.GivenTheRequestIs(new Ocelot.Request.Request(new HttpRequestMessage() { RequestUri = new Uri("http://localhost:60080") }, false, new NoQoSProvider(), false, false, "", false)))
|
||||||
|
.When(x => x.WhenIGetResponse())
|
||||||
|
.Then(x => x.ThenTheResponseIsCalledError())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenTheRequestIs(Ocelot.Request.Request request)
|
||||||
|
{
|
||||||
|
_request = request;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WhenIGetResponse()
|
||||||
|
{
|
||||||
|
_response = _httpClientRequester.GetResponse(_request).Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenTheResponseIsCalledCorrectly()
|
||||||
|
{
|
||||||
|
_response.IsError.ShouldBeFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenTheResponseIsCalledError()
|
||||||
|
{
|
||||||
|
_response.IsError.ShouldBeTrue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
namespace Ocelot.UnitTests.Requester
|
namespace Ocelot.UnitTests.Requester
|
||||||
{
|
{
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
@ -28,7 +28,7 @@
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void should_call_scoped_data_repository_correctly()
|
public void should_call_scoped_data_repository_correctly()
|
||||||
{
|
{
|
||||||
this.Given(x => x.GivenTheRequestIs(new Ocelot.Request.Request(new HttpRequestMessage(),true, new NoQoSProvider(), false, false)))
|
this.Given(x => x.GivenTheRequestIs(new Ocelot.Request.Request(new HttpRequestMessage(),true, new NoQoSProvider(), false, false, "", false)))
|
||||||
.And(x => x.GivenTheRequesterReturns(new HttpResponseMessage()))
|
.And(x => x.GivenTheRequesterReturns(new HttpResponseMessage()))
|
||||||
.And(x => x.GivenTheScopedRepoReturns())
|
.And(x => x.GivenTheScopedRepoReturns())
|
||||||
.When(x => x.WhenICallTheMiddleware())
|
.When(x => x.WhenICallTheMiddleware())
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
using Moq;
|
using Moq;
|
||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
using Ocelot.Configuration.Builder;
|
using Ocelot.Configuration.Builder;
|
||||||
using Ocelot.LoadBalancer.LoadBalancers;
|
|
||||||
using Ocelot.Requester.QoS;
|
using Ocelot.Requester.QoS;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
using Ocelot.UnitTests.LoadBalancer;
|
|
||||||
using Shouldly;
|
using Shouldly;
|
||||||
using TestStack.BDDfy;
|
using TestStack.BDDfy;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
@ -121,7 +121,7 @@ namespace Ocelot.UnitTests.Responder
|
|||||||
// If this test fails then it's because the number of error codes has changed.
|
// If this test fails then it's because the number of error codes has changed.
|
||||||
// You should make the appropriate changes to the test cases here to ensure
|
// You should make the appropriate changes to the test cases here to ensure
|
||||||
// they cover all the error codes, and then modify this assertion.
|
// they cover all the error codes, and then modify this assertion.
|
||||||
Enum.GetNames(typeof(OcelotErrorCode)).Length.ShouldBe(32, "Looks like the number of error codes has changed. Do you need to modify ErrorsToHttpStatusCodeMapper?");
|
Enum.GetNames(typeof(OcelotErrorCode)).Length.ShouldBe(33, "Looks like the number of error codes has changed. Do you need to modify ErrorsToHttpStatusCodeMapper?");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShouldMapErrorToStatusCode(OcelotErrorCode errorCode, HttpStatusCode expectedHttpStatusCode)
|
private void ShouldMapErrorToStatusCode(OcelotErrorCode errorCode, HttpStatusCode expectedHttpStatusCode)
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
namespace Ocelot.UnitTests.Responder
|
namespace Ocelot.UnitTests.Responder
|
||||||
{
|
{
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
using Ocelot.DownstreamRouteFinder.Finder;
|
||||||
|
using Ocelot.Errors;
|
||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
|
using Ocelot.Requester;
|
||||||
using Ocelot.Responder;
|
using Ocelot.Responder;
|
||||||
using Ocelot.Responder.Middleware;
|
using Ocelot.Responder.Middleware;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
@ -35,6 +39,17 @@
|
|||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_return_any_errors()
|
||||||
|
{
|
||||||
|
this.Given(x => x.GivenTheHttpResponseMessageIs(new HttpResponseMessage()))
|
||||||
|
.And(x => x.GivenThereArePipelineErrors(new UnableToFindDownstreamRouteError()))
|
||||||
|
.When(x => x.WhenICallTheMiddleware())
|
||||||
|
.Then(x => x.ThenThereAreNoErrors())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services)
|
protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
|
services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
|
||||||
@ -68,5 +83,14 @@
|
|||||||
{
|
{
|
||||||
//todo a better assert?
|
//todo a better assert?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void GivenThereArePipelineErrors(Error error)
|
||||||
|
{
|
||||||
|
ScopedRepository
|
||||||
|
.Setup(x => x.Get<bool>("OcelotMiddlewareError"))
|
||||||
|
.Returns(new OkResponse<bool>(true));
|
||||||
|
ScopedRepository.Setup(x => x.Get<List<Error>>("OcelotMiddlewareErrors"))
|
||||||
|
.Returns(new OkResponse<List<Error>>(new List<Error>() { error }));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,212 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using Consul;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Moq;
|
||||||
|
using Ocelot.Logging;
|
||||||
|
using Ocelot.ServiceDiscovery;
|
||||||
|
using Ocelot.Values;
|
||||||
|
using Xunit;
|
||||||
|
using TestStack.BDDfy;
|
||||||
|
using Shouldly;
|
||||||
|
|
||||||
|
namespace Ocelot.UnitTests.ServiceDiscovery
|
||||||
|
{
|
||||||
|
public class ConsulServiceDiscoveryProviderTests : IDisposable
|
||||||
|
{
|
||||||
|
private IWebHost _fakeConsulBuilder;
|
||||||
|
private readonly List<ServiceEntry> _serviceEntries;
|
||||||
|
private readonly ConsulServiceDiscoveryProvider _provider;
|
||||||
|
private readonly string _serviceName;
|
||||||
|
private readonly int _port;
|
||||||
|
private readonly string _consulHost;
|
||||||
|
private readonly string _fakeConsulServiceDiscoveryUrl;
|
||||||
|
private List<Service> _services;
|
||||||
|
private Mock<IOcelotLoggerFactory> _factory;
|
||||||
|
private readonly Mock<IOcelotLogger> _logger;
|
||||||
|
|
||||||
|
public ConsulServiceDiscoveryProviderTests()
|
||||||
|
{
|
||||||
|
_serviceName = "test";
|
||||||
|
_port = 8500;
|
||||||
|
_consulHost = "localhost";
|
||||||
|
_fakeConsulServiceDiscoveryUrl = $"http://{_consulHost}:{_port}";
|
||||||
|
_serviceEntries = new List<ServiceEntry>();
|
||||||
|
|
||||||
|
_factory = new Mock<IOcelotLoggerFactory>();
|
||||||
|
_logger = new Mock<IOcelotLogger>();
|
||||||
|
_factory.Setup(x => x.CreateLogger<ConsulServiceDiscoveryProvider>()).Returns(_logger.Object);
|
||||||
|
|
||||||
|
var config = new ConsulRegistryConfiguration(_consulHost, _port, _serviceName);
|
||||||
|
_provider = new ConsulServiceDiscoveryProvider(config, _factory.Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_return_service_from_consul()
|
||||||
|
{
|
||||||
|
var serviceEntryOne = new ServiceEntry()
|
||||||
|
{
|
||||||
|
Service = new AgentService()
|
||||||
|
{
|
||||||
|
Service = _serviceName,
|
||||||
|
Address = "localhost",
|
||||||
|
Port = 50881,
|
||||||
|
ID = Guid.NewGuid().ToString(),
|
||||||
|
Tags = new string[0]
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Given(x =>GivenThereIsAFakeConsulServiceDiscoveryProvider(_fakeConsulServiceDiscoveryUrl, _serviceName))
|
||||||
|
.And(x => GivenTheServicesAreRegisteredWithConsul(serviceEntryOne))
|
||||||
|
.When(x => WhenIGetTheServices())
|
||||||
|
.Then(x => ThenTheCountIs(1))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_not_return_services_with_invalid_address()
|
||||||
|
{
|
||||||
|
var serviceEntryOne = new ServiceEntry()
|
||||||
|
{
|
||||||
|
Service = new AgentService()
|
||||||
|
{
|
||||||
|
Service = _serviceName,
|
||||||
|
Address = "http://localhost",
|
||||||
|
Port = 50881,
|
||||||
|
ID = Guid.NewGuid().ToString(),
|
||||||
|
Tags = new string[0]
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var serviceEntryTwo = new ServiceEntry()
|
||||||
|
{
|
||||||
|
Service = new AgentService()
|
||||||
|
{
|
||||||
|
Service = _serviceName,
|
||||||
|
Address = "http://localhost",
|
||||||
|
Port = 50888,
|
||||||
|
ID = Guid.NewGuid().ToString(),
|
||||||
|
Tags = new string[0]
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(_fakeConsulServiceDiscoveryUrl, _serviceName))
|
||||||
|
.And(x => GivenTheServicesAreRegisteredWithConsul(serviceEntryOne, serviceEntryTwo))
|
||||||
|
.When(x => WhenIGetTheServices())
|
||||||
|
.Then(x => ThenTheCountIs(0))
|
||||||
|
.And(x => ThenTheLoggerHasBeenCalledCorrectlyForInvalidAddress())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_not_return_services_with_invalid_port()
|
||||||
|
{
|
||||||
|
var serviceEntryOne = new ServiceEntry()
|
||||||
|
{
|
||||||
|
Service = new AgentService()
|
||||||
|
{
|
||||||
|
Service = _serviceName,
|
||||||
|
Address = "localhost",
|
||||||
|
Port = -1,
|
||||||
|
ID = Guid.NewGuid().ToString(),
|
||||||
|
Tags = new string[0]
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var serviceEntryTwo = new ServiceEntry()
|
||||||
|
{
|
||||||
|
Service = new AgentService()
|
||||||
|
{
|
||||||
|
Service = _serviceName,
|
||||||
|
Address = "localhost",
|
||||||
|
Port = 0,
|
||||||
|
ID = Guid.NewGuid().ToString(),
|
||||||
|
Tags = new string[0]
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(_fakeConsulServiceDiscoveryUrl, _serviceName))
|
||||||
|
.And(x => GivenTheServicesAreRegisteredWithConsul(serviceEntryOne, serviceEntryTwo))
|
||||||
|
.When(x => WhenIGetTheServices())
|
||||||
|
.Then(x => ThenTheCountIs(0))
|
||||||
|
.And(x => ThenTheLoggerHasBeenCalledCorrectlyForInvalidPorts())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenTheLoggerHasBeenCalledCorrectlyForInvalidAddress()
|
||||||
|
{
|
||||||
|
_logger.Verify(
|
||||||
|
x => x.LogError(
|
||||||
|
"Unable to use service Address: http://localhost and Port: 50881 as it is invalid. Address must contain host only e.g. localhost and port must be greater than 0"),
|
||||||
|
Times.Once);
|
||||||
|
|
||||||
|
_logger.Verify(
|
||||||
|
x => x.LogError(
|
||||||
|
"Unable to use service Address: http://localhost and Port: 50888 as it is invalid. Address must contain host only e.g. localhost and port must be greater than 0"),
|
||||||
|
Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenTheLoggerHasBeenCalledCorrectlyForInvalidPorts()
|
||||||
|
{
|
||||||
|
_logger.Verify(
|
||||||
|
x => x.LogError(
|
||||||
|
"Unable to use service Address: localhost and Port: -1 as it is invalid. Address must contain host only e.g. localhost and port must be greater than 0"),
|
||||||
|
Times.Once);
|
||||||
|
|
||||||
|
_logger.Verify(
|
||||||
|
x => x.LogError(
|
||||||
|
"Unable to use service Address: localhost and Port: 0 as it is invalid. Address must contain host only e.g. localhost and port must be greater than 0"),
|
||||||
|
Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenTheCountIs(int count)
|
||||||
|
{
|
||||||
|
_services.Count.ShouldBe(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WhenIGetTheServices()
|
||||||
|
{
|
||||||
|
_services = _provider.Get().GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenTheServicesAreRegisteredWithConsul(params ServiceEntry[] serviceEntries)
|
||||||
|
{
|
||||||
|
foreach (var serviceEntry in serviceEntries)
|
||||||
|
{
|
||||||
|
_serviceEntries.Add(serviceEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url, string serviceName)
|
||||||
|
{
|
||||||
|
_fakeConsulBuilder = new WebHostBuilder()
|
||||||
|
.UseUrls(url)
|
||||||
|
.UseKestrel()
|
||||||
|
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||||
|
.UseIISIntegration()
|
||||||
|
.UseUrls(url)
|
||||||
|
.Configure(app =>
|
||||||
|
{
|
||||||
|
app.Run(async context =>
|
||||||
|
{
|
||||||
|
if (context.Request.Path.Value == $"/v1/health/service/{serviceName}")
|
||||||
|
{
|
||||||
|
await context.Response.WriteJsonAsync(_serviceEntries);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
_fakeConsulBuilder.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_fakeConsulBuilder?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Moq;
|
||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
using Ocelot.Configuration.Builder;
|
using Ocelot.Configuration.Builder;
|
||||||
|
using Ocelot.Logging;
|
||||||
using Ocelot.ServiceDiscovery;
|
using Ocelot.ServiceDiscovery;
|
||||||
using Shouldly;
|
using Shouldly;
|
||||||
using TestStack.BDDfy;
|
using TestStack.BDDfy;
|
||||||
@ -15,10 +17,12 @@ namespace Ocelot.UnitTests.ServiceDiscovery
|
|||||||
private IServiceDiscoveryProvider _result;
|
private IServiceDiscoveryProvider _result;
|
||||||
private readonly ServiceDiscoveryProviderFactory _factory;
|
private readonly ServiceDiscoveryProviderFactory _factory;
|
||||||
private ReRoute _reRoute;
|
private ReRoute _reRoute;
|
||||||
|
private Mock<IOcelotLoggerFactory> _loggerFactory;
|
||||||
|
|
||||||
public ServiceProviderFactoryTests()
|
public ServiceProviderFactoryTests()
|
||||||
{
|
{
|
||||||
_factory = new ServiceDiscoveryProviderFactory();
|
_loggerFactory = new Mock<IOcelotLoggerFactory>();
|
||||||
|
_factory = new ServiceDiscoveryProviderFactory(_loggerFactory.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user