diff --git a/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs b/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs index 1e06a440..effb9cb8 100644 --- a/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs +++ b/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs @@ -32,6 +32,9 @@ namespace Ocelot.Configuration.Builder private string _downstreamScheme; private string _downstreamHost; private int _dsPort; + private int _exceptionsAllowedBeforeBreaking; + private int _durationOfBreak; + private int _timeoutValue; public ReRouteBuilder() { @@ -192,6 +195,24 @@ namespace Ocelot.Configuration.Builder return this; } + public ReRouteBuilder WithExceptionsAllowedBeforeBreaking(int exceptionsAllowedBeforeBreaking) + { + _exceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking; + return this; + } + + public ReRouteBuilder WithDurationOfBreak(int durationOfBreak) + { + _durationOfBreak = durationOfBreak; + return this; + } + + public ReRouteBuilder WithTimeoutValue(int timeoutValue) + { + _timeoutValue = timeoutValue; + return this; + } + public ReRoute Build() { Func downstreamHostFunc = () => new HostAndPort(_downstreamHost, _dsPort); @@ -200,7 +221,8 @@ namespace Ocelot.Configuration.Builder _isAuthenticated, new AuthenticationOptions(_authenticationProvider, _authenticationProviderUrl, _scopeName, _requireHttps, _additionalScopes, _scopeSecret), _configHeaderExtractorProperties, _claimToClaims, _routeClaimRequirement, _isAuthorised, _claimToQueries, _requestIdHeaderKey, _isCached, _fileCacheOptions, _serviceName, - _useServiceDiscovery, _serviceDiscoveryAddress, _serviceDiscoveryProvider, downstreamHostFunc, _downstreamScheme); + _useServiceDiscovery, _serviceDiscoveryAddress, _serviceDiscoveryProvider, downstreamHostFunc, _downstreamScheme, + _exceptionsAllowedBeforeBreaking,_durationOfBreak, _timeoutValue); } } } diff --git a/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs index 8884f0d9..e22ecd0b 100644 --- a/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs +++ b/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs @@ -96,7 +96,6 @@ namespace Ocelot.Configuration.Creator && !string.IsNullOrEmpty(globalConfiguration?.ServiceDiscoveryProvider?.Address) && !string.IsNullOrEmpty(globalConfiguration?.ServiceDiscoveryProvider?.Provider); - Func downstreamHostAndPortFunc = () => new HostAndPort(reRoute.DownstreamHost.Trim('/'), reRoute.DownstreamPort); if (isAuthenticated) @@ -116,7 +115,8 @@ namespace Ocelot.Configuration.Creator reRoute.RouteClaimsRequirement, isAuthorised, claimsToQueries, requestIdKey, isCached, new CacheOptions(reRoute.FileCacheOptions.TtlSeconds), reRoute.ServiceName, useServiceDiscovery, globalConfiguration?.ServiceDiscoveryProvider?.Provider, - globalConfiguration?.ServiceDiscoveryProvider?.Address, downstreamHostAndPortFunc, reRoute.DownstreamScheme); + globalConfiguration?.ServiceDiscoveryProvider?.Address, downstreamHostAndPortFunc, reRoute.DownstreamScheme, + reRoute.ExceptionsAllowedBeforeBreaking, reRoute.DurationOfBreak, reRoute.TimeoutValue); } return new ReRoute(new DownstreamPathTemplate(reRoute.DownstreamPathTemplate), reRoute.UpstreamTemplate, @@ -125,7 +125,8 @@ namespace Ocelot.Configuration.Creator reRoute.RouteClaimsRequirement, isAuthorised, new List(), requestIdKey, isCached, new CacheOptions(reRoute.FileCacheOptions.TtlSeconds), reRoute.ServiceName, useServiceDiscovery, globalConfiguration?.ServiceDiscoveryProvider?.Provider, - globalConfiguration?.ServiceDiscoveryProvider?.Address, downstreamHostAndPortFunc, reRoute.DownstreamScheme); + globalConfiguration?.ServiceDiscoveryProvider?.Address, downstreamHostAndPortFunc, reRoute.DownstreamScheme, + reRoute.ExceptionsAllowedBeforeBreaking, reRoute.DurationOfBreak, reRoute.TimeoutValue); } private string BuildUpstreamTemplate(FileReRoute reRoute) diff --git a/src/Ocelot/Configuration/File/FileReRoute.cs b/src/Ocelot/Configuration/File/FileReRoute.cs index a653224a..314f13bf 100644 --- a/src/Ocelot/Configuration/File/FileReRoute.cs +++ b/src/Ocelot/Configuration/File/FileReRoute.cs @@ -29,5 +29,8 @@ namespace Ocelot.Configuration.File public string DownstreamScheme {get;set;} public string DownstreamHost {get;set;} public int DownstreamPort { get; set; } + public int ExceptionsAllowedBeforeBreaking { get; set; } + public int DurationOfBreak { get; set; } + public int TimeoutValue { get; set; } } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/ReRoute.cs b/src/Ocelot/Configuration/ReRoute.cs index 960374cc..f6e188b7 100644 --- a/src/Ocelot/Configuration/ReRoute.cs +++ b/src/Ocelot/Configuration/ReRoute.cs @@ -10,7 +10,8 @@ namespace Ocelot.Configuration bool isAuthenticated, AuthenticationOptions authenticationOptions, List configurationHeaderExtractorProperties, List claimsToClaims, Dictionary routeClaimsRequirement, bool isAuthorised, List claimsToQueries, string requestIdKey, bool isCached, CacheOptions fileCacheOptions, string serviceName, bool useServiceDiscovery, - string serviceDiscoveryProvider, string serviceDiscoveryAddress, Func downstreamHostAndPort, string downstreamScheme) + string serviceDiscoveryProvider, string serviceDiscoveryAddress, Func downstreamHostAndPort, string downstreamScheme, + int exceptionsAllowedBeforeBreaking =3, int durationofBreak =8, int timeoutValue = 5000) { DownstreamPathTemplate = downstreamPathTemplate; UpstreamTemplate = upstreamTemplate; @@ -35,6 +36,9 @@ namespace Ocelot.Configuration ServiceDiscoveryAddress = serviceDiscoveryAddress; DownstreamHostAndPort = downstreamHostAndPort; DownstreamScheme = downstreamScheme; + ExceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking; + DurationOfBreak = durationofBreak; + TimeoutValue = timeoutValue; } public DownstreamPathTemplate DownstreamPathTemplate { get; private set; } @@ -57,5 +61,8 @@ namespace Ocelot.Configuration public string ServiceDiscoveryAddress { get; private set;} public Func DownstreamHostAndPort {get;private set;} public string DownstreamScheme {get;private set;} + public int ExceptionsAllowedBeforeBreaking { get; private set; } + public int DurationOfBreak { get; private set; } + public int TimeoutValue { get; private set; } } } \ No newline at end of file diff --git a/src/Ocelot/Request/Builder/HttpRequestCreator.cs b/src/Ocelot/Request/Builder/HttpRequestCreator.cs index 91234331..27ba4c07 100644 --- a/src/Ocelot/Request/Builder/HttpRequestCreator.cs +++ b/src/Ocelot/Request/Builder/HttpRequestCreator.cs @@ -15,7 +15,8 @@ namespace Ocelot.Request.Builder IRequestCookieCollection cookies, QueryString queryString, string contentType, - RequestId.RequestId requestId) + RequestId.RequestId requestId, + Values.QoS qos) { var request = await new RequestBuilder() .WithHttpMethod(httpMethod) @@ -26,6 +27,7 @@ namespace Ocelot.Request.Builder .WithHeaders(headers) .WithRequestId(requestId) .WithCookies(cookies) + .WithQos(qos) .Build(); return new OkResponse(request); diff --git a/src/Ocelot/Request/Builder/IRequestCreator.cs b/src/Ocelot/Request/Builder/IRequestCreator.cs index 7641d848..858636b5 100644 --- a/src/Ocelot/Request/Builder/IRequestCreator.cs +++ b/src/Ocelot/Request/Builder/IRequestCreator.cs @@ -14,6 +14,7 @@ namespace Ocelot.Request.Builder IRequestCookieCollection cookies, QueryString queryString, string contentType, - RequestId.RequestId requestId); + RequestId.RequestId requestId, + Values.QoS qos); } } diff --git a/src/Ocelot/Request/Builder/RequestBuilder.cs b/src/Ocelot/Request/Builder/RequestBuilder.cs index c9463993..d7f35ef7 100644 --- a/src/Ocelot/Request/Builder/RequestBuilder.cs +++ b/src/Ocelot/Request/Builder/RequestBuilder.cs @@ -22,6 +22,7 @@ namespace Ocelot.Request.Builder private RequestId.RequestId _requestId; private IRequestCookieCollection _cookies; private readonly string[] _unsupportedHeaders = {"host"}; + private Values.QoS _qos; public RequestBuilder WithHttpMethod(string httpMethod) { @@ -71,6 +72,12 @@ namespace Ocelot.Request.Builder return this; } + public RequestBuilder WithQos(Values.QoS qos) + { + _qos = qos; + return this; + } + public async Task Build() { var uri = CreateUri(); @@ -90,7 +97,7 @@ namespace Ocelot.Request.Builder var cookieContainer = CreateCookieContainer(uri); - return new Request(httpRequestMessage, cookieContainer); + return new Request(httpRequestMessage, cookieContainer, _qos); } private Uri CreateUri() diff --git a/src/Ocelot/Request/Middleware/HttpRequestBuilderMiddleware.cs b/src/Ocelot/Request/Middleware/HttpRequestBuilderMiddleware.cs index a2c5194b..a875ea8c 100644 --- a/src/Ocelot/Request/Middleware/HttpRequestBuilderMiddleware.cs +++ b/src/Ocelot/Request/Middleware/HttpRequestBuilderMiddleware.cs @@ -32,7 +32,8 @@ namespace Ocelot.Request.Middleware var buildResult = await _requestCreator .Build(context.Request.Method, DownstreamUrl, context.Request.Body, context.Request.Headers, context.Request.Cookies, context.Request.QueryString, - context.Request.ContentType, new RequestId.RequestId(DownstreamRoute?.ReRoute?.RequestIdKey, context.TraceIdentifier)); + context.Request.ContentType, new RequestId.RequestId(DownstreamRoute?.ReRoute?.RequestIdKey, context.TraceIdentifier), + new Values.QoS(DownstreamRoute.ReRoute.ExceptionsAllowedBeforeBreaking, DownstreamRoute.ReRoute.DurationOfBreak, DownstreamRoute.ReRoute.TimeoutValue)); if (buildResult.IsError) { diff --git a/src/Ocelot/Request/Request.cs b/src/Ocelot/Request/Request.cs index d43071e1..60e23b1e 100644 --- a/src/Ocelot/Request/Request.cs +++ b/src/Ocelot/Request/Request.cs @@ -1,17 +1,20 @@ -using System.Net; +using Ocelot.Values; +using System.Net; using System.Net.Http; namespace Ocelot.Request { public class Request { - public Request(HttpRequestMessage httpRequestMessage, CookieContainer cookieContainer) + public Request(HttpRequestMessage httpRequestMessage, CookieContainer cookieContainer, QoS qos) { HttpRequestMessage = httpRequestMessage; CookieContainer = cookieContainer; + Qos = qos; } public HttpRequestMessage HttpRequestMessage { get; private set; } public CookieContainer CookieContainer { get; private set; } + public QoS Qos { get; private set; } } } diff --git a/src/Ocelot/Requester/CircuitBreakingDelegatingHandler.cs b/src/Ocelot/Requester/CircuitBreakingDelegatingHandler.cs new file mode 100644 index 00000000..4adc0eeb --- /dev/null +++ b/src/Ocelot/Requester/CircuitBreakingDelegatingHandler.cs @@ -0,0 +1,74 @@ +using Ocelot.Logging; +using Polly; +using Polly.CircuitBreaker; +using Polly.Timeout; +using System; +using System.Net; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; + +namespace Ocelot.Requester +{ + public class CircuitBreakingDelegatingHandler : DelegatingHandler + { + private readonly IOcelotLogger _logger; + private readonly int _exceptionsAllowedBeforeBreaking; + private readonly TimeSpan _durationOfBreak; + private readonly Policy _circuitBreakerPolicy; + private readonly TimeoutPolicy _timeoutPolicy; + + public CircuitBreakingDelegatingHandler(int exceptionsAllowedBeforeBreaking, TimeSpan durationOfBreak,TimeSpan timeoutValue + ,TimeoutStrategy timeoutStrategy, IOcelotLogger logger, HttpMessageHandler innerHandler) + : base(innerHandler) + { + this._exceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking; + this._durationOfBreak = durationOfBreak; + + _circuitBreakerPolicy = Policy + .Handle() + .Or() + .Or() + .CircuitBreakerAsync( + exceptionsAllowedBeforeBreaking: exceptionsAllowedBeforeBreaking, + durationOfBreak: 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.") + ); + _timeoutPolicy = Policy.TimeoutAsync(timeoutValue, timeoutStrategy); + _logger = logger; + } + + protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + Task responseTask = null; + + try + { + responseTask = Policy.WrapAsync(_circuitBreakerPolicy, _timeoutPolicy).ExecuteAsync(() => + { + return base.SendAsync(request,cancellationToken); + }); + return responseTask; + } + catch (BrokenCircuitException ex) + { + _logger.LogError($"Reached to allowed number of exceptions. Circuit is open. AllowedExceptionCount: {_exceptionsAllowedBeforeBreaking}, DurationOfBreak: {_durationOfBreak}",ex); + throw; + } + catch (HttpRequestException) + { + return responseTask; + } + } + + private static bool IsTransientFailure(HttpResponseMessage result) + { + return result.StatusCode >= HttpStatusCode.InternalServerError; + } + } +} diff --git a/src/Ocelot/Requester/HttpClientBuilder.cs b/src/Ocelot/Requester/HttpClientBuilder.cs new file mode 100644 index 00000000..ebf19d24 --- /dev/null +++ b/src/Ocelot/Requester/HttpClientBuilder.cs @@ -0,0 +1,41 @@ +using Ocelot.Logging; +using Ocelot.Values; +using Polly.Timeout; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; + +namespace Ocelot.Requester +{ + internal class HttpClientBuilder + { + private readonly Dictionary> handlers = new Dictionary>(); + + public HttpClientBuilder WithCircuitBreaker(QoS qos, IOcelotLogger logger, HttpMessageHandler innerHandler) + { + handlers.Add(5000, () => new CircuitBreakingDelegatingHandler(qos.ExceptionsAllowedBeforeBreaking, qos.DurationOfBreak, qos.TimeoutValue, qos.TimeoutStrategy, logger, innerHandler)); + return this; + } + + internal HttpClient Build() + { + return handlers.Any() ? new HttpClient(CreateHttpMessageHandler()) : new HttpClient(); + } + + private HttpMessageHandler CreateHttpMessageHandler() + { + HttpMessageHandler httpMessageHandler = new HttpClientHandler(); + + handlers.OrderByDescending(handler => handler.Key).Select(handler => handler.Value).Reverse().ToList().ForEach(handler => + { + var delegatingHandler = handler(); + delegatingHandler.InnerHandler = httpMessageHandler; + httpMessageHandler = delegatingHandler; + }); + + return httpMessageHandler; + } + } +} diff --git a/src/Ocelot/Requester/HttpClientHttpRequester.cs b/src/Ocelot/Requester/HttpClientHttpRequester.cs index 8056adeb..35c405d1 100644 --- a/src/Ocelot/Requester/HttpClientHttpRequester.cs +++ b/src/Ocelot/Requester/HttpClientHttpRequester.cs @@ -4,9 +4,6 @@ using System.Net.Http; using System.Threading.Tasks; using Ocelot.Errors; using Ocelot.Responses; -using Polly; -using Polly.Timeout; -using Polly.CircuitBreaker; using Ocelot.Logging; namespace Ocelot.Requester @@ -14,7 +11,7 @@ namespace Ocelot.Requester public class HttpClientHttpRequester : IHttpRequester { private readonly IOcelotLogger _logger; - + public HttpClientHttpRequester(IOcelotLoggerFactory loggerFactory) { _logger = loggerFactory.CreateLogger(); @@ -22,46 +19,26 @@ namespace Ocelot.Requester public async Task> GetResponse(Request.Request request) { - double timeoutvalue = 5000; - TimeoutStrategy timeoutStrategy = TimeoutStrategy.Pessimistic; - - var timeoutPolicy = Policy - .TimeoutAsync(TimeSpan.FromMilliseconds(timeoutvalue), timeoutStrategy); - - var circuitBreakerPolicy = Policy - .Handle() - .Or() - .Or() - .CircuitBreakerAsync( - exceptionsAllowedBeforeBreaking: 4, - durationOfBreak: TimeSpan.FromSeconds(8), - 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.") - ); + HttpClientBuilder builder = new HttpClientBuilder(); using (var handler = new HttpClientHandler { CookieContainer = request.CookieContainer }) - using (var httpClient = new HttpClient(handler)) { - try + builder.WithCircuitBreaker(request.Qos, _logger, handler); + using (var httpClient = builder.Build()) { - // Retry the following call according to the policy - 3 times. - HttpResponseMessage response = await Policy.WrapAsync(circuitBreakerPolicy, timeoutPolicy).ExecuteAsync(() => + try { - return httpClient.SendAsync(request.HttpRequestMessage); - }); - return new OkResponse(response); - } - catch (BrokenCircuitException exception) - { - return - new ErrorResponse(new List - { - new UnableToCompleteRequestError(exception) - }); + var response = await httpClient.SendAsync(request.HttpRequestMessage); + return new OkResponse(response); + } + catch (Exception exception) + { + return + new ErrorResponse(new List + { + new UnableToCompleteRequestError(exception) + }); + } } } } diff --git a/src/Ocelot/Requester/IHttpRequester.cs b/src/Ocelot/Requester/IHttpRequester.cs index 201c3add..e3972957 100644 --- a/src/Ocelot/Requester/IHttpRequester.cs +++ b/src/Ocelot/Requester/IHttpRequester.cs @@ -7,5 +7,7 @@ namespace Ocelot.Requester public interface IHttpRequester { Task> GetResponse(Request.Request request); + + } } diff --git a/src/Ocelot/Values/QoS.cs b/src/Ocelot/Values/QoS.cs new file mode 100644 index 00000000..b3e8df6a --- /dev/null +++ b/src/Ocelot/Values/QoS.cs @@ -0,0 +1,27 @@ +using Polly.Timeout; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Ocelot.Values +{ + public class QoS + { + public QoS(int exceptionsAllowedBeforeBreaking, int durationofBreak, int timeoutValue, TimeoutStrategy timeoutStrategy = TimeoutStrategy.Pessimistic) + { + ExceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking; + DurationOfBreak = TimeSpan.FromMilliseconds(durationofBreak); + TimeoutValue = TimeSpan.FromMilliseconds(timeoutValue); + TimeoutStrategy = timeoutStrategy; + } + + public int ExceptionsAllowedBeforeBreaking { get; private set; } + + public TimeSpan DurationOfBreak { get; private set; } + + public TimeSpan TimeoutValue { get; private set; } + + public TimeoutStrategy TimeoutStrategy { get; private set; } + } +} diff --git a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs index 8b14f4f1..4a23282c 100644 --- a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs @@ -125,6 +125,9 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = _downstreamServiceScheme, UpstreamTemplate = "/", UpstreamHttpMethod = "Get", + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, AuthenticationOptions = new FileAuthenticationOptions { AdditionalScopes = new List(), @@ -165,6 +168,9 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = _downstreamServiceScheme, UpstreamTemplate = "/", UpstreamHttpMethod = "Post", + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, AuthenticationOptions = new FileAuthenticationOptions { AdditionalScopes = new List(), @@ -205,6 +211,9 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = _downstreamServiceScheme, UpstreamTemplate = "/", UpstreamHttpMethod = "Post", + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, AuthenticationOptions = new FileAuthenticationOptions { AdditionalScopes = new List(), diff --git a/test/Ocelot.AcceptanceTests/AuthorisationTests.cs b/test/Ocelot.AcceptanceTests/AuthorisationTests.cs index 1f86c6ff..17f99528 100644 --- a/test/Ocelot.AcceptanceTests/AuthorisationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthorisationTests.cs @@ -43,6 +43,9 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, AuthenticationOptions = new FileAuthenticationOptions { AdditionalScopes = new List(), diff --git a/test/Ocelot.AcceptanceTests/CachingTests.cs b/test/Ocelot.AcceptanceTests/CachingTests.cs index e4e628af..46f5dc3c 100644 --- a/test/Ocelot.AcceptanceTests/CachingTests.cs +++ b/test/Ocelot.AcceptanceTests/CachingTests.cs @@ -37,6 +37,9 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, FileCacheOptions = new FileCacheOptions { TtlSeconds = 100 @@ -73,6 +76,9 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, FileCacheOptions = new FileCacheOptions { TtlSeconds = 1 diff --git a/test/Ocelot.AcceptanceTests/CaseSensitiveRoutingTests.cs b/test/Ocelot.AcceptanceTests/CaseSensitiveRoutingTests.cs index 81824602..9cb8e72c 100644 --- a/test/Ocelot.AcceptanceTests/CaseSensitiveRoutingTests.cs +++ b/test/Ocelot.AcceptanceTests/CaseSensitiveRoutingTests.cs @@ -35,7 +35,10 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", UpstreamTemplate = "/products/{productId}", - UpstreamHttpMethod = "Get" + UpstreamHttpMethod = "Get", + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000 } } }; @@ -63,7 +66,10 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamTemplate = "/products/{productId}", UpstreamHttpMethod = "Get", - ReRouteIsCaseSensitive = false + ReRouteIsCaseSensitive = false, + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, } } }; @@ -91,7 +97,10 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamTemplate = "/products/{productId}", UpstreamHttpMethod = "Get", - ReRouteIsCaseSensitive = true + ReRouteIsCaseSensitive = true, + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000 } } }; @@ -119,7 +128,10 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamTemplate = "/PRODUCTS/{productId}", UpstreamHttpMethod = "Get", - ReRouteIsCaseSensitive = true + ReRouteIsCaseSensitive = true, + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, } } }; @@ -147,7 +159,10 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamTemplate = "/products/{productId}", UpstreamHttpMethod = "Get", - ReRouteIsCaseSensitive = true + ReRouteIsCaseSensitive = true, + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, } } }; @@ -175,7 +190,10 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamTemplate = "/PRODUCTS/{productId}", UpstreamHttpMethod = "Get", - ReRouteIsCaseSensitive = true + ReRouteIsCaseSensitive = true, + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000 } } }; diff --git a/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs b/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs index 08bbd968..4c036eac 100644 --- a/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs +++ b/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs @@ -57,6 +57,9 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, AuthenticationOptions = new FileAuthenticationOptions { AdditionalScopes = new List diff --git a/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs b/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs index 04dc25db..fe8ff799 100644 --- a/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs +++ b/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs @@ -57,6 +57,9 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, AuthenticationOptions = new FileAuthenticationOptions { AdditionalScopes = new List diff --git a/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs b/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs index f6f6de20..1ad929de 100644 --- a/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs +++ b/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs @@ -51,6 +51,9 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, } } }; @@ -88,6 +91,9 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, } } }; @@ -125,6 +131,9 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, } } }; @@ -162,6 +171,9 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, } } }; @@ -199,6 +211,9 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, } } }; @@ -236,6 +251,9 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, } } }; diff --git a/test/Ocelot.AcceptanceTests/RequestIdTests.cs b/test/Ocelot.AcceptanceTests/RequestIdTests.cs index 9334786b..2273eb2c 100644 --- a/test/Ocelot.AcceptanceTests/RequestIdTests.cs +++ b/test/Ocelot.AcceptanceTests/RequestIdTests.cs @@ -39,7 +39,10 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", - RequestIdKey = _steps.RequestIdKey + RequestIdKey = _steps.RequestIdKey, + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, } } }; @@ -67,7 +70,10 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", - RequestIdKey = _steps.RequestIdKey + RequestIdKey = _steps.RequestIdKey, + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, } } }; @@ -97,6 +103,9 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, } }, GlobalConfiguration = new FileGlobalConfiguration diff --git a/test/Ocelot.AcceptanceTests/RoutingTests.cs b/test/Ocelot.AcceptanceTests/RoutingTests.cs index 4f97114f..acfec46c 100644 --- a/test/Ocelot.AcceptanceTests/RoutingTests.cs +++ b/test/Ocelot.AcceptanceTests/RoutingTests.cs @@ -46,6 +46,9 @@ namespace Ocelot.AcceptanceTests DownstreamPort = 51879, UpstreamTemplate = "/", UpstreamHttpMethod = "Get", + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, } } }; @@ -74,6 +77,9 @@ namespace Ocelot.AcceptanceTests DownstreamPort = 51879, UpstreamTemplate = "/", UpstreamHttpMethod = "Get", + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, } } }; @@ -102,6 +108,9 @@ namespace Ocelot.AcceptanceTests DownstreamPort = 51879, UpstreamTemplate = "/", UpstreamHttpMethod = "Get", + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, } } }; @@ -130,6 +139,9 @@ namespace Ocelot.AcceptanceTests DownstreamPort = 51879, UpstreamTemplate = "/products/", UpstreamHttpMethod = "Get", + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, } } }; @@ -158,6 +170,9 @@ namespace Ocelot.AcceptanceTests DownstreamPort = 51879, UpstreamTemplate = "/products", UpstreamHttpMethod = "Get", + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, } } }; @@ -186,6 +201,9 @@ namespace Ocelot.AcceptanceTests DownstreamPort = 51879, UpstreamTemplate = "/products/{productId}", UpstreamHttpMethod = "Get", + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, } } }; @@ -212,7 +230,10 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", DownstreamPort = 51879, UpstreamTemplate = "/products/{productId}", - UpstreamHttpMethod = "Get" + UpstreamHttpMethod = "Get", + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, } } }; @@ -240,7 +261,10 @@ namespace Ocelot.AcceptanceTests DownstreamPort = 51879, DownstreamScheme = "http", UpstreamTemplate = "/", - UpstreamHttpMethod = "Post" + UpstreamHttpMethod = "Post", + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, } } }; @@ -269,6 +293,9 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", DownstreamPort = 51879, UpstreamHttpMethod = "Get", + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak =5, + TimeoutValue = 5000, } } }; diff --git a/test/Ocelot.AcceptanceTests/configuration.json b/test/Ocelot.AcceptanceTests/configuration.json index f28abefe..0c347f55 100755 --- a/test/Ocelot.AcceptanceTests/configuration.json +++ b/test/Ocelot.AcceptanceTests/configuration.json @@ -1 +1 @@ -{"ReRoutes":[{"DownstreamPathTemplate":"/","UpstreamTemplate":"/","UpstreamHttpMethod":"Get","AuthenticationOptions":{"Provider":null,"ProviderRootUrl":null,"ScopeName":null,"RequireHttps":false,"AdditionalScopes":[],"ScopeSecret":null},"AddHeadersToRequest":{},"AddClaimsToRequest":{},"RouteClaimsRequirement":{},"AddQueriesToRequest":{},"RequestIdKey":null,"FileCacheOptions":{"TtlSeconds":0},"ReRouteIsCaseSensitive":false,"ServiceName":null,"DownstreamScheme":"http","DownstreamHost":"localhost","DownstreamPort":41879}],"GlobalConfiguration":{"RequestIdKey":null,"ServiceDiscoveryProvider":{"Provider":null,"Address":null}}} \ No newline at end of file +{"ReRoutes":[{"DownstreamPathTemplate":"/","UpstreamTemplate":"/","UpstreamHttpMethod":"Get","AuthenticationOptions":{"Provider":null,"ProviderRootUrl":null,"ScopeName":null,"RequireHttps":false,"AdditionalScopes":[],"ScopeSecret":null},"AddHeadersToRequest":{},"AddClaimsToRequest":{},"RouteClaimsRequirement":{},"AddQueriesToRequest":{},"RequestIdKey":null,"FileCacheOptions":{"TtlSeconds":0},"ReRouteIsCaseSensitive":false,"ServiceName":null,"DownstreamScheme":"http","DownstreamHost":"localhost","DownstreamPort":41879,"ExceptionsAllowedBeforeBreaking":3,"DurationOfBreak":5,"TimeoutValue":5000}],"GlobalConfiguration":{"RequestIdKey":null,"ServiceDiscoveryProvider":{"Provider":null,"Address":null}}} \ No newline at end of file diff --git a/test/Ocelot.ManualTest/configuration.json b/test/Ocelot.ManualTest/configuration.json index f7e2bb75..a887f3fb 100644 --- a/test/Ocelot.ManualTest/configuration.json +++ b/test/Ocelot.ManualTest/configuration.json @@ -1,119 +1,149 @@ { "ReRoutes": [ - { - "DownstreamPathTemplate": "/", - "DownstreamScheme": "http", - "DownstreamHost": "localhost", - "DownstreamPort": 52876, - "UpstreamTemplate": "/identityserverexample", - "UpstreamHttpMethod": "Get", - "AuthenticationOptions": { - "Provider": "IdentityServer", - "ProviderRootUrl": "http://localhost:52888", - "ScopeName": "api", - "AdditionalScopes": [ - "openid", - "offline_access" - ], - "ScopeSecret": "secret" - }, - "AddHeadersToRequest": { - "CustomerId": "Claims[CustomerId] > value", - "LocationId": "Claims[LocationId] > value", - "UserType": "Claims[sub] > value[0] > |", - "UserId": "Claims[sub] > value[1] > |" - }, - "AddClaimsToRequest": { - "CustomerId": "Claims[CustomerId] > value", - "LocationId": "Claims[LocationId] > value", - "UserType": "Claims[sub] > value[0] > |", - "UserId": "Claims[sub] > value[1] > |" - }, - "AddQueriesToRequest": { - "CustomerId": "Claims[CustomerId] > value", - "LocationId": "Claims[LocationId] > value", - "UserType": "Claims[sub] > value[0] > |", - "UserId": "Claims[sub] > value[1] > |" - }, - "RouteClaimsRequirement": { - "UserType": "registered" - }, - "RequestIdKey": "OcRequestId" + { + "DownstreamPathTemplate": "/", + "DownstreamScheme": "http", + "DownstreamHost": "localhost", + "DownstreamPort": 52876, + "UpstreamTemplate": "/identityserverexample", + "UpstreamHttpMethod": "Get", + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000, + "AuthenticationOptions": { + "Provider": "IdentityServer", + "ProviderRootUrl": "http://localhost:52888", + "ScopeName": "api", + "AdditionalScopes": [ + "openid", + "offline_access" + ], + "ScopeSecret": "secret" }, - { - "DownstreamPathTemplate": "/posts", - "DownstreamScheme": "http", - "DownstreamHost": "jsonplaceholder.typicode.com", - "DownstreamPort": 80, - "UpstreamTemplate": "/posts", - "UpstreamHttpMethod": "Get", - "FileCacheOptions": { "TtlSeconds": 15 } + "AddHeadersToRequest": { + "CustomerId": "Claims[CustomerId] > value", + "LocationId": "Claims[LocationId] > value", + "UserType": "Claims[sub] > value[0] > |", + "UserId": "Claims[sub] > value[1] > |" }, - { - "DownstreamPathTemplate": "/posts/{postId}", - "DownstreamScheme": "http", - "DownstreamHost": "jsonplaceholder.typicode.com", - "DownstreamPort": 80, - "UpstreamTemplate": "/posts/{postId}", - "UpstreamHttpMethod": "Get" + "AddClaimsToRequest": { + "CustomerId": "Claims[CustomerId] > value", + "LocationId": "Claims[LocationId] > value", + "UserType": "Claims[sub] > value[0] > |", + "UserId": "Claims[sub] > value[1] > |" }, - { - "DownstreamPathTemplate": "/posts/{postId}/comments", - "DownstreamScheme": "http", - "DownstreamHost": "jsonplaceholder.typicode.com", - "DownstreamPort": 80, - "UpstreamTemplate": "/posts/{postId}/comments", - "UpstreamHttpMethod": "Get" + "AddQueriesToRequest": { + "CustomerId": "Claims[CustomerId] > value", + "LocationId": "Claims[LocationId] > value", + "UserType": "Claims[sub] > value[0] > |", + "UserId": "Claims[sub] > value[1] > |" }, - { - "DownstreamPathTemplate": "/comments", - "DownstreamScheme": "http", - "DownstreamHost": "jsonplaceholder.typicode.com", - "DownstreamPort": 80, - "UpstreamTemplate": "/comments", - "UpstreamHttpMethod": "Get" - }, - { - "DownstreamPathTemplate": "/posts", - "DownstreamScheme": "http", - "DownstreamHost": "jsonplaceholder.typicode.com", - "DownstreamPort": 80, - "UpstreamTemplate": "/posts", - "UpstreamHttpMethod": "Post" - }, - { - "DownstreamPathTemplate": "/posts/{postId}", - "DownstreamScheme": "http", - "DownstreamHost": "jsonplaceholder.typicode.com", - "DownstreamPort": 80, - "UpstreamTemplate": "/posts/{postId}", - "UpstreamHttpMethod": "Put" - }, - { - "DownstreamPathTemplate": "/posts/{postId}", - "DownstreamScheme": "http", - "DownstreamHost": "jsonplaceholder.typicode.com", - "DownstreamPort": 80, - "UpstreamTemplate": "/posts/{postId}", - "UpstreamHttpMethod": "Patch" - }, - { - "DownstreamPathTemplate": "/posts/{postId}", - "DownstreamScheme": "http", - "DownstreamHost": "jsonplaceholder.typicode.com", - "DownstreamPort": 80, - "UpstreamTemplate": "/posts/{postId}", - "UpstreamHttpMethod": "Delete" - }, - { - "DownstreamPathTemplate": "/api/products", - "DownstreamScheme": "http", - "DownstreamHost": "jsonplaceholder.typicode.com", - "DownstreamPort": 80, - "UpstreamTemplate": "/products", - "UpstreamHttpMethod": "Get", - "FileCacheOptions": { "TtlSeconds": 15 } + "RouteClaimsRequirement": { + "UserType": "registered" }, + "RequestIdKey": "OcRequestId" + }, + { + "DownstreamPathTemplate": "/posts", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamTemplate": "/posts", + "UpstreamHttpMethod": "Get", + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000, + "FileCacheOptions": { "TtlSeconds": 15 } + }, + { + "DownstreamPathTemplate": "/posts/{postId}", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamTemplate": "/posts/{postId}", + "UpstreamHttpMethod": "Get", + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + }, + { + "DownstreamPathTemplate": "/posts/{postId}/comments", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamTemplate": "/posts/{postId}/comments", + "UpstreamHttpMethod": "Get", + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + }, + { + "DownstreamPathTemplate": "/comments", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamTemplate": "/comments", + "UpstreamHttpMethod": "Get", + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + }, + { + "DownstreamPathTemplate": "/posts", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamTemplate": "/posts", + "UpstreamHttpMethod": "Post", + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + }, + { + "DownstreamPathTemplate": "/posts/{postId}", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamTemplate": "/posts/{postId}", + "UpstreamHttpMethod": "Put", + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + }, + { + "DownstreamPathTemplate": "/posts/{postId}", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamTemplate": "/posts/{postId}", + "UpstreamHttpMethod": "Patch", + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + }, + { + "DownstreamPathTemplate": "/posts/{postId}", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamTemplate": "/posts/{postId}", + "UpstreamHttpMethod": "Delete", + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + }, + { + "DownstreamPathTemplate": "/api/products", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamTemplate": "/products", + "UpstreamHttpMethod": "Get", + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000, + "FileCacheOptions": { "TtlSeconds": 15 } + }, { "DownstreamPathTemplate": "/api/products/{productId}", "DownstreamScheme": "http", @@ -123,87 +153,114 @@ "UpstreamHttpMethod": "Get", "FileCacheOptions": { "TtlSeconds": 15 } }, - { - "DownstreamPathTemplate": "/api/products", - "DownstreamScheme": "http", - "DownstreamHost": "products20161126090340.azurewebsites.net", - "DownstreamPort": 80, - "UpstreamTemplate": "/products", - "UpstreamHttpMethod": "Post", - "FileCacheOptions": { "TtlSeconds": 15 } - }, - { - "DownstreamPathTemplate": "/api/products/{productId}", - "DownstreamScheme": "http", - "DownstreamHost": "products20161126090340.azurewebsites.net", - "DownstreamPort": 80, - "UpstreamTemplate": "/products/{productId}", - "UpstreamHttpMethod": "Put", - "FileCacheOptions": { "TtlSeconds": 15 } - }, - { - "DownstreamPathTemplate": "/api/products/{productId}", - "DownstreamScheme": "http", - "DownstreamHost": "products20161126090340.azurewebsites.net", - "DownstreamPort": 80, - "UpstreamTemplate": "/products/{productId}", - "UpstreamHttpMethod": "Delete", - "FileCacheOptions": { "TtlSeconds": 15 } - }, - { - "DownstreamPathTemplate": "/api/customers", - "DownstreamScheme": "http", - "DownstreamHost": "customers20161126090811.azurewebsites.net", - "DownstreamPort": 80, - "UpstreamTemplate": "/customers", - "UpstreamHttpMethod": "Get", - "FileCacheOptions": { "TtlSeconds": 15 } - }, - { - "DownstreamPathTemplate": "/api/customers/{customerId}", - "DownstreamScheme": "http", - "DownstreamHost": "customers20161126090811.azurewebsites.net", - "DownstreamPort": 80, - "UpstreamTemplate": "/customers/{customerId}", - "UpstreamHttpMethod": "Get", - "FileCacheOptions": { "TtlSeconds": 15 } - }, - { - "DownstreamPathTemplate": "/api/customers", - "DownstreamScheme": "http", - "DownstreamHost": "customers20161126090811.azurewebsites.net", - "DownstreamPort": 80, - "UpstreamTemplate": "/customers", - "UpstreamHttpMethod": "Post", - "FileCacheOptions": { "TtlSeconds": 15 } - }, - { - "DownstreamPathTemplate": "/api/customers/{customerId}", - "DownstreamScheme": "http", - "DownstreamHost": "customers20161126090811.azurewebsites.net", - "DownstreamPort": 80, - "UpstreamTemplate": "/customers/{customerId}", - "UpstreamHttpMethod": "Put", - "FileCacheOptions": { "TtlSeconds": 15 } - }, - { - "DownstreamPathTemplate": "/api/customers/{customerId}", - "DownstreamScheme": "http", - "DownstreamHost": "customers20161126090811.azurewebsites.net", - "DownstreamPort": 80, - "UpstreamTemplate": "/customers/{customerId}", - "UpstreamHttpMethod": "Delete", - "FileCacheOptions": { "TtlSeconds": 15 } - }, - { - "DownstreamPathTemplate": "/posts", - "DownstreamScheme": "http", - "DownstreamHost": "jsonplaceholder.typicode.com", - "DownstreamPort": 80, - "UpstreamTemplate": "/posts/", - "UpstreamHttpMethod": "Get", - "FileCacheOptions": { "TtlSeconds": 15 } - } + { + "DownstreamPathTemplate": "/api/products", + "DownstreamScheme": "http", + "DownstreamHost": "products20161126090340.azurewebsites.net", + "DownstreamPort": 80, + "UpstreamTemplate": "/products", + "UpstreamHttpMethod": "Post", + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000, + "FileCacheOptions": { "TtlSeconds": 15 } + }, + { + "DownstreamPathTemplate": "/api/products/{productId}", + "DownstreamScheme": "http", + "DownstreamHost": "products20161126090340.azurewebsites.net", + "DownstreamPort": 80, + "UpstreamTemplate": "/products/{productId}", + "UpstreamHttpMethod": "Put", + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000, + "FileCacheOptions": { "TtlSeconds": 15 } + }, + { + "DownstreamPathTemplate": "/api/products/{productId}", + "DownstreamScheme": "http", + "DownstreamHost": "products20161126090340.azurewebsites.net", + "DownstreamPort": 80, + "UpstreamTemplate": "/products/{productId}", + "UpstreamHttpMethod": "Delete", + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000, + "FileCacheOptions": { "TtlSeconds": 15 } + }, + { + "DownstreamPathTemplate": "/api/customers", + "DownstreamScheme": "http", + "DownstreamHost": "customers20161126090811.azurewebsites.net", + "DownstreamPort": 80, + "UpstreamTemplate": "/customers", + "UpstreamHttpMethod": "Get", + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000, + "FileCacheOptions": { "TtlSeconds": 15 } + }, + { + "DownstreamPathTemplate": "/api/customers/{customerId}", + "DownstreamScheme": "http", + "DownstreamHost": "customers20161126090811.azurewebsites.net", + "DownstreamPort": 80, + "UpstreamTemplate": "/customers/{customerId}", + "UpstreamHttpMethod": "Get", + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000, + "FileCacheOptions": { "TtlSeconds": 15 } + }, + { + "DownstreamPathTemplate": "/api/customers", + "DownstreamScheme": "http", + "DownstreamHost": "customers20161126090811.azurewebsites.net", + "DownstreamPort": 80, + "UpstreamTemplate": "/customers", + "UpstreamHttpMethod": "Post", + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000, + "FileCacheOptions": { "TtlSeconds": 15 } + }, + { + "DownstreamPathTemplate": "/api/customers/{customerId}", + "DownstreamScheme": "http", + "DownstreamHost": "customers20161126090811.azurewebsites.net", + "DownstreamPort": 80, + "UpstreamTemplate": "/customers/{customerId}", + "UpstreamHttpMethod": "Put", + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000, + "FileCacheOptions": { "TtlSeconds": 15 } + }, + { + "DownstreamPathTemplate": "/api/customers/{customerId}", + "DownstreamScheme": "http", + "DownstreamHost": "customers20161126090811.azurewebsites.net", + "DownstreamPort": 80, + "UpstreamTemplate": "/customers/{customerId}", + "UpstreamHttpMethod": "Delete", + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000, + "FileCacheOptions": { "TtlSeconds": 15 } + }, + { + "DownstreamPathTemplate": "/posts", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamTemplate": "/posts/", + "UpstreamHttpMethod": "Get", + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000, + "FileCacheOptions": { "TtlSeconds": 15 } + } ], "GlobalConfiguration": { "RequestIdKey": "OcRequestId" diff --git a/test/Ocelot.UnitTests/Request/HttpRequestBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/Request/HttpRequestBuilderMiddlewareTests.cs index e2f81abe..406e7cb6 100644 --- a/test/Ocelot.UnitTests/Request/HttpRequestBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Request/HttpRequestBuilderMiddlewareTests.cs @@ -72,7 +72,7 @@ namespace Ocelot.UnitTests.Request this.Given(x => x.GivenTheDownStreamUrlIs("any old string")) .And(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) - .And(x => x.GivenTheRequestBuilderReturns(new Ocelot.Request.Request(new HttpRequestMessage(), new CookieContainer()))) + .And(x => x.GivenTheRequestBuilderReturns(new Ocelot.Request.Request(new HttpRequestMessage(), new CookieContainer(),new Values.QoS(3, 8 ,5000, Polly.Timeout.TimeoutStrategy.Pessimistic)))) .When(x => x.WhenICallTheMiddleware()) .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) .BDDfy(); @@ -91,7 +91,7 @@ namespace Ocelot.UnitTests.Request _request = new OkResponse(request); _requestBuilder .Setup(x => x.Build(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), - It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(),It.IsAny())) .ReturnsAsync(_request); } diff --git a/test/Ocelot.UnitTests/Request/RequestBuilderTests.cs b/test/Ocelot.UnitTests/Request/RequestBuilderTests.cs index 3a07532e..55d18c38 100644 --- a/test/Ocelot.UnitTests/Request/RequestBuilderTests.cs +++ b/test/Ocelot.UnitTests/Request/RequestBuilderTests.cs @@ -25,6 +25,7 @@ namespace Ocelot.UnitTests.Request private readonly IRequestCreator _requestCreator; private Response _result; private Ocelot.RequestId.RequestId _requestId; + private Ocelot.Values.QoS _qos; public RequestBuilderTests() { @@ -37,6 +38,7 @@ namespace Ocelot.UnitTests.Request { this.Given(x => x.GivenIHaveHttpMethod("GET")) .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) + .And(x=> x.GivenTheQos(new Values.QoS(3, 8, 5000, Polly.Timeout.TimeoutStrategy.Pessimistic))) .When(x => x.WhenICreateARequest()) .And(x => x.ThenTheCorrectDownstreamUrlIsUsed("http://www.bbc.co.uk/")) .BDDfy(); @@ -47,6 +49,8 @@ namespace Ocelot.UnitTests.Request { this.Given(x => x.GivenIHaveHttpMethod("POST")) .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) + .And(x => x.GivenTheQos(new Values.QoS(3, 8, 5000, Polly.Timeout.TimeoutStrategy.Pessimistic))) + .When(x => x.WhenICreateARequest()) .And(x => x.ThenTheCorrectHttpMethodIsUsed(HttpMethod.Post)) .BDDfy(); @@ -59,7 +63,9 @@ namespace Ocelot.UnitTests.Request .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) .And(x => x.GivenIHaveTheHttpContent(new StringContent("Hi from Tom"))) .And(x => x.GivenTheContentTypeIs("application/json")) - .When(x => x.WhenICreateARequest()) + .And(x => x.GivenTheQos(new Values.QoS(3, 8, 5000, Polly.Timeout.TimeoutStrategy.Pessimistic))) + + .When(x => x.WhenICreateARequest()) .And(x => x.ThenTheCorrectContentIsUsed(new StringContent("Hi from Tom"))) .BDDfy(); } @@ -71,6 +77,8 @@ namespace Ocelot.UnitTests.Request .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) .And(x => x.GivenIHaveTheHttpContent(new StringContent("Hi from Tom"))) .And(x => x.GivenTheContentTypeIs("application/json")) + .And(x => x.GivenTheQos(new Values.QoS(3, 8, 5000, Polly.Timeout.TimeoutStrategy.Pessimistic))) + .When(x => x.WhenICreateARequest()) .And(x => x.ThenTheCorrectContentHeadersAreUsed(new HeaderDictionary { @@ -88,6 +96,8 @@ namespace Ocelot.UnitTests.Request .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) .And(x => x.GivenIHaveTheHttpContent(new StringContent("Hi from Tom"))) .And(x => x.GivenTheContentTypeIs("application/json; charset=utf-8")) + .And(x => x.GivenTheQos(new Values.QoS(3, 8, 5000, Polly.Timeout.TimeoutStrategy.Pessimistic))) + .When(x => x.WhenICreateARequest()) .And(x => x.ThenTheCorrectContentHeadersAreUsed(new HeaderDictionary { @@ -107,6 +117,8 @@ namespace Ocelot.UnitTests.Request { {"ChopSticks", "Bubbles" } })) + .And(x => x.GivenTheQos(new Values.QoS(3, 8, 5000, Polly.Timeout.TimeoutStrategy.Pessimistic))) + .When(x => x.WhenICreateARequest()) .And(x => x.ThenTheCorrectHeadersAreUsed(new HeaderDictionary { @@ -124,7 +136,8 @@ namespace Ocelot.UnitTests.Request .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) .And(x => x.GivenTheHttpHeadersAre(new HeaderDictionary())) .And(x => x.GivenTheRequestIdIs(new Ocelot.RequestId.RequestId("RequestId", requestId))) - .When(x => x.WhenICreateARequest()) + .And(x => x.GivenTheQos(new Values.QoS(3, 8, 5000, Polly.Timeout.TimeoutStrategy.Pessimistic))) + .When(x => x.WhenICreateARequest()) .And(x => x.ThenTheCorrectHeadersAreUsed(new HeaderDictionary { {"RequestId", requestId } @@ -142,7 +155,8 @@ namespace Ocelot.UnitTests.Request {"RequestId", "534534gv54gv45g" } })) .And(x => x.GivenTheRequestIdIs(new Ocelot.RequestId.RequestId("RequestId", Guid.NewGuid().ToString()))) - .When(x => x.WhenICreateARequest()) + .And(x => x.GivenTheQos(new Values.QoS(3, 8, 5000, Polly.Timeout.TimeoutStrategy.Pessimistic))) + .When(x => x.WhenICreateARequest()) .And(x => x.ThenTheCorrectHeadersAreUsed(new HeaderDictionary { {"RequestId", "534534gv54gv45g" } @@ -161,7 +175,8 @@ namespace Ocelot.UnitTests.Request .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) .And(x => x.GivenTheHttpHeadersAre(new HeaderDictionary())) .And(x => x.GivenTheRequestIdIs(new Ocelot.RequestId.RequestId(requestIdKey, requestIdValue))) - .When(x => x.WhenICreateARequest()) + .And(x => x.GivenTheQos(new Values.QoS(3, 8, 5000, Polly.Timeout.TimeoutStrategy.Pessimistic))) + .When(x => x.WhenICreateARequest()) .And(x => x.ThenTheRequestIdIsNotInTheHeaders()) .BDDfy(); } @@ -171,6 +186,11 @@ namespace Ocelot.UnitTests.Request _requestId = requestId; } + private void GivenTheQos(Ocelot.Values.QoS qos) + { + _qos = qos; + } + [Fact] public void should_use_cookies() { @@ -281,7 +301,7 @@ namespace Ocelot.UnitTests.Request private void WhenICreateARequest() { _result = _requestCreator.Build(_httpMethod, _downstreamUrl, _content?.ReadAsStreamAsync().Result, _headers, - _cookies, _query, _contentType, _requestId).Result; + _cookies, _query, _contentType, _requestId, _qos).Result; } diff --git a/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs b/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs index d99a99eb..66c7491e 100644 --- a/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs @@ -61,7 +61,7 @@ namespace Ocelot.UnitTests.Requester [Fact] public void should_call_scoped_data_repository_correctly() { - this.Given(x => x.GivenTheRequestIs(new Ocelot.Request.Request(new HttpRequestMessage(),new CookieContainer()))) + this.Given(x => x.GivenTheRequestIs(new Ocelot.Request.Request(new HttpRequestMessage(),new CookieContainer(), new Values.QoS(3, 8, 5000, Polly.Timeout.TimeoutStrategy.Pessimistic)))) .And(x => x.GivenTheRequesterReturns(new HttpResponseMessage())) .And(x => x.GivenTheScopedRepoReturns()) .When(x => x.WhenICallTheMiddleware())