Feature/move polly (#561)

* added delegate to select last handler

* #529 implemented a way we can inject the last delegating handler

* wip - moving code

* #529 removed loads of qos code and moved it into Ocelot.Provider.Polly
This commit is contained in:
Tom Pallister 2018-08-19 10:14:15 +01:00 committed by GitHub
parent e909cf9ce7
commit 98ba0271be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 213 additions and 669 deletions

View File

@ -1,6 +1,4 @@
using Polly.Timeout; namespace Ocelot.Configuration
namespace Ocelot.Configuration
{ {
public class QoSOptions public class QoSOptions
{ {
@ -9,7 +7,9 @@ namespace Ocelot.Configuration
int durationofBreak, int durationofBreak,
int timeoutValue, int timeoutValue,
string key, string key,
TimeoutStrategy timeoutStrategy = TimeoutStrategy.Pessimistic) //todo - this is never set in Ocelot so always Pessimistic...I guess it doesn't
//matter to much.
string timeoutStrategy = "Pessimistic")
{ {
ExceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking; ExceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking;
DurationOfBreak = durationofBreak; DurationOfBreak = durationofBreak;
@ -24,9 +24,10 @@ namespace Ocelot.Configuration
public int TimeoutValue { get; } public int TimeoutValue { get; }
public TimeoutStrategy TimeoutStrategy { get; } public string TimeoutStrategy { get; }
public bool UseQos => ExceptionsAllowedBeforeBreaking > 0 && TimeoutValue > 0; public bool UseQos => ExceptionsAllowedBeforeBreaking > 0 && TimeoutValue > 0;
public string Key { get; } public string Key { get; }
} }
} }

View File

@ -28,17 +28,12 @@ namespace Ocelot.DependencyInjection
using Ocelot.Requester.QoS; using Ocelot.Requester.QoS;
using Ocelot.Responder; using Ocelot.Responder;
using Ocelot.ServiceDiscovery; using Ocelot.ServiceDiscovery;
using System;
using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using Microsoft.AspNetCore.Builder;
using Ocelot.Configuration; using Ocelot.Configuration;
using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.DependencyInjection.Extensions;
using System.Net.Http; using System.Net.Http;
using Ocelot.Infrastructure; using Ocelot.Infrastructure;
using Ocelot.Middleware.Multiplexer; using Ocelot.Middleware.Multiplexer;
using ServiceDiscovery.Providers;
using Ocelot.Request.Creator; using Ocelot.Request.Creator;
public class OcelotBuilder : IOcelotBuilder public class OcelotBuilder : IOcelotBuilder
@ -75,8 +70,6 @@ namespace Ocelot.DependencyInjection
Services.TryAddSingleton<IRegionCreator, RegionCreator>(); Services.TryAddSingleton<IRegionCreator, RegionCreator>();
Services.TryAddSingleton<IFileConfigurationRepository, DiskFileConfigurationRepository>(); Services.TryAddSingleton<IFileConfigurationRepository, DiskFileConfigurationRepository>();
Services.TryAddSingleton<IFileConfigurationSetter, FileAndInternalConfigurationSetter>(); Services.TryAddSingleton<IFileConfigurationSetter, FileAndInternalConfigurationSetter>();
Services.TryAddSingleton<IQosProviderHouse, QosProviderHouse>();
Services.TryAddSingleton<IQoSProviderFactory, QoSProviderFactory>();
Services.TryAddSingleton<IServiceDiscoveryProviderFactory, ServiceDiscoveryProviderFactory>(); Services.TryAddSingleton<IServiceDiscoveryProviderFactory, ServiceDiscoveryProviderFactory>();
Services.TryAddSingleton<ILoadBalancerFactory, LoadBalancerFactory>(); Services.TryAddSingleton<ILoadBalancerFactory, LoadBalancerFactory>();
Services.TryAddSingleton<ILoadBalancerHouse, LoadBalancerHouse>(); Services.TryAddSingleton<ILoadBalancerHouse, LoadBalancerHouse>();
@ -136,6 +129,7 @@ namespace Ocelot.DependencyInjection
Services.TryAddSingleton<IDefinedAggregatorProvider, ServiceLocatorDefinedAggregatorProvider>(); Services.TryAddSingleton<IDefinedAggregatorProvider, ServiceLocatorDefinedAggregatorProvider>();
Services.TryAddSingleton<IDownstreamRequestCreator, DownstreamRequestCreator>(); Services.TryAddSingleton<IDownstreamRequestCreator, DownstreamRequestCreator>();
Services.TryAddSingleton<IFrameworkDescription, FrameworkDescription>(); Services.TryAddSingleton<IFrameworkDescription, FrameworkDescription>();
Services.TryAddSingleton<IQoSFactory, QoSFactory>();
} }
public IOcelotBuilder AddSingletonDefinedAggregator<T>() public IOcelotBuilder AddSingletonDefinedAggregator<T>()

View File

@ -45,6 +45,5 @@
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.0" /> <PackageReference Include="System.Text.RegularExpressions" Version="4.3.0" />
<PackageReference Include="Polly" Version="6.0.1" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,31 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using Microsoft.Extensions.DependencyInjection;
using Ocelot.Configuration;
using Ocelot.Logging;
using Ocelot.Requester.QoS;
using Ocelot.Responses;
namespace Ocelot.Requester namespace Ocelot.Requester
{ {
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using Microsoft.Extensions.DependencyInjection;
using Ocelot.Configuration;
using Ocelot.Responses;
using QoS;
public class DelegatingHandlerHandlerFactory : IDelegatingHandlerHandlerFactory public class DelegatingHandlerHandlerFactory : IDelegatingHandlerHandlerFactory
{ {
private readonly ITracingHandlerFactory _factory; private readonly ITracingHandlerFactory _tracingFactory;
private readonly IOcelotLoggerFactory _loggerFactory; private readonly IQoSFactory _qoSFactory;
private readonly IQosProviderHouse _qosProviderHouse;
private readonly IServiceProvider _serviceProvider; private readonly IServiceProvider _serviceProvider;
public DelegatingHandlerHandlerFactory(IOcelotLoggerFactory loggerFactory, public DelegatingHandlerHandlerFactory(
ITracingHandlerFactory factory, ITracingHandlerFactory tracingFactory,
IQosProviderHouse qosProviderHouse, IQoSFactory qoSFactory,
IServiceProvider serviceProvider) IServiceProvider serviceProvider)
{ {
_serviceProvider = serviceProvider; _serviceProvider = serviceProvider;
_factory = factory; _tracingFactory = tracingFactory;
_loggerFactory = loggerFactory; _qoSFactory = qoSFactory;
_qosProviderHouse = qosProviderHouse;
} }
public Response<List<Func<DelegatingHandler>>> Get(DownstreamReRoute request) public Response<List<Func<DelegatingHandler>>> Get(DownstreamReRoute request)
@ -64,19 +61,21 @@ namespace Ocelot.Requester
if (request.HttpHandlerOptions.UseTracing) if (request.HttpHandlerOptions.UseTracing)
{ {
handlers.Add(() => (DelegatingHandler)_factory.Get()); handlers.Add(() => (DelegatingHandler)_tracingFactory.Get());
} }
if (request.QosOptions.UseQos) if (request.QosOptions.UseQos)
{ {
var qosProvider = _qosProviderHouse.Get(request); var handler = _qoSFactory.Get(request);
if (qosProvider.IsError) if (handler != null && !handler.IsError)
{ {
return new ErrorResponse<List<Func<DelegatingHandler>>>(qosProvider.Errors); handlers.Add(() => handler.Data);
}
else
{
return new ErrorResponse<List<Func<DelegatingHandler>>>(handler?.Errors);
} }
handlers.Add(() => new PollyCircuitBreakingDelegatingHandler(qosProvider.Data, _loggerFactory));
} }
return new OkResponse<List<Func<DelegatingHandler>>>(handlers); return new OkResponse<List<Func<DelegatingHandler>>>(handlers);

View File

@ -132,7 +132,7 @@ namespace Ocelot.Requester
{ {
var cacheKey = $"{request.DownstreamRequest.Method}:{request.DownstreamRequest.OriginalString}"; var cacheKey = $"{request.DownstreamRequest.Method}:{request.DownstreamRequest.OriginalString}";
this._logger.LogDebug($"Cache key for request is {cacheKey}"); _logger.LogDebug($"Cache key for request is {cacheKey}");
return cacheKey; return cacheKey;
} }

View File

@ -4,8 +4,6 @@ using System.Threading.Tasks;
using Ocelot.Logging; using Ocelot.Logging;
using Ocelot.Middleware; using Ocelot.Middleware;
using Ocelot.Responses; using Ocelot.Responses;
using Polly.CircuitBreaker;
using Polly.Timeout;
namespace Ocelot.Requester namespace Ocelot.Requester
{ {
@ -35,18 +33,6 @@ namespace Ocelot.Requester
var response = await httpClient.SendAsync(context.DownstreamRequest.ToHttpRequestMessage()); var response = await httpClient.SendAsync(context.DownstreamRequest.ToHttpRequestMessage());
return new OkResponse<HttpResponseMessage>(response); return new OkResponse<HttpResponseMessage>(response);
} }
catch (TimeoutRejectedException exception)
{
return new ErrorResponse<HttpResponseMessage>(new RequestTimedOutError(exception));
}
catch (TaskCanceledException exception)
{
return new ErrorResponse<HttpResponseMessage>(new RequestTimedOutError(exception));
}
catch (BrokenCircuitException exception)
{
return new ErrorResponse<HttpResponseMessage>(new RequestTimedOutError(exception));
}
catch (Exception exception) catch (Exception exception)
{ {
return new ErrorResponse<HttpResponseMessage>(new UnableToCompleteRequestError(exception)); return new ErrorResponse<HttpResponseMessage>(new UnableToCompleteRequestError(exception));

View File

@ -1,45 +0,0 @@
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Ocelot.Logging;
using Ocelot.Requester.QoS;
using Polly;
using Polly.CircuitBreaker;
using Polly.Timeout;
namespace Ocelot.Requester
{
public class PollyCircuitBreakingDelegatingHandler : DelegatingHandler
{
private readonly IQoSProvider _qoSProvider;
private readonly IOcelotLogger _logger;
public PollyCircuitBreakingDelegatingHandler(
IQoSProvider qoSProvider,
IOcelotLoggerFactory loggerFactory)
{
_qoSProvider = qoSProvider;
_logger = loggerFactory.CreateLogger<PollyCircuitBreakingDelegatingHandler>();
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
try
{
return await Policy
.WrapAsync(_qoSProvider.CircuitBreaker.CircuitBreakerPolicy, _qoSProvider.CircuitBreaker.TimeoutPolicy)
.ExecuteAsync(() => base.SendAsync(request,cancellationToken));
}
catch (BrokenCircuitException ex)
{
_logger.LogError($"Reached to allowed number of exceptions. Circuit is open",ex);
throw;
}
catch (HttpRequestException ex)
{
_logger.LogError($"Error in CircuitBreakingDelegatingHandler.SendAync", ex);
throw;
}
}
}
}

View File

@ -1,17 +0,0 @@
using Polly.CircuitBreaker;
using Polly.Timeout;
namespace Ocelot.Requester.QoS
{
public class CircuitBreaker
{
public CircuitBreaker(CircuitBreakerPolicy circuitBreakerPolicy, TimeoutPolicy timeoutPolicy)
{
CircuitBreakerPolicy = circuitBreakerPolicy;
TimeoutPolicy = timeoutPolicy;
}
public CircuitBreakerPolicy CircuitBreakerPolicy { get; private set; }
public TimeoutPolicy TimeoutPolicy { get; private set; }
}
}

View File

@ -1,7 +0,0 @@
namespace Ocelot.Requester.QoS
{
public interface IQoSProvider
{
CircuitBreaker CircuitBreaker { get; }
}
}

View File

@ -1,10 +0,0 @@
using Ocelot.Configuration;
using Ocelot.LoadBalancer.LoadBalancers;
namespace Ocelot.Requester.QoS
{
public interface IQoSProviderFactory
{
IQoSProvider Get(DownstreamReRoute reRoute);
}
}

View File

@ -0,0 +1,11 @@
namespace Ocelot.Requester.QoS
{
using System.Net.Http;
using Configuration;
using Responses;
public interface IQoSFactory
{
Response<DelegatingHandler> Get(DownstreamReRoute request);
}
}

View File

@ -1,10 +0,0 @@
using Ocelot.Configuration;
using Ocelot.Responses;
namespace Ocelot.Requester.QoS
{
public interface IQosProviderHouse
{
Response<IQoSProvider> Get(DownstreamReRoute reRoute);
}
}

View File

@ -1,7 +0,0 @@
namespace Ocelot.Requester.QoS
{
public class NoQoSProvider : IQoSProvider
{
public CircuitBreaker CircuitBreaker { get; }
}
}

View File

@ -1,51 +0,0 @@
using System;
using System.Net.Http;
using Ocelot.Configuration;
using Ocelot.Logging;
using Polly;
using Polly.CircuitBreaker;
using Polly.Timeout;
namespace Ocelot.Requester.QoS
{
public class PollyQoSProvider : IQoSProvider
{
private readonly CircuitBreakerPolicy _circuitBreakerPolicy;
private readonly TimeoutPolicy _timeoutPolicy;
private readonly IOcelotLogger _logger;
private readonly CircuitBreaker _circuitBreaker;
public PollyQoSProvider(DownstreamReRoute reRoute, IOcelotLoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<PollyQoSProvider>();
_timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromMilliseconds(reRoute.QosOptions.TimeoutValue), reRoute.QosOptions.TimeoutStrategy);
_circuitBreakerPolicy = Policy
.Handle<HttpRequestException>()
.Or<TimeoutRejectedException>()
.Or<TimeoutException>()
.CircuitBreakerAsync(
exceptionsAllowedBeforeBreaking: reRoute.QosOptions.ExceptionsAllowedBeforeBreaking,
durationOfBreak: TimeSpan.FromMilliseconds(reRoute.QosOptions.DurationOfBreak),
onBreak: (ex, breakDelay) =>
{
_logger.LogError(
".Breaker logging: Breaking the circuit for " + breakDelay.TotalMilliseconds + "ms!", ex);
},
onReset: () =>
{
_logger.LogDebug(".Breaker logging: Call ok! Closed the circuit again.");
},
onHalfOpen: () =>
{
_logger.LogDebug(".Breaker logging: Half-open; next call is a trial.");
}
);
_circuitBreaker = new CircuitBreaker(_circuitBreakerPolicy, _timeoutPolicy);
}
public CircuitBreaker CircuitBreaker => _circuitBreaker;
}
}

View File

@ -1,25 +0,0 @@
using Ocelot.Configuration;
using Ocelot.Logging;
namespace Ocelot.Requester.QoS
{
public class QoSProviderFactory : IQoSProviderFactory
{
private readonly IOcelotLoggerFactory _loggerFactory;
public QoSProviderFactory(IOcelotLoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory;
}
public IQoSProvider Get(DownstreamReRoute reRoute)
{
if (reRoute.QosOptions.UseQos)
{
return new PollyQoSProvider(reRoute, _loggerFactory);
}
return new NoQoSProvider();
}
}
}

View File

@ -0,0 +1,33 @@
namespace Ocelot.Requester.QoS
{
using System;
using System.Net.Http;
using Configuration;
using Logging;
using Microsoft.Extensions.DependencyInjection;
using Responses;
public class QoSFactory : IQoSFactory
{
private readonly IServiceProvider _serviceProvider;
private readonly IOcelotLoggerFactory _ocelotLoggerFactory;
public QoSFactory(IServiceProvider serviceProvider, IOcelotLoggerFactory ocelotLoggerFactory)
{
_serviceProvider = serviceProvider;
_ocelotLoggerFactory = ocelotLoggerFactory;
}
public Response<DelegatingHandler> Get(DownstreamReRoute request)
{
var handler = _serviceProvider.GetService<QosDelegatingHandlerDelegate>();
if (handler != null)
{
return new OkResponse<DelegatingHandler>(handler(request, _ocelotLoggerFactory));
}
return new ErrorResponse<DelegatingHandler>(new UnableToFindQoSProviderError($"could not find qosProvider for {request.DownstreamScheme}{request.DownstreamAddresses}{request.DownstreamPathTemplate}"));
}
}
}

View File

@ -1,53 +0,0 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using Ocelot.Configuration;
using Ocelot.Responses;
namespace Ocelot.Requester.QoS
{
public class QosProviderHouse : IQosProviderHouse
{
private readonly ConcurrentDictionary<string, IQoSProvider> _qoSProviders;
private readonly IQoSProviderFactory _qoSProviderFactory;
public QosProviderHouse(IQoSProviderFactory qoSProviderFactory)
{
_qoSProviderFactory = qoSProviderFactory;
_qoSProviders = new ConcurrentDictionary<string, IQoSProvider>();
}
public Response<IQoSProvider> Get(DownstreamReRoute reRoute)
{
try
{
if (_qoSProviders.TryGetValue(reRoute.QosOptions.Key, out var qosProvider))
{
if (reRoute.QosOptions.UseQos && qosProvider.CircuitBreaker == null)
{
qosProvider = _qoSProviderFactory.Get(reRoute);
Add(reRoute.QosOptions.Key, qosProvider);
}
return new OkResponse<IQoSProvider>(_qoSProviders[reRoute.QosOptions.Key]);
}
qosProvider = _qoSProviderFactory.Get(reRoute);
Add(reRoute.QosOptions.Key, qosProvider);
return new OkResponse<IQoSProvider>(qosProvider);
}
catch (Exception ex)
{
return new ErrorResponse<IQoSProvider>(new List<Ocelot.Errors.Error>()
{
new UnableToFindQoSProviderError($"unabe to find qos provider for {reRoute.QosOptions.Key}, exception was {ex}")
});
}
}
private void Add(string key, IQoSProvider qosProvider)
{
_qoSProviders.AddOrUpdate(key, qosProvider, (x, y) => qosProvider);
}
}
}

View File

@ -1,11 +1,7 @@
using System; namespace Ocelot.Requester.QoS
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Ocelot.Errors;
namespace Ocelot.Requester.QoS
{ {
using Ocelot.Errors;
public class UnableToFindQoSProviderError : Error public class UnableToFindQoSProviderError : Error
{ {
public UnableToFindQoSProviderError(string message) public UnableToFindQoSProviderError(string message)

View File

@ -0,0 +1,8 @@
namespace Ocelot.Requester
{
using System.Net.Http;
using Configuration;
using Logging;
public delegate DelegatingHandler QosDelegatingHandlerDelegate(DownstreamReRoute reRoute, IOcelotLoggerFactory logger);
}

View File

@ -1,13 +0,0 @@
using System;
using Ocelot.Errors;
namespace Ocelot.Requester
{
public class RequestTimedOutError : Error
{
public RequestTimedOutError(Exception exception)
: base($"Timeout making http request, exception: {exception}", OcelotErrorCode.RequestTimedOutError)
{
}
}
}

View File

@ -1,272 +0,0 @@
namespace Ocelot.AcceptanceTests
{
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using TestStack.BDDfy;
using Xunit;
public class QoSTests : IDisposable
{
private readonly Steps _steps;
private int _requestCount;
private readonly ServiceHandler _serviceHandler;
public QoSTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
}
[Fact]
public void should_not_timeout()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51569,
}
},
DownstreamScheme = "http",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Post" },
QoSOptions = new FileQoSOptions
{
TimeoutValue = 1000,
}
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51569", 200, string.Empty, 10))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.And(x => _steps.GivenThePostHasContent("postContent"))
.When(x => _steps.WhenIPostUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.BDDfy();
}
[Fact]
public void should_timeout()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51579,
}
},
DownstreamScheme = "http",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Post" },
QoSOptions = new FileQoSOptions
{
TimeoutValue = 10,
}
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51579", 201, string.Empty, 1000))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.And(x => _steps.GivenThePostHasContent("postContent"))
.When(x => _steps.WhenIPostUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
.BDDfy();
}
[Fact]
public void should_open_circuit_breaker_then_close()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51892,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
QoSOptions = new FileQoSOptions
{
ExceptionsAllowedBeforeBreaking = 1,
TimeoutValue = 500,
DurationOfBreak = 1000
},
}
}
};
this.Given(x => x.GivenThereIsAPossiblyBrokenServiceRunningOn("http://localhost:51892", "Hello from Laura"))
.Given(x => _steps.GivenThereIsAConfiguration(configuration))
.Given(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.Given(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Given(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
.Given(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Given(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
.Given(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Given(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
.Given(x => x.GivenIWaitMilliseconds(3000))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void open_circuit_should_not_effect_different_reRoute()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51872,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
QoSOptions = new FileQoSOptions
{
ExceptionsAllowedBeforeBreaking = 1,
TimeoutValue = 500,
DurationOfBreak = 1000
}
},
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51880,
}
},
UpstreamPathTemplate = "/working",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAPossiblyBrokenServiceRunningOn("http://localhost:51872", "Hello from Laura"))
.And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51880/", 200, "Hello from Tom", 0))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.And(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.And(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
.And(x => _steps.WhenIGetUrlOnTheApiGateway("/working"))
.And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Tom"))
.And(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
.And(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
.And(x => x.GivenIWaitMilliseconds(3000))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
private void GivenIWaitMilliseconds(int ms)
{
Thread.Sleep(ms);
}
private void GivenThereIsAPossiblyBrokenServiceRunningOn(string url, string responseBody)
{
_serviceHandler.GivenThereIsAServiceRunningOn(url, async context =>
{
//circuit starts closed
if (_requestCount == 0)
{
_requestCount++;
context.Response.StatusCode = 200;
await context.Response.WriteAsync(responseBody);
return;
}
//request one times out and polly throws exception, circuit opens
if (_requestCount == 1)
{
_requestCount++;
await Task.Delay(1000);
context.Response.StatusCode = 200;
return;
}
//after break closes we return 200 OK
if (_requestCount == 2)
{
context.Response.StatusCode = 200;
await context.Response.WriteAsync(responseBody);
}
});
}
private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody, int timeout)
{
_serviceHandler.GivenThereIsAServiceRunningOn(url, async context =>
{
Thread.Sleep(timeout);
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
});
}
public void Dispose()
{
_serviceHandler?.Dispose();
_steps.Dispose();
}
}
}

View File

@ -831,7 +831,7 @@ namespace Ocelot.AcceptanceTests
} }
[Fact] [Fact]
public void should_fix_145() public void should_not_set_trailing_slash_on_url_template()
{ {
var configuration = new FileConfiguration var configuration = new FileConfiguration
{ {
@ -851,11 +851,6 @@ namespace Ocelot.AcceptanceTests
}, },
UpstreamPathTemplate = "/platform/{url}", UpstreamPathTemplate = "/platform/{url}",
UpstreamHttpMethod = new List<string> { "Get" }, UpstreamHttpMethod = new List<string> { "Get" },
QoSOptions = new FileQoSOptions {
ExceptionsAllowedBeforeBreaking = 3,
DurationOfBreak = 10,
TimeoutValue = 5000
}
} }
} }
}; };

View File

@ -36,7 +36,6 @@
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.1.1" /> <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.1.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.1.1" /> <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.1.1" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.1.1" /> <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.1.1" />
<PackageReference Include="Polly" Version="6.0.1" />
<PackageReference Include="StyleCop.Analyzers" Version="1.0.2"> <PackageReference Include="StyleCop.Analyzers" Version="1.0.2">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>

View File

@ -16,23 +16,28 @@ using Xunit;
namespace Ocelot.UnitTests.Requester namespace Ocelot.UnitTests.Requester
{ {
using Responder;
public class DelegatingHandlerHandlerProviderFactoryTests public class DelegatingHandlerHandlerProviderFactoryTests
{ {
private DelegatingHandlerHandlerFactory _factory; private DelegatingHandlerHandlerFactory _factory;
private readonly Mock<IOcelotLoggerFactory> _loggerFactory; private readonly Mock<IOcelotLoggerFactory> _loggerFactory;
private DownstreamReRoute _request; private DownstreamReRoute _request;
private Response<List<Func<DelegatingHandler>>> _result; private Response<List<Func<DelegatingHandler>>> _result;
private readonly Mock<IQosProviderHouse> _qosProviderHouse; private readonly Mock<IQoSFactory> _qosFactory;
private readonly Mock<ITracingHandlerFactory> _tracingFactory; private readonly Mock<ITracingHandlerFactory> _tracingFactory;
private IServiceProvider _serviceProvider; private IServiceProvider _serviceProvider;
private readonly IServiceCollection _services; private readonly IServiceCollection _services;
private readonly QosDelegatingHandlerDelegate _qosDelegate;
public DelegatingHandlerHandlerProviderFactoryTests() public DelegatingHandlerHandlerProviderFactoryTests()
{ {
_qosDelegate = (a, b) => new FakeQoSHandler();
_tracingFactory = new Mock<ITracingHandlerFactory>(); _tracingFactory = new Mock<ITracingHandlerFactory>();
_qosProviderHouse = new Mock<IQosProviderHouse>(); _qosFactory = new Mock<IQoSFactory>();
_loggerFactory = new Mock<IOcelotLoggerFactory>(); _loggerFactory = new Mock<IOcelotLoggerFactory>();
_services = new ServiceCollection(); _services = new ServiceCollection();
_services.AddSingleton(_qosDelegate);
} }
[Fact] [Fact]
@ -56,8 +61,8 @@ namespace Ocelot.UnitTests.Requester
.Build(); .Build();
this.Given(x => GivenTheFollowingRequest(reRoute)) this.Given(x => GivenTheFollowingRequest(reRoute))
.And(x => GivenTheQosFactoryReturns(new FakeQoSHandler()))
.And(x => GivenTheTracingFactoryReturns()) .And(x => GivenTheTracingFactoryReturns())
.And(x => GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(It.IsAny<PollyQoSProvider>())))
.And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers<FakeDelegatingHandlerThree, FakeDelegatingHandlerFour>()) .And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers<FakeDelegatingHandlerThree, FakeDelegatingHandlerFour>())
.And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>()) .And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
.When(x => WhenIGet()) .When(x => WhenIGet())
@ -67,7 +72,7 @@ namespace Ocelot.UnitTests.Requester
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandler>(2)) .And(x => ThenHandlerAtPositionIs<FakeDelegatingHandler>(2))
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandlerTwo>(3)) .And(x => ThenHandlerAtPositionIs<FakeDelegatingHandlerTwo>(3))
.And(x => ThenHandlerAtPositionIs<FakeTracingHandler>(4)) .And(x => ThenHandlerAtPositionIs<FakeTracingHandler>(4))
.And(x => ThenHandlerAtPositionIs<PollyCircuitBreakingDelegatingHandler>(5)) .And(x => ThenHandlerAtPositionIs<FakeQoSHandler>(5))
.BDDfy(); .BDDfy();
} }
@ -93,8 +98,8 @@ namespace Ocelot.UnitTests.Requester
.Build(); .Build();
this.Given(x => GivenTheFollowingRequest(reRoute)) this.Given(x => GivenTheFollowingRequest(reRoute))
.And(x => GivenTheQosFactoryReturns(new FakeQoSHandler()))
.And(x => GivenTheTracingFactoryReturns()) .And(x => GivenTheTracingFactoryReturns())
.And(x => GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(It.IsAny<PollyQoSProvider>())))
.And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers<FakeDelegatingHandlerFour, FakeDelegatingHandlerThree>()) .And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers<FakeDelegatingHandlerFour, FakeDelegatingHandlerThree>())
.And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>()) .And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
.When(x => WhenIGet()) .When(x => WhenIGet())
@ -104,7 +109,7 @@ namespace Ocelot.UnitTests.Requester
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandler>(2)) //second from config .And(x => ThenHandlerAtPositionIs<FakeDelegatingHandler>(2)) //second from config
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandlerFour>(3)) //third from config (global) .And(x => ThenHandlerAtPositionIs<FakeDelegatingHandlerFour>(3)) //third from config (global)
.And(x => ThenHandlerAtPositionIs<FakeTracingHandler>(4)) .And(x => ThenHandlerAtPositionIs<FakeTracingHandler>(4))
.And(x => ThenHandlerAtPositionIs<PollyCircuitBreakingDelegatingHandler>(5)) .And(x => ThenHandlerAtPositionIs<FakeQoSHandler>(5))
.BDDfy(); .BDDfy();
} }
@ -129,8 +134,8 @@ namespace Ocelot.UnitTests.Requester
.Build(); .Build();
this.Given(x => GivenTheFollowingRequest(reRoute)) this.Given(x => GivenTheFollowingRequest(reRoute))
.And(x => GivenTheQosFactoryReturns(new FakeQoSHandler()))
.And(x => GivenTheTracingFactoryReturns()) .And(x => GivenTheTracingFactoryReturns())
.And(x => GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(It.IsAny<PollyQoSProvider>())))
.And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers<FakeDelegatingHandlerThree, FakeDelegatingHandlerFour>()) .And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers<FakeDelegatingHandlerThree, FakeDelegatingHandlerFour>())
.And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>()) .And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
.When(x => WhenIGet()) .When(x => WhenIGet())
@ -140,7 +145,7 @@ namespace Ocelot.UnitTests.Requester
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandlerTwo>(2)) .And(x => ThenHandlerAtPositionIs<FakeDelegatingHandlerTwo>(2))
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandler>(3)) .And(x => ThenHandlerAtPositionIs<FakeDelegatingHandler>(3))
.And(x => ThenHandlerAtPositionIs<FakeTracingHandler>(4)) .And(x => ThenHandlerAtPositionIs<FakeTracingHandler>(4))
.And(x => ThenHandlerAtPositionIs<PollyCircuitBreakingDelegatingHandler>(5)) .And(x => ThenHandlerAtPositionIs<FakeQoSHandler>(5))
.BDDfy(); .BDDfy();
} }
@ -164,8 +169,8 @@ namespace Ocelot.UnitTests.Requester
.Build(); .Build();
this.Given(x => GivenTheFollowingRequest(reRoute)) this.Given(x => GivenTheFollowingRequest(reRoute))
.And(x => GivenTheQosFactoryReturns(new FakeQoSHandler()))
.And(x => GivenTheTracingFactoryReturns()) .And(x => GivenTheTracingFactoryReturns())
.And(x => GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(It.IsAny<PollyQoSProvider>())))
.And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers<FakeDelegatingHandlerThree, FakeDelegatingHandlerFour>()) .And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers<FakeDelegatingHandlerThree, FakeDelegatingHandlerFour>())
.And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>()) .And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
.When(x => WhenIGet()) .When(x => WhenIGet())
@ -174,7 +179,7 @@ namespace Ocelot.UnitTests.Requester
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandlerFour>(1)) .And(x => ThenHandlerAtPositionIs<FakeDelegatingHandlerFour>(1))
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandler>(2)) .And(x => ThenHandlerAtPositionIs<FakeDelegatingHandler>(2))
.And(x => ThenHandlerAtPositionIs<FakeTracingHandler>(3)) .And(x => ThenHandlerAtPositionIs<FakeTracingHandler>(3))
.And(x => ThenHandlerAtPositionIs<PollyCircuitBreakingDelegatingHandler>(4)) .And(x => ThenHandlerAtPositionIs<FakeQoSHandler>(4))
.BDDfy(); .BDDfy();
} }
@ -194,8 +199,8 @@ namespace Ocelot.UnitTests.Requester
.Build(); .Build();
this.Given(x => GivenTheFollowingRequest(reRoute)) this.Given(x => GivenTheFollowingRequest(reRoute))
.And(x => GivenTheQosFactoryReturns(new FakeQoSHandler()))
.And(x => GivenTheTracingFactoryReturns()) .And(x => GivenTheTracingFactoryReturns())
.And(x => GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(It.IsAny<PollyQoSProvider>())))
.And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>()) .And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
.And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>()) .And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
.When(x => WhenIGet()) .When(x => WhenIGet())
@ -203,7 +208,7 @@ namespace Ocelot.UnitTests.Requester
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandler>(0)) .And(x => ThenHandlerAtPositionIs<FakeDelegatingHandler>(0))
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandlerTwo>(1)) .And(x => ThenHandlerAtPositionIs<FakeDelegatingHandlerTwo>(1))
.And(x => ThenHandlerAtPositionIs<FakeTracingHandler>(2)) .And(x => ThenHandlerAtPositionIs<FakeTracingHandler>(2))
.And(x => ThenHandlerAtPositionIs<PollyCircuitBreakingDelegatingHandler>(3)) .And(x => ThenHandlerAtPositionIs<FakeQoSHandler>(3))
.BDDfy(); .BDDfy();
} }
@ -225,7 +230,6 @@ namespace Ocelot.UnitTests.Requester
.Build(); .Build();
this.Given(x => GivenTheFollowingRequest(reRoute)) this.Given(x => GivenTheFollowingRequest(reRoute))
.And(x => GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(It.IsAny<PollyQoSProvider>())))
.And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>()) .And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
.When(x => WhenIGet()) .When(x => WhenIGet())
.Then(x => ThenThereIsDelegatesInProvider(2)) .Then(x => ThenThereIsDelegatesInProvider(2))
@ -247,12 +251,12 @@ namespace Ocelot.UnitTests.Requester
.WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true)).WithLoadBalancerKey("").Build(); .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true)).WithLoadBalancerKey("").Build();
this.Given(x => GivenTheFollowingRequest(reRoute)) this.Given(x => GivenTheFollowingRequest(reRoute))
.And(x => GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(It.IsAny<PollyQoSProvider>()))) .And(x => GivenTheQosFactoryReturns(new FakeQoSHandler()))
.And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>()) .And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
.When(x => WhenIGet()) .When(x => WhenIGet())
.Then(x => ThenThereIsDelegatesInProvider(3)) .Then(x => ThenThereIsDelegatesInProvider(3))
.And(x => ThenTheDelegatesAreAddedCorrectly()) .And(x => ThenTheDelegatesAreAddedCorrectly())
.And(x => ThenItIsPolly(2)) .And(x => ThenItIsQosHandler(2))
.BDDfy(); .BDDfy();
} }
@ -287,11 +291,11 @@ namespace Ocelot.UnitTests.Requester
.WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true)).WithLoadBalancerKey("").Build(); .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true)).WithLoadBalancerKey("").Build();
this.Given(x => GivenTheFollowingRequest(reRoute)) this.Given(x => GivenTheFollowingRequest(reRoute))
.And(x => GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(It.IsAny<PollyQoSProvider>()))) .And(x => GivenTheQosFactoryReturns(new FakeQoSHandler()))
.And(x => GivenTheServiceProviderReturnsNothing()) .And(x => GivenTheServiceProviderReturnsNothing())
.When(x => WhenIGet()) .When(x => WhenIGet())
.Then(x => ThenThereIsDelegatesInProvider(1)) .Then(x => ThenThereIsDelegatesInProvider(1))
.And(x => ThenItIsPolly(0)) .And(x => ThenItIsQosHandler(0))
.BDDfy(); .BDDfy();
} }
@ -309,7 +313,7 @@ namespace Ocelot.UnitTests.Requester
.WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true)).WithLoadBalancerKey("").Build(); .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true)).WithLoadBalancerKey("").Build();
this.Given(x => GivenTheFollowingRequest(reRoute)) this.Given(x => GivenTheFollowingRequest(reRoute))
.And(x => GivenTheQosProviderHouseReturns(new ErrorResponse<IQoSProvider>(It.IsAny<Error>()))) .And(x => GivenTheQosFactoryReturnsError())
.And(x => GivenTheServiceProviderReturnsNothing()) .And(x => GivenTheServiceProviderReturnsNothing())
.When(x => WhenIGet()) .When(x => WhenIGet())
.Then(x => ThenAnErrorIsReturned()) .Then(x => ThenAnErrorIsReturned())
@ -378,18 +382,25 @@ namespace Ocelot.UnitTests.Requester
handlerTwo.Order.ShouldBe(2); handlerTwo.Order.ShouldBe(2);
} }
private void GivenTheQosProviderHouseReturns(Response<IQoSProvider> qosProvider) private void GivenTheQosFactoryReturns(DelegatingHandler handler)
{ {
_qosProviderHouse _qosFactory
.Setup(x => x.Get(It.IsAny<DownstreamReRoute>())) .Setup(x => x.Get(It.IsAny<DownstreamReRoute>()))
.Returns(qosProvider); .Returns(new OkResponse<DelegatingHandler>(handler));
} }
private void ThenItIsPolly(int i) private void GivenTheQosFactoryReturnsError()
{
_qosFactory
.Setup(x => x.Get(It.IsAny<DownstreamReRoute>()))
.Returns(new ErrorResponse<DelegatingHandler>(new AnyError()));
}
private void ThenItIsQosHandler(int i)
{ {
var delegates = _result.Data; var delegates = _result.Data;
var del = delegates[i].Invoke(); var del = delegates[i].Invoke();
del.ShouldBeOfType<PollyCircuitBreakingDelegatingHandler>(); del.ShouldBeOfType<FakeQoSHandler>();
} }
private void ThenThereIsDelegatesInProvider(int count) private void ThenThereIsDelegatesInProvider(int count)
@ -406,7 +417,7 @@ namespace Ocelot.UnitTests.Requester
private void WhenIGet() private void WhenIGet()
{ {
_serviceProvider = _services.BuildServiceProvider(); _serviceProvider = _services.BuildServiceProvider();
_factory = new DelegatingHandlerHandlerFactory(_loggerFactory.Object, _tracingFactory.Object, _qosProviderHouse.Object, _serviceProvider); _factory = new DelegatingHandlerHandlerFactory(_tracingFactory.Object, _qosFactory.Object, _serviceProvider);
_result = _factory.Get(_request); _result = _factory.Get(_request);
} }
@ -420,4 +431,8 @@ namespace Ocelot.UnitTests.Requester
internal class FakeTracingHandler : DelegatingHandler, ITracingHandler internal class FakeTracingHandler : DelegatingHandler, ITracingHandler
{ {
} }
internal class FakeQoSHandler : DelegatingHandler
{
}
} }

View File

@ -144,7 +144,7 @@ namespace Ocelot.UnitTests.Requester
private void ThenTheErrorIsTimeout() private void ThenTheErrorIsTimeout()
{ {
_response.Errors[0].ShouldBeOfType<RequestTimedOutError>(); _response.Errors[0].ShouldBeOfType<UnableToCompleteRequestError>();
} }
private void GivenTheHouseReturnsOkHandler() private void GivenTheHouseReturnsOkHandler()

View File

@ -1,15 +1,17 @@
using Moq; /*
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Logging;
using Ocelot.Requester.QoS;
using Shouldly;
using System.Collections.Generic;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Requester namespace Ocelot.UnitTests.Requester
{ {
using Microsoft.Extensions.DependencyInjection;
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Logging;
using Ocelot.Requester.QoS;
using Shouldly;
using System.Collections.Generic;
using TestStack.BDDfy;
using Xunit;
public class QoSProviderFactoryTests public class QoSProviderFactoryTests
{ {
private readonly IQoSProviderFactory _factory; private readonly IQoSProviderFactory _factory;
@ -22,10 +24,9 @@ namespace Ocelot.UnitTests.Requester
{ {
_logger = new Mock<IOcelotLogger>(); _logger = new Mock<IOcelotLogger>();
_loggerFactory = new Mock<IOcelotLoggerFactory>(); _loggerFactory = new Mock<IOcelotLoggerFactory>();
_loggerFactory var services = new ServiceCollection();
.Setup(x => x.CreateLogger<PollyQoSProvider>()) var provider = services.BuildServiceProvider();
.Returns(_logger.Object); _factory = new QoSProviderFactory(_loggerFactory.Object, provider);
_factory = new QoSProviderFactory(_loggerFactory.Object);
} }
[Fact] [Fact]
@ -46,7 +47,7 @@ namespace Ocelot.UnitTests.Requester
} }
[Fact] [Fact]
public void should_return_polly_qos_provider() public void should_return_delegate_provider()
{ {
var qosOptions = new QoSOptionsBuilder() var qosOptions = new QoSOptionsBuilder()
.WithTimeoutValue(100) .WithTimeoutValue(100)
@ -55,13 +56,13 @@ namespace Ocelot.UnitTests.Requester
.Build(); .Build();
var reRoute = new DownstreamReRouteBuilder() var reRoute = new DownstreamReRouteBuilder()
.WithUpstreamHttpMethod(new List<string> { "get" }) .WithUpstreamHttpMethod(new List<string> { "get" })
.WithQosOptions(qosOptions) .WithQosOptions(qosOptions)
.Build(); .Build();
this.Given(x => x.GivenAReRoute(reRoute)) this.Given(x => x.GivenAReRoute(reRoute))
.When(x => x.WhenIGetTheQoSProvider()) .When(x => x.WhenIGetTheQoSProvider())
.Then(x => x.ThenTheQoSProviderIsReturned<PollyQoSProvider>()) .Then(x => x.ThenTheQoSProviderIsReturned<FakeProvider>())
.BDDfy(); .BDDfy();
} }
@ -80,4 +81,13 @@ namespace Ocelot.UnitTests.Requester
_result.ShouldBeOfType<T>(); _result.ShouldBeOfType<T>();
} }
} }
internal class FakeProvider : IQoSProvider
{
public T CircuitBreaker<T>()
{
throw new System.NotImplementedException();
}
}
} }
*/

View File

@ -1,4 +1,5 @@
using Moq; /*
using Moq;
using Ocelot.Configuration; using Ocelot.Configuration;
using Ocelot.Configuration.Builder; using Ocelot.Configuration.Builder;
using Ocelot.Requester.QoS; using Ocelot.Requester.QoS;
@ -176,12 +177,19 @@ namespace Ocelot.UnitTests.Requester
class FakeQoSProvider : IQoSProvider class FakeQoSProvider : IQoSProvider
{ {
public CircuitBreaker CircuitBreaker { get; } T IQoSProvider.CircuitBreaker<T>()
{
throw new System.NotImplementedException();
}
} }
class FakePollyQoSProvider : IQoSProvider class FakePollyQoSProvider : IQoSProvider
{ {
public CircuitBreaker CircuitBreaker { get; } T IQoSProvider.CircuitBreaker<T>()
{
throw new System.NotImplementedException();
}
} }
} }
} }
*/