diff --git a/src/Ocelot/Configuration/QoSOptions.cs b/src/Ocelot/Configuration/QoSOptions.cs index 3b7733a3..b0e7df7a 100644 --- a/src/Ocelot/Configuration/QoSOptions.cs +++ b/src/Ocelot/Configuration/QoSOptions.cs @@ -1,32 +1,33 @@ -using Polly.Timeout; - -namespace Ocelot.Configuration -{ - public class QoSOptions - { - public QoSOptions( - int exceptionsAllowedBeforeBreaking, - int durationofBreak, - int timeoutValue, - string key, - TimeoutStrategy timeoutStrategy = TimeoutStrategy.Pessimistic) - { - ExceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking; - DurationOfBreak = durationofBreak; - TimeoutValue = timeoutValue; - TimeoutStrategy = timeoutStrategy; - Key = key; - } - - public int ExceptionsAllowedBeforeBreaking { get; } - - public int DurationOfBreak { get; } - - public int TimeoutValue { get; } - - public TimeoutStrategy TimeoutStrategy { get; } - - public bool UseQos => ExceptionsAllowedBeforeBreaking > 0 && TimeoutValue > 0; - public string Key { get; } - } -} +namespace Ocelot.Configuration +{ + public class QoSOptions + { + public QoSOptions( + int exceptionsAllowedBeforeBreaking, + int durationofBreak, + int timeoutValue, + string key, + //todo - this is never set in Ocelot so always Pessimistic...I guess it doesn't + //matter to much. + string timeoutStrategy = "Pessimistic") + { + ExceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking; + DurationOfBreak = durationofBreak; + TimeoutValue = timeoutValue; + TimeoutStrategy = timeoutStrategy; + Key = key; + } + + public int ExceptionsAllowedBeforeBreaking { get; } + + public int DurationOfBreak { get; } + + public int TimeoutValue { get; } + + public string TimeoutStrategy { get; } + + public bool UseQos => ExceptionsAllowedBeforeBreaking > 0 && TimeoutValue > 0; + + public string Key { get; } + } +} diff --git a/src/Ocelot/DependencyInjection/OcelotBuilder.cs b/src/Ocelot/DependencyInjection/OcelotBuilder.cs index 80c8ae29..c9b49039 100644 --- a/src/Ocelot/DependencyInjection/OcelotBuilder.cs +++ b/src/Ocelot/DependencyInjection/OcelotBuilder.cs @@ -28,17 +28,12 @@ namespace Ocelot.DependencyInjection using Ocelot.Requester.QoS; using Ocelot.Responder; using Ocelot.ServiceDiscovery; - using System; - using System.Collections.Generic; using System.Reflection; - using System.Security.Cryptography.X509Certificates; - using Microsoft.AspNetCore.Builder; using Ocelot.Configuration; using Microsoft.Extensions.DependencyInjection.Extensions; using System.Net.Http; using Ocelot.Infrastructure; using Ocelot.Middleware.Multiplexer; - using ServiceDiscovery.Providers; using Ocelot.Request.Creator; public class OcelotBuilder : IOcelotBuilder @@ -75,8 +70,6 @@ namespace Ocelot.DependencyInjection Services.TryAddSingleton(); Services.TryAddSingleton(); Services.TryAddSingleton(); - Services.TryAddSingleton(); - Services.TryAddSingleton(); Services.TryAddSingleton(); Services.TryAddSingleton(); Services.TryAddSingleton(); @@ -136,6 +129,7 @@ namespace Ocelot.DependencyInjection Services.TryAddSingleton(); Services.TryAddSingleton(); Services.TryAddSingleton(); + Services.TryAddSingleton(); } public IOcelotBuilder AddSingletonDefinedAggregator() diff --git a/src/Ocelot/Ocelot.csproj b/src/Ocelot/Ocelot.csproj index 910c4ce5..b25af9f7 100644 --- a/src/Ocelot/Ocelot.csproj +++ b/src/Ocelot/Ocelot.csproj @@ -45,6 +45,5 @@ all - diff --git a/src/Ocelot/Requester/DelegatingHandlerHandlerFactory.cs b/src/Ocelot/Requester/DelegatingHandlerHandlerFactory.cs index a4263ef1..89de2840 100644 --- a/src/Ocelot/Requester/DelegatingHandlerHandlerFactory.cs +++ b/src/Ocelot/Requester/DelegatingHandlerHandlerFactory.cs @@ -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 { + 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 { - private readonly ITracingHandlerFactory _factory; - private readonly IOcelotLoggerFactory _loggerFactory; - private readonly IQosProviderHouse _qosProviderHouse; + private readonly ITracingHandlerFactory _tracingFactory; + private readonly IQoSFactory _qoSFactory; private readonly IServiceProvider _serviceProvider; - public DelegatingHandlerHandlerFactory(IOcelotLoggerFactory loggerFactory, - ITracingHandlerFactory factory, - IQosProviderHouse qosProviderHouse, + public DelegatingHandlerHandlerFactory( + ITracingHandlerFactory tracingFactory, + IQoSFactory qoSFactory, IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; - _factory = factory; - _loggerFactory = loggerFactory; - _qosProviderHouse = qosProviderHouse; + _tracingFactory = tracingFactory; + _qoSFactory = qoSFactory; } public Response>> Get(DownstreamReRoute request) @@ -64,19 +61,21 @@ namespace Ocelot.Requester if (request.HttpHandlerOptions.UseTracing) { - handlers.Add(() => (DelegatingHandler)_factory.Get()); + handlers.Add(() => (DelegatingHandler)_tracingFactory.Get()); } 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>>(qosProvider.Errors); + handlers.Add(() => handler.Data); + } + else + { + return new ErrorResponse>>(handler?.Errors); } - - handlers.Add(() => new PollyCircuitBreakingDelegatingHandler(qosProvider.Data, _loggerFactory)); } return new OkResponse>>(handlers); diff --git a/src/Ocelot/Requester/HttpClientBuilder.cs b/src/Ocelot/Requester/HttpClientBuilder.cs index 748c60c4..ec44e375 100644 --- a/src/Ocelot/Requester/HttpClientBuilder.cs +++ b/src/Ocelot/Requester/HttpClientBuilder.cs @@ -132,7 +132,7 @@ namespace Ocelot.Requester { 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; } diff --git a/src/Ocelot/Requester/HttpClientHttpRequester.cs b/src/Ocelot/Requester/HttpClientHttpRequester.cs index c7914c94..ea557f66 100644 --- a/src/Ocelot/Requester/HttpClientHttpRequester.cs +++ b/src/Ocelot/Requester/HttpClientHttpRequester.cs @@ -4,8 +4,6 @@ using System.Threading.Tasks; using Ocelot.Logging; using Ocelot.Middleware; using Ocelot.Responses; -using Polly.CircuitBreaker; -using Polly.Timeout; namespace Ocelot.Requester { @@ -35,18 +33,6 @@ namespace Ocelot.Requester var response = await httpClient.SendAsync(context.DownstreamRequest.ToHttpRequestMessage()); return new OkResponse(response); } - catch (TimeoutRejectedException exception) - { - return new ErrorResponse(new RequestTimedOutError(exception)); - } - catch (TaskCanceledException exception) - { - return new ErrorResponse(new RequestTimedOutError(exception)); - } - catch (BrokenCircuitException exception) - { - return new ErrorResponse(new RequestTimedOutError(exception)); - } catch (Exception exception) { return new ErrorResponse(new UnableToCompleteRequestError(exception)); diff --git a/src/Ocelot/Requester/PollyCircuitBreakingDelegatingHandler.cs b/src/Ocelot/Requester/PollyCircuitBreakingDelegatingHandler.cs deleted file mode 100644 index 45b0ac12..00000000 --- a/src/Ocelot/Requester/PollyCircuitBreakingDelegatingHandler.cs +++ /dev/null @@ -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(); - } - - protected override async Task 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; - } - } - } -} diff --git a/src/Ocelot/Requester/QoS/CircuitBreaker.cs b/src/Ocelot/Requester/QoS/CircuitBreaker.cs deleted file mode 100644 index 91b8e430..00000000 --- a/src/Ocelot/Requester/QoS/CircuitBreaker.cs +++ /dev/null @@ -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; } - } -} \ No newline at end of file diff --git a/src/Ocelot/Requester/QoS/IQoSProvider.cs b/src/Ocelot/Requester/QoS/IQoSProvider.cs deleted file mode 100644 index 7382cb06..00000000 --- a/src/Ocelot/Requester/QoS/IQoSProvider.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ocelot.Requester.QoS -{ - public interface IQoSProvider - { - CircuitBreaker CircuitBreaker { get; } - } -} diff --git a/src/Ocelot/Requester/QoS/IQoSProviderFactory.cs b/src/Ocelot/Requester/QoS/IQoSProviderFactory.cs deleted file mode 100644 index 2152fb41..00000000 --- a/src/Ocelot/Requester/QoS/IQoSProviderFactory.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Ocelot.Configuration; -using Ocelot.LoadBalancer.LoadBalancers; - -namespace Ocelot.Requester.QoS -{ - public interface IQoSProviderFactory - { - IQoSProvider Get(DownstreamReRoute reRoute); - } -} diff --git a/src/Ocelot/Requester/QoS/IQosFactory.cs b/src/Ocelot/Requester/QoS/IQosFactory.cs new file mode 100644 index 00000000..fb795504 --- /dev/null +++ b/src/Ocelot/Requester/QoS/IQosFactory.cs @@ -0,0 +1,11 @@ +namespace Ocelot.Requester.QoS +{ + using System.Net.Http; + using Configuration; + using Responses; + + public interface IQoSFactory + { + Response Get(DownstreamReRoute request); + } +} diff --git a/src/Ocelot/Requester/QoS/IQosProviderHouse.cs b/src/Ocelot/Requester/QoS/IQosProviderHouse.cs deleted file mode 100644 index 29f1324a..00000000 --- a/src/Ocelot/Requester/QoS/IQosProviderHouse.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Ocelot.Configuration; -using Ocelot.Responses; - -namespace Ocelot.Requester.QoS -{ - public interface IQosProviderHouse - { - Response Get(DownstreamReRoute reRoute); - } -} \ No newline at end of file diff --git a/src/Ocelot/Requester/QoS/NoQoSProvider.cs b/src/Ocelot/Requester/QoS/NoQoSProvider.cs deleted file mode 100644 index 45ed2285..00000000 --- a/src/Ocelot/Requester/QoS/NoQoSProvider.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ocelot.Requester.QoS -{ - public class NoQoSProvider : IQoSProvider - { - public CircuitBreaker CircuitBreaker { get; } - } -} \ No newline at end of file diff --git a/src/Ocelot/Requester/QoS/PollyQoSProvider.cs b/src/Ocelot/Requester/QoS/PollyQoSProvider.cs deleted file mode 100644 index afbf9c3a..00000000 --- a/src/Ocelot/Requester/QoS/PollyQoSProvider.cs +++ /dev/null @@ -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(); - - _timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromMilliseconds(reRoute.QosOptions.TimeoutValue), reRoute.QosOptions.TimeoutStrategy); - - _circuitBreakerPolicy = Policy - .Handle() - .Or() - .Or() - .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; - } -} diff --git a/src/Ocelot/Requester/QoS/QoSProviderFactory.cs b/src/Ocelot/Requester/QoS/QoSProviderFactory.cs deleted file mode 100644 index 45fa78b3..00000000 --- a/src/Ocelot/Requester/QoS/QoSProviderFactory.cs +++ /dev/null @@ -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(); - } - } -} diff --git a/src/Ocelot/Requester/QoS/QosFactory.cs b/src/Ocelot/Requester/QoS/QosFactory.cs new file mode 100644 index 00000000..37211f4b --- /dev/null +++ b/src/Ocelot/Requester/QoS/QosFactory.cs @@ -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 Get(DownstreamReRoute request) + { + var handler = _serviceProvider.GetService(); + + if (handler != null) + { + return new OkResponse(handler(request, _ocelotLoggerFactory)); + } + + return new ErrorResponse(new UnableToFindQoSProviderError($"could not find qosProvider for {request.DownstreamScheme}{request.DownstreamAddresses}{request.DownstreamPathTemplate}")); + } + } +} diff --git a/src/Ocelot/Requester/QoS/QosProviderHouse.cs b/src/Ocelot/Requester/QoS/QosProviderHouse.cs deleted file mode 100644 index f0e44b39..00000000 --- a/src/Ocelot/Requester/QoS/QosProviderHouse.cs +++ /dev/null @@ -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 _qoSProviders; - private readonly IQoSProviderFactory _qoSProviderFactory; - - public QosProviderHouse(IQoSProviderFactory qoSProviderFactory) - { - _qoSProviderFactory = qoSProviderFactory; - _qoSProviders = new ConcurrentDictionary(); - } - - public Response 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(_qoSProviders[reRoute.QosOptions.Key]); - } - - qosProvider = _qoSProviderFactory.Get(reRoute); - Add(reRoute.QosOptions.Key, qosProvider); - return new OkResponse(qosProvider); - } - catch (Exception ex) - { - return new ErrorResponse(new List() - { - 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); - } - } -} diff --git a/src/Ocelot/Requester/QoS/UnableToFindQoSProviderError.cs b/src/Ocelot/Requester/QoS/UnableToFindQoSProviderError.cs index d54db554..e3c02b27 100644 --- a/src/Ocelot/Requester/QoS/UnableToFindQoSProviderError.cs +++ b/src/Ocelot/Requester/QoS/UnableToFindQoSProviderError.cs @@ -1,11 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Ocelot.Errors; - -namespace Ocelot.Requester.QoS +namespace Ocelot.Requester.QoS { + using Ocelot.Errors; + public class UnableToFindQoSProviderError : Error { public UnableToFindQoSProviderError(string message) diff --git a/src/Ocelot/Requester/QosDelegatingHandlerDelegate.cs b/src/Ocelot/Requester/QosDelegatingHandlerDelegate.cs new file mode 100644 index 00000000..a0c66955 --- /dev/null +++ b/src/Ocelot/Requester/QosDelegatingHandlerDelegate.cs @@ -0,0 +1,8 @@ +namespace Ocelot.Requester +{ + using System.Net.Http; + using Configuration; + using Logging; + + public delegate DelegatingHandler QosDelegatingHandlerDelegate(DownstreamReRoute reRoute, IOcelotLoggerFactory logger); +} diff --git a/src/Ocelot/Requester/RequestTimedOutError.cs b/src/Ocelot/Requester/RequestTimedOutError.cs deleted file mode 100644 index f99308b3..00000000 --- a/src/Ocelot/Requester/RequestTimedOutError.cs +++ /dev/null @@ -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) - { - } - } -} diff --git a/test/Ocelot.AcceptanceTests/QoSTests.cs b/test/Ocelot.AcceptanceTests/QoSTests.cs deleted file mode 100644 index e62de7b3..00000000 --- a/test/Ocelot.AcceptanceTests/QoSTests.cs +++ /dev/null @@ -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 - { - new FileReRoute - { - DownstreamPathTemplate = "/", - DownstreamHostAndPorts = new List - { - new FileHostAndPort - { - Host = "localhost", - Port = 51569, - } - }, - DownstreamScheme = "http", - UpstreamPathTemplate = "/", - UpstreamHttpMethod = new List { "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 - { - new FileReRoute - { - DownstreamPathTemplate = "/", - DownstreamHostAndPorts = new List - { - new FileHostAndPort - { - Host = "localhost", - Port = 51579, - } - }, - DownstreamScheme = "http", - UpstreamPathTemplate = "/", - UpstreamHttpMethod = new List { "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 - { - new FileReRoute - { - DownstreamPathTemplate = "/", - DownstreamScheme = "http", - DownstreamHostAndPorts = new List - { - new FileHostAndPort - { - Host = "localhost", - Port = 51892, - } - }, - UpstreamPathTemplate = "/", - UpstreamHttpMethod = new List { "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 - { - new FileReRoute - { - DownstreamPathTemplate = "/", - DownstreamScheme = "http", - DownstreamHostAndPorts = new List - { - new FileHostAndPort - { - Host = "localhost", - Port = 51872, - } - }, - UpstreamPathTemplate = "/", - UpstreamHttpMethod = new List { "Get" }, - QoSOptions = new FileQoSOptions - { - ExceptionsAllowedBeforeBreaking = 1, - TimeoutValue = 500, - DurationOfBreak = 1000 - } - }, - new FileReRoute - { - DownstreamPathTemplate = "/", - DownstreamScheme = "http", - DownstreamHostAndPorts = new List - { - new FileHostAndPort - { - Host = "localhost", - Port = 51880, - } - }, - UpstreamPathTemplate = "/working", - UpstreamHttpMethod = new List { "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(); - } - } -} diff --git a/test/Ocelot.AcceptanceTests/RoutingTests.cs b/test/Ocelot.AcceptanceTests/RoutingTests.cs index 340db66f..685c1e00 100644 --- a/test/Ocelot.AcceptanceTests/RoutingTests.cs +++ b/test/Ocelot.AcceptanceTests/RoutingTests.cs @@ -831,7 +831,7 @@ namespace Ocelot.AcceptanceTests } [Fact] - public void should_fix_145() + public void should_not_set_trailing_slash_on_url_template() { var configuration = new FileConfiguration { @@ -851,11 +851,6 @@ namespace Ocelot.AcceptanceTests }, UpstreamPathTemplate = "/platform/{url}", UpstreamHttpMethod = new List { "Get" }, - QoSOptions = new FileQoSOptions { - ExceptionsAllowedBeforeBreaking = 3, - DurationOfBreak = 10, - TimeoutValue = 5000 - } } } }; diff --git a/test/Ocelot.ManualTest/Ocelot.ManualTest.csproj b/test/Ocelot.ManualTest/Ocelot.ManualTest.csproj index 5c3c5cfe..2f81d2b9 100644 --- a/test/Ocelot.ManualTest/Ocelot.ManualTest.csproj +++ b/test/Ocelot.ManualTest/Ocelot.ManualTest.csproj @@ -36,9 +36,8 @@ - all - \ No newline at end of file + diff --git a/test/Ocelot.UnitTests/Requester/DelegatingHandlerHandlerProviderFactoryTests.cs b/test/Ocelot.UnitTests/Requester/DelegatingHandlerHandlerProviderFactoryTests.cs index 2882ed8b..679b051c 100644 --- a/test/Ocelot.UnitTests/Requester/DelegatingHandlerHandlerProviderFactoryTests.cs +++ b/test/Ocelot.UnitTests/Requester/DelegatingHandlerHandlerProviderFactoryTests.cs @@ -16,23 +16,28 @@ using Xunit; namespace Ocelot.UnitTests.Requester { + using Responder; + public class DelegatingHandlerHandlerProviderFactoryTests { private DelegatingHandlerHandlerFactory _factory; private readonly Mock _loggerFactory; private DownstreamReRoute _request; private Response>> _result; - private readonly Mock _qosProviderHouse; + private readonly Mock _qosFactory; private readonly Mock _tracingFactory; private IServiceProvider _serviceProvider; private readonly IServiceCollection _services; + private readonly QosDelegatingHandlerDelegate _qosDelegate; public DelegatingHandlerHandlerProviderFactoryTests() { + _qosDelegate = (a, b) => new FakeQoSHandler(); _tracingFactory = new Mock(); - _qosProviderHouse = new Mock(); + _qosFactory = new Mock(); _loggerFactory = new Mock(); _services = new ServiceCollection(); + _services.AddSingleton(_qosDelegate); } [Fact] @@ -56,8 +61,8 @@ namespace Ocelot.UnitTests.Requester .Build(); this.Given(x => GivenTheFollowingRequest(reRoute)) + .And(x => GivenTheQosFactoryReturns(new FakeQoSHandler())) .And(x => GivenTheTracingFactoryReturns()) - .And(x => GivenTheQosProviderHouseReturns(new OkResponse(It.IsAny()))) .And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers()) .And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers()) .When(x => WhenIGet()) @@ -67,7 +72,7 @@ namespace Ocelot.UnitTests.Requester .And(x => ThenHandlerAtPositionIs(2)) .And(x => ThenHandlerAtPositionIs(3)) .And(x => ThenHandlerAtPositionIs(4)) - .And(x => ThenHandlerAtPositionIs(5)) + .And(x => ThenHandlerAtPositionIs(5)) .BDDfy(); } @@ -93,8 +98,8 @@ namespace Ocelot.UnitTests.Requester .Build(); this.Given(x => GivenTheFollowingRequest(reRoute)) + .And(x => GivenTheQosFactoryReturns(new FakeQoSHandler())) .And(x => GivenTheTracingFactoryReturns()) - .And(x => GivenTheQosProviderHouseReturns(new OkResponse(It.IsAny()))) .And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers()) .And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers()) .When(x => WhenIGet()) @@ -104,7 +109,7 @@ namespace Ocelot.UnitTests.Requester .And(x => ThenHandlerAtPositionIs(2)) //second from config .And(x => ThenHandlerAtPositionIs(3)) //third from config (global) .And(x => ThenHandlerAtPositionIs(4)) - .And(x => ThenHandlerAtPositionIs(5)) + .And(x => ThenHandlerAtPositionIs(5)) .BDDfy(); } @@ -129,8 +134,8 @@ namespace Ocelot.UnitTests.Requester .Build(); this.Given(x => GivenTheFollowingRequest(reRoute)) + .And(x => GivenTheQosFactoryReturns(new FakeQoSHandler())) .And(x => GivenTheTracingFactoryReturns()) - .And(x => GivenTheQosProviderHouseReturns(new OkResponse(It.IsAny()))) .And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers()) .And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers()) .When(x => WhenIGet()) @@ -140,7 +145,7 @@ namespace Ocelot.UnitTests.Requester .And(x => ThenHandlerAtPositionIs(2)) .And(x => ThenHandlerAtPositionIs(3)) .And(x => ThenHandlerAtPositionIs(4)) - .And(x => ThenHandlerAtPositionIs(5)) + .And(x => ThenHandlerAtPositionIs(5)) .BDDfy(); } @@ -164,8 +169,8 @@ namespace Ocelot.UnitTests.Requester .Build(); this.Given(x => GivenTheFollowingRequest(reRoute)) + .And(x => GivenTheQosFactoryReturns(new FakeQoSHandler())) .And(x => GivenTheTracingFactoryReturns()) - .And(x => GivenTheQosProviderHouseReturns(new OkResponse(It.IsAny()))) .And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers()) .And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers()) .When(x => WhenIGet()) @@ -174,7 +179,7 @@ namespace Ocelot.UnitTests.Requester .And(x => ThenHandlerAtPositionIs(1)) .And(x => ThenHandlerAtPositionIs(2)) .And(x => ThenHandlerAtPositionIs(3)) - .And(x => ThenHandlerAtPositionIs(4)) + .And(x => ThenHandlerAtPositionIs(4)) .BDDfy(); } @@ -194,8 +199,8 @@ namespace Ocelot.UnitTests.Requester .Build(); this.Given(x => GivenTheFollowingRequest(reRoute)) + .And(x => GivenTheQosFactoryReturns(new FakeQoSHandler())) .And(x => GivenTheTracingFactoryReturns()) - .And(x => GivenTheQosProviderHouseReturns(new OkResponse(It.IsAny()))) .And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers()) .And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers()) .When(x => WhenIGet()) @@ -203,7 +208,7 @@ namespace Ocelot.UnitTests.Requester .And(x => ThenHandlerAtPositionIs(0)) .And(x => ThenHandlerAtPositionIs(1)) .And(x => ThenHandlerAtPositionIs(2)) - .And(x => ThenHandlerAtPositionIs(3)) + .And(x => ThenHandlerAtPositionIs(3)) .BDDfy(); } @@ -225,7 +230,6 @@ namespace Ocelot.UnitTests.Requester .Build(); this.Given(x => GivenTheFollowingRequest(reRoute)) - .And(x => GivenTheQosProviderHouseReturns(new OkResponse(It.IsAny()))) .And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers()) .When(x => WhenIGet()) .Then(x => ThenThereIsDelegatesInProvider(2)) @@ -247,12 +251,12 @@ namespace Ocelot.UnitTests.Requester .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true)).WithLoadBalancerKey("").Build(); this.Given(x => GivenTheFollowingRequest(reRoute)) - .And(x => GivenTheQosProviderHouseReturns(new OkResponse(It.IsAny()))) + .And(x => GivenTheQosFactoryReturns(new FakeQoSHandler())) .And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers()) .When(x => WhenIGet()) .Then(x => ThenThereIsDelegatesInProvider(3)) .And(x => ThenTheDelegatesAreAddedCorrectly()) - .And(x => ThenItIsPolly(2)) + .And(x => ThenItIsQosHandler(2)) .BDDfy(); } @@ -287,11 +291,11 @@ namespace Ocelot.UnitTests.Requester .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true)).WithLoadBalancerKey("").Build(); this.Given(x => GivenTheFollowingRequest(reRoute)) - .And(x => GivenTheQosProviderHouseReturns(new OkResponse(It.IsAny()))) + .And(x => GivenTheQosFactoryReturns(new FakeQoSHandler())) .And(x => GivenTheServiceProviderReturnsNothing()) .When(x => WhenIGet()) .Then(x => ThenThereIsDelegatesInProvider(1)) - .And(x => ThenItIsPolly(0)) + .And(x => ThenItIsQosHandler(0)) .BDDfy(); } @@ -309,7 +313,7 @@ namespace Ocelot.UnitTests.Requester .WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true)).WithLoadBalancerKey("").Build(); this.Given(x => GivenTheFollowingRequest(reRoute)) - .And(x => GivenTheQosProviderHouseReturns(new ErrorResponse(It.IsAny()))) + .And(x => GivenTheQosFactoryReturnsError()) .And(x => GivenTheServiceProviderReturnsNothing()) .When(x => WhenIGet()) .Then(x => ThenAnErrorIsReturned()) @@ -378,18 +382,25 @@ namespace Ocelot.UnitTests.Requester handlerTwo.Order.ShouldBe(2); } - private void GivenTheQosProviderHouseReturns(Response qosProvider) + private void GivenTheQosFactoryReturns(DelegatingHandler handler) { - _qosProviderHouse + _qosFactory .Setup(x => x.Get(It.IsAny())) - .Returns(qosProvider); + .Returns(new OkResponse(handler)); } - private void ThenItIsPolly(int i) + private void GivenTheQosFactoryReturnsError() + { + _qosFactory + .Setup(x => x.Get(It.IsAny())) + .Returns(new ErrorResponse(new AnyError())); + } + + private void ThenItIsQosHandler(int i) { var delegates = _result.Data; var del = delegates[i].Invoke(); - del.ShouldBeOfType(); + del.ShouldBeOfType(); } private void ThenThereIsDelegatesInProvider(int count) @@ -406,7 +417,7 @@ namespace Ocelot.UnitTests.Requester private void WhenIGet() { _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); } @@ -420,4 +431,8 @@ namespace Ocelot.UnitTests.Requester internal class FakeTracingHandler : DelegatingHandler, ITracingHandler { } + + internal class FakeQoSHandler : DelegatingHandler + { + } } diff --git a/test/Ocelot.UnitTests/Requester/HttpClientHttpRequesterTest.cs b/test/Ocelot.UnitTests/Requester/HttpClientHttpRequesterTest.cs index ae9a25af..6b961a16 100644 --- a/test/Ocelot.UnitTests/Requester/HttpClientHttpRequesterTest.cs +++ b/test/Ocelot.UnitTests/Requester/HttpClientHttpRequesterTest.cs @@ -144,7 +144,7 @@ namespace Ocelot.UnitTests.Requester private void ThenTheErrorIsTimeout() { - _response.Errors[0].ShouldBeOfType(); + _response.Errors[0].ShouldBeOfType(); } private void GivenTheHouseReturnsOkHandler() diff --git a/test/Ocelot.UnitTests/Requester/QoSProviderFactoryTests.cs b/test/Ocelot.UnitTests/Requester/QoSProviderFactoryTests.cs index f4292656..4310788d 100644 --- a/test/Ocelot.UnitTests/Requester/QoSProviderFactoryTests.cs +++ b/test/Ocelot.UnitTests/Requester/QoSProviderFactoryTests.cs @@ -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 { + 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 { private readonly IQoSProviderFactory _factory; @@ -22,10 +24,9 @@ namespace Ocelot.UnitTests.Requester { _logger = new Mock(); _loggerFactory = new Mock(); - _loggerFactory - .Setup(x => x.CreateLogger()) - .Returns(_logger.Object); - _factory = new QoSProviderFactory(_loggerFactory.Object); + var services = new ServiceCollection(); + var provider = services.BuildServiceProvider(); + _factory = new QoSProviderFactory(_loggerFactory.Object, provider); } [Fact] @@ -46,7 +47,7 @@ namespace Ocelot.UnitTests.Requester } [Fact] - public void should_return_polly_qos_provider() + public void should_return_delegate_provider() { var qosOptions = new QoSOptionsBuilder() .WithTimeoutValue(100) @@ -55,13 +56,13 @@ namespace Ocelot.UnitTests.Requester .Build(); var reRoute = new DownstreamReRouteBuilder() - .WithUpstreamHttpMethod(new List { "get" }) - .WithQosOptions(qosOptions) - .Build(); + .WithUpstreamHttpMethod(new List { "get" }) + .WithQosOptions(qosOptions) + .Build(); this.Given(x => x.GivenAReRoute(reRoute)) .When(x => x.WhenIGetTheQoSProvider()) - .Then(x => x.ThenTheQoSProviderIsReturned()) + .Then(x => x.ThenTheQoSProviderIsReturned()) .BDDfy(); } @@ -80,4 +81,13 @@ namespace Ocelot.UnitTests.Requester _result.ShouldBeOfType(); } } + + internal class FakeProvider : IQoSProvider + { + public T CircuitBreaker() + { + throw new System.NotImplementedException(); + } + } } +*/ diff --git a/test/Ocelot.UnitTests/Requester/QosProviderHouseTests.cs b/test/Ocelot.UnitTests/Requester/QosProviderHouseTests.cs index a2db0198..f5c3682b 100644 --- a/test/Ocelot.UnitTests/Requester/QosProviderHouseTests.cs +++ b/test/Ocelot.UnitTests/Requester/QosProviderHouseTests.cs @@ -1,4 +1,5 @@ -using Moq; +/* +using Moq; using Ocelot.Configuration; using Ocelot.Configuration.Builder; using Ocelot.Requester.QoS; @@ -25,13 +26,13 @@ namespace Ocelot.UnitTests.Requester [Fact] public void should_store_qos_provider_on_first_request() - { - var qosOptions = new QoSOptionsBuilder() - .WithKey("test") - .Build(); + { + var qosOptions = new QoSOptionsBuilder() + .WithKey("test") + .Build(); - var reRoute = new DownstreamReRouteBuilder() - .WithQosOptions(qosOptions) + var reRoute = new DownstreamReRouteBuilder() + .WithQosOptions(qosOptions) .Build(); this.Given(x => x.GivenThereIsAQoSProvider(reRoute, new FakeQoSProvider())) @@ -47,7 +48,7 @@ namespace Ocelot.UnitTests.Requester .Build(); var reRoute = new DownstreamReRouteBuilder() - .WithQosOptions(qosOptions) + .WithQosOptions(qosOptions) .Build(); this.Given(x => x.GivenThereIsAQoSProvider(reRoute, new FakeQoSProvider())) @@ -68,8 +69,8 @@ namespace Ocelot.UnitTests.Requester .Build(); var reRoute = new DownstreamReRouteBuilder() - .WithQosOptions(qosOptions) - .Build(); + .WithQosOptions(qosOptions) + .Build(); var reRouteTwo = new DownstreamReRouteBuilder() .WithQosOptions(qosOptionsTwo) @@ -88,10 +89,10 @@ namespace Ocelot.UnitTests.Requester public void should_return_error_if_no_qos_provider_with_key() { var qosOptions = new QoSOptionsBuilder() - .Build(); + .Build(); - var reRoute = new DownstreamReRouteBuilder() - .WithQosOptions(qosOptions) + var reRoute = new DownstreamReRouteBuilder() + .WithQosOptions(qosOptions) .Build(); this.When(x => x.WhenWeGetTheQoSProvider(reRoute)) @@ -109,16 +110,16 @@ namespace Ocelot.UnitTests.Requester .WithExceptionsAllowedBeforeBreaking(1) .Build(); - var dontUseQoSOptions = new QoSOptionsBuilder() + var dontUseQoSOptions = new QoSOptionsBuilder() .WithKey("test") - .Build(); - + .Build(); + var reRoute = new DownstreamReRouteBuilder() .WithQosOptions(dontUseQoSOptions) .Build(); - var reRouteTwo = new DownstreamReRouteBuilder() - .WithQosOptions(useQoSOptions) + var reRouteTwo = new DownstreamReRouteBuilder() + .WithQosOptions(useQoSOptions) .Build(); this.Given(x => x.GivenThereIsAQoSProvider(reRoute, new FakeQoSProvider())) @@ -176,12 +177,19 @@ namespace Ocelot.UnitTests.Requester class FakeQoSProvider : IQoSProvider { - public CircuitBreaker CircuitBreaker { get; } + T IQoSProvider.CircuitBreaker() + { + throw new System.NotImplementedException(); + } } class FakePollyQoSProvider : IQoSProvider { - public CircuitBreaker CircuitBreaker { get; } + T IQoSProvider.CircuitBreaker() + { + throw new System.NotImplementedException(); + } } } } +*/