diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index a038c877..00000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.gitignore b/.gitignore index 1a7759c2..f96b1d02 100644 --- a/.gitignore +++ b/.gitignore @@ -236,3 +236,9 @@ _Pvt_Extensions # FAKE - F# Make .fake/ tools/ + +# MacOS +.DS_Store + +# Ocelot acceptance test config +test/Ocelot.AcceptanceTests/configuration.json \ No newline at end of file diff --git a/src/.DS_Store b/src/.DS_Store deleted file mode 100644 index e6c4e75f..00000000 Binary files a/src/.DS_Store and /dev/null differ diff --git a/src/Ocelot/.DS_Store b/src/Ocelot/.DS_Store deleted file mode 100644 index 996c69e4..00000000 Binary files a/src/Ocelot/.DS_Store and /dev/null differ diff --git a/src/Ocelot/Authentication/Handler/.DS_Store b/src/Ocelot/Authentication/Handler/.DS_Store deleted file mode 100644 index 61afe9de..00000000 Binary files a/src/Ocelot/Authentication/Handler/.DS_Store and /dev/null differ diff --git a/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs b/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs index d6615d11..42e4e5bf 100644 --- a/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs +++ b/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs @@ -28,6 +28,8 @@ namespace Ocelot.Configuration.Builder private int _downstreamPort; private string _loadBalancer; private ServiceProviderConfiguraion _serviceProviderConfiguraion; + private bool _useQos; + private QoSOptions _qosOptions; public ReRouteBuilder WithLoadBalancer(string loadBalancer) { @@ -135,6 +137,19 @@ namespace Ocelot.Configuration.Builder return this; } + public ReRouteBuilder WithIsQos(bool input) + { + _useQos = input; + return this; + } + + public ReRouteBuilder WithQosOptions(QoSOptions input) + { + _qosOptions = input; + return this; + } + + public ReRouteBuilder WithLoadBalancerKey(string loadBalancerKey) { _loadBalancerKey = loadBalancerKey; @@ -175,7 +190,9 @@ namespace Ocelot.Configuration.Builder _downstreamHost, _downstreamPort, _loadBalancerKey, - _serviceProviderConfiguraion); + _serviceProviderConfiguraion, + _useQos, + _qosOptions); } } } diff --git a/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs index 357d6296..740a2b95 100644 --- a/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs +++ b/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs @@ -95,12 +95,14 @@ namespace Ocelot.Configuration.Creator var loadBalancerKey = BuildLoadBalancerKey(fileReRoute); var upstreamTemplatePattern = BuildUpstreamTemplate(fileReRoute); + var isQos = fileReRoute.QoSOptions.ExceptionsAllowedBeforeBreaking > 0 && fileReRoute.QoSOptions.TimeoutValue >0; var serviceProviderConfiguration = BuildServiceProviderConfiguration(fileReRoute, globalConfiguration); var authOptionsForRoute = BuildAuthenticationOptions(fileReRoute); var claimsToHeaders = BuildAddThingsToRequest(fileReRoute.AddHeadersToRequest); + var claimsToClaims = BuildAddThingsToRequest(fileReRoute.AddClaimsToRequest); @@ -137,7 +139,7 @@ namespace Ocelot.Configuration.Creator { return !string.IsNullOrEmpty(fileReRoute.AuthenticationOptions?.Provider); } - + private bool IsAuthorised(FileReRoute fileReRoute) { return fileReRoute.RouteClaimsRequirement?.Count > 0; diff --git a/src/Ocelot/Configuration/File/FileQoSOptions.cs b/src/Ocelot/Configuration/File/FileQoSOptions.cs new file mode 100644 index 00000000..dfac3ac6 --- /dev/null +++ b/src/Ocelot/Configuration/File/FileQoSOptions.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Ocelot.Configuration.File +{ + public class FileQoSOptions + { + public int ExceptionsAllowedBeforeBreaking { get; set; } + + public int DurationOfBreak { get; set; } + + public int TimeoutValue { get; set; } + } +} diff --git a/src/Ocelot/Configuration/File/FileReRoute.cs b/src/Ocelot/Configuration/File/FileReRoute.cs index 6d3fea4f..bdb8f87f 100644 --- a/src/Ocelot/Configuration/File/FileReRoute.cs +++ b/src/Ocelot/Configuration/File/FileReRoute.cs @@ -12,6 +12,7 @@ namespace Ocelot.Configuration.File AddQueriesToRequest = new Dictionary(); AuthenticationOptions = new FileAuthenticationOptions(); FileCacheOptions = new FileCacheOptions(); + QoSOptions = new FileQoSOptions(); } public string DownstreamPathTemplate { get; set; } @@ -29,6 +30,7 @@ namespace Ocelot.Configuration.File public string DownstreamScheme {get;set;} public string DownstreamHost {get;set;} public int DownstreamPort { get; set; } + public FileQoSOptions QoSOptions { get; set; } public string LoadBalancer {get;set;} } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/QoSOptions.cs b/src/Ocelot/Configuration/QoSOptions.cs new file mode 100644 index 00000000..8584c57e --- /dev/null +++ b/src/Ocelot/Configuration/QoSOptions.cs @@ -0,0 +1,29 @@ +using Polly.Timeout; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Ocelot.Configuration +{ + public class QoSOptions + { + public QoSOptions(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/src/Ocelot/Configuration/ReRoute.cs b/src/Ocelot/Configuration/ReRoute.cs index 82d13e02..45b31d38 100644 --- a/src/Ocelot/Configuration/ReRoute.cs +++ b/src/Ocelot/Configuration/ReRoute.cs @@ -8,16 +8,27 @@ namespace Ocelot.Configuration public class ReRoute { public ReRoute(PathTemplate downstreamPathTemplate, - PathTemplate upstreamTemplate, HttpMethod upstreamHttpMethod, + PathTemplate upstreamTemplate, + HttpMethod upstreamHttpMethod, string upstreamTemplatePattern, - bool isAuthenticated, AuthenticationOptions authenticationOptions, + bool isAuthenticated, + AuthenticationOptions authenticationOptions, List configurationHeaderExtractorProperties, List claimsToClaims, - Dictionary routeClaimsRequirement, bool isAuthorised, + Dictionary routeClaimsRequirement, + bool isAuthorised, List claimsToQueries, - string requestIdKey, bool isCached, CacheOptions fileCacheOptions, - string downstreamScheme, string loadBalancer, string downstreamHost, - int downstreamPort, string loadBalancerKey, ServiceProviderConfiguraion serviceProviderConfiguraion) + string requestIdKey, + bool isCached, + CacheOptions fileCacheOptions, + string downstreamScheme, + string loadBalancer, + string downstreamHost, + int downstreamPort, + string loadBalancerKey, + ServiceProviderConfiguraion serviceProviderConfiguraion, + bool isQos, + QoSOptions qos) { LoadBalancerKey = loadBalancerKey; ServiceProviderConfiguraion = serviceProviderConfiguraion; @@ -42,6 +53,8 @@ namespace Ocelot.Configuration ClaimsToHeaders = configurationHeaderExtractorProperties ?? new List(); DownstreamScheme = downstreamScheme; + IsQos = isQos; + QosOptions = qos; } public string LoadBalancerKey {get;private set;} @@ -60,6 +73,8 @@ namespace Ocelot.Configuration public bool IsCached { get; private set; } public CacheOptions FileCacheOptions { get; private set; } public string DownstreamScheme {get;private set;} + public bool IsQos { get; private set; } + public QoSOptions QosOptions { get; private set; } public string LoadBalancer {get;private set;} public string DownstreamHost { get; private set; } public int DownstreamPort { get; private set; } diff --git a/src/Ocelot/Request/Builder/HttpRequestCreator.cs b/src/Ocelot/Request/Builder/HttpRequestCreator.cs index 91234331..f326933c 100644 --- a/src/Ocelot/Request/Builder/HttpRequestCreator.cs +++ b/src/Ocelot/Request/Builder/HttpRequestCreator.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Ocelot.Responses; +using Ocelot.Configuration; namespace Ocelot.Request.Builder { @@ -15,7 +16,9 @@ namespace Ocelot.Request.Builder IRequestCookieCollection cookies, QueryString queryString, string contentType, - RequestId.RequestId requestId) + RequestId.RequestId requestId, + bool isQos, + QoSOptions qos) { var request = await new RequestBuilder() .WithHttpMethod(httpMethod) @@ -26,6 +29,8 @@ namespace Ocelot.Request.Builder .WithHeaders(headers) .WithRequestId(requestId) .WithCookies(cookies) + .WithIsQos(isQos) + .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..3417d933 100644 --- a/src/Ocelot/Request/Builder/IRequestCreator.cs +++ b/src/Ocelot/Request/Builder/IRequestCreator.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Ocelot.Responses; +using Ocelot.Configuration; namespace Ocelot.Request.Builder { @@ -13,7 +14,9 @@ namespace Ocelot.Request.Builder IHeaderDictionary headers, IRequestCookieCollection cookies, QueryString queryString, - string contentType, - RequestId.RequestId requestId); + string contentType, + RequestId.RequestId requestId, + bool isQos, + QoSOptions qos); } } diff --git a/src/Ocelot/Request/Builder/RequestBuilder.cs b/src/Ocelot/Request/Builder/RequestBuilder.cs index c9463993..e0201bc8 100644 --- a/src/Ocelot/Request/Builder/RequestBuilder.cs +++ b/src/Ocelot/Request/Builder/RequestBuilder.cs @@ -8,6 +8,7 @@ using System.Net.Http.Headers; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; +using Ocelot.Configuration; namespace Ocelot.Request.Builder { @@ -22,6 +23,8 @@ namespace Ocelot.Request.Builder private RequestId.RequestId _requestId; private IRequestCookieCollection _cookies; private readonly string[] _unsupportedHeaders = {"host"}; + private bool _isQos; + private QoSOptions _qos; public RequestBuilder WithHttpMethod(string httpMethod) { @@ -71,6 +74,18 @@ namespace Ocelot.Request.Builder return this; } + public RequestBuilder WithIsQos(bool isqos) + { + _isQos = isqos; + return this; + } + + public RequestBuilder WithQos(QoSOptions qos) + { + _qos = qos; + return this; + } + public async Task Build() { var uri = CreateUri(); @@ -90,7 +105,7 @@ namespace Ocelot.Request.Builder var cookieContainer = CreateCookieContainer(uri); - return new Request(httpRequestMessage, cookieContainer); + return new Request(httpRequestMessage, cookieContainer,_isQos,_qos); } private Uri CreateUri() diff --git a/src/Ocelot/Request/Middleware/HttpRequestBuilderMiddleware.cs b/src/Ocelot/Request/Middleware/HttpRequestBuilderMiddleware.cs index a2c5194b..aafa2f3d 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), + DownstreamRoute.ReRoute.IsQos,DownstreamRoute.ReRoute.QosOptions); if (buildResult.IsError) { diff --git a/src/Ocelot/Request/Request.cs b/src/Ocelot/Request/Request.cs index d43071e1..a1e62834 100644 --- a/src/Ocelot/Request/Request.cs +++ b/src/Ocelot/Request/Request.cs @@ -1,17 +1,23 @@ -using System.Net; +using Ocelot.Configuration; +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,bool isQos, QoSOptions qos) { HttpRequestMessage = httpRequestMessage; CookieContainer = cookieContainer; + IsQos = isQos; + Qos = qos; } public HttpRequestMessage HttpRequestMessage { get; private set; } public CookieContainer CookieContainer { get; private set; } + public bool IsQos { get; private set; } + public QoSOptions 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..c3c98ac0 --- /dev/null +++ b/src/Ocelot/Requester/HttpClientBuilder.cs @@ -0,0 +1,42 @@ +using Ocelot.Configuration; +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(QoSOptions 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(HttpMessageHandler innerHandler) + { + return handlers.Any() ? new HttpClient(CreateHttpMessageHandler()) : new HttpClient(innerHandler); + } + + 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 0167ef6a..77ab90cc 100644 --- a/src/Ocelot/Requester/HttpClientHttpRequester.cs +++ b/src/Ocelot/Requester/HttpClientHttpRequester.cs @@ -4,28 +4,44 @@ using System.Net.Http; using System.Threading.Tasks; using Ocelot.Errors; using Ocelot.Responses; +using Ocelot.Logging; namespace Ocelot.Requester { public class HttpClientHttpRequester : IHttpRequester { + private readonly IOcelotLogger _logger; + + public HttpClientHttpRequester(IOcelotLoggerFactory loggerFactory) + { + _logger = loggerFactory.CreateLogger(); + } + public async Task> GetResponse(Request.Request request) { + HttpClientBuilder builder = new HttpClientBuilder(); + using (var handler = new HttpClientHandler { CookieContainer = request.CookieContainer }) - using (var httpClient = new HttpClient(handler)) { - try + if (request.IsQos) { - var response = await httpClient.SendAsync(request.HttpRequestMessage); - return new OkResponse(response); - } - catch (Exception exception) + builder.WithCircuitBreaker(request.Qos, _logger, handler); + } + using (var httpClient = builder.Build(handler)) { - return - new ErrorResponse(new List - { - new UnableToCompleteRequestError(exception) - }); + try + { + 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/project.json b/src/Ocelot/project.json index 6ce4ffbb..4e098803 100644 --- a/src/Ocelot/project.json +++ b/src/Ocelot/project.json @@ -1,38 +1,38 @@ { "version": "0.0.0-dev", - - "dependencies": { - "Microsoft.AspNetCore.Server.IISIntegration": "1.1.0", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0", - "Microsoft.Extensions.Configuration.FileExtensions": "1.1.0", - "Microsoft.Extensions.Configuration.Json": "1.1.0", - "Microsoft.Extensions.Logging": "1.1.0", - "Microsoft.Extensions.Logging.Console": "1.1.0", - "Microsoft.Extensions.Logging.Debug": "1.1.0", - "Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0", - "Microsoft.AspNetCore.Http": "1.1.0", - "System.Text.RegularExpressions": "4.3.0", - "Microsoft.AspNetCore.Authentication.OAuth": "1.1.0", - "Microsoft.AspNetCore.Authentication.JwtBearer": "1.1.0", - "Microsoft.AspNetCore.Authentication.OpenIdConnect": "1.1.0", - "Microsoft.AspNetCore.Authentication.Cookies": "1.1.0", - "Microsoft.AspNetCore.Authentication.Google": "1.1.0", - "Microsoft.AspNetCore.Authentication.Facebook": "1.1.0", - "Microsoft.AspNetCore.Authentication.Twitter": "1.1.0", - "Microsoft.AspNetCore.Authentication.MicrosoftAccount": "1.1.0", - "Microsoft.AspNetCore.Authentication": "1.1.0", - "IdentityServer4.AccessTokenValidation": "1.0.2", - "Microsoft.AspNetCore.Mvc": "1.1.0", - "Microsoft.AspNetCore.Server.Kestrel": "1.1.0", - "Microsoft.NETCore.App": "1.1.0", - "CacheManager.Core": "0.9.2", - "CacheManager.Microsoft.Extensions.Configuration": "0.9.2", - "CacheManager.Microsoft.Extensions.Logging": "0.9.2", - "Consul": "0.7.2.1" - }, + "dependencies": { + "Microsoft.AspNetCore.Server.IISIntegration": "1.1.0", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0", + "Microsoft.Extensions.Configuration.FileExtensions": "1.1.0", + "Microsoft.Extensions.Configuration.Json": "1.1.0", + "Microsoft.Extensions.Logging": "1.1.0", + "Microsoft.Extensions.Logging.Console": "1.1.0", + "Microsoft.Extensions.Logging.Debug": "1.1.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0", + "Microsoft.AspNetCore.Http": "1.1.0", + "System.Text.RegularExpressions": "4.3.0", + "Microsoft.AspNetCore.Authentication.OAuth": "1.1.0", + "Microsoft.AspNetCore.Authentication.JwtBearer": "1.1.0", + "Microsoft.AspNetCore.Authentication.OpenIdConnect": "1.1.0", + "Microsoft.AspNetCore.Authentication.Cookies": "1.1.0", + "Microsoft.AspNetCore.Authentication.Google": "1.1.0", + "Microsoft.AspNetCore.Authentication.Facebook": "1.1.0", + "Microsoft.AspNetCore.Authentication.Twitter": "1.1.0", + "Microsoft.AspNetCore.Authentication.MicrosoftAccount": "1.1.0", + "Microsoft.AspNetCore.Authentication": "1.1.0", + "IdentityServer4.AccessTokenValidation": "1.0.2", + "Microsoft.AspNetCore.Mvc": "1.1.0", + "Microsoft.AspNetCore.Server.Kestrel": "1.1.0", + "Microsoft.NETCore.App": "1.1.0", + "CacheManager.Core": "0.9.2", + "CacheManager.Microsoft.Extensions.Configuration": "0.9.2", + "CacheManager.Microsoft.Extensions.Logging": "0.9.2", + "Consul": "0.7.2.1", + "Polly": "5.0.3" + }, "runtimes": { "win10-x64": {}, - "osx.10.11-x64":{}, + "osx.10.11-x64": {}, "win7-x64": {} }, "frameworks": { diff --git a/test/.DS_Store b/test/.DS_Store deleted file mode 100644 index e73160dc..00000000 Binary files a/test/.DS_Store and /dev/null differ diff --git a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs index 87419ae6..6dca1dc2 100644 --- a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs @@ -165,6 +165,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = _downstreamServiceScheme, UpstreamPathTemplate = "/", UpstreamHttpMethod = "Post", + AuthenticationOptions = new FileAuthenticationOptions { AdditionalScopes = new List(), @@ -205,7 +206,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = _downstreamServiceScheme, UpstreamPathTemplate = "/", UpstreamHttpMethod = "Post", - AuthenticationOptions = new FileAuthenticationOptions + AuthenticationOptions = new FileAuthenticationOptions { AdditionalScopes = new List(), Provider = "IdentityServer", diff --git a/test/Ocelot.AcceptanceTests/CaseSensitiveRoutingTests.cs b/test/Ocelot.AcceptanceTests/CaseSensitiveRoutingTests.cs index 7b1dfc75..85e8fd68 100644 --- a/test/Ocelot.AcceptanceTests/CaseSensitiveRoutingTests.cs +++ b/test/Ocelot.AcceptanceTests/CaseSensitiveRoutingTests.cs @@ -35,7 +35,7 @@ namespace Ocelot.AcceptanceTests DownstreamScheme = "http", DownstreamHost = "localhost", UpstreamPathTemplate = "/products/{productId}", - UpstreamHttpMethod = "Get" + UpstreamHttpMethod = "Get", } } }; @@ -63,7 +63,7 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamPathTemplate = "/products/{productId}", UpstreamHttpMethod = "Get", - ReRouteIsCaseSensitive = false + ReRouteIsCaseSensitive = false, } } }; @@ -91,7 +91,7 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamPathTemplate = "/products/{productId}", UpstreamHttpMethod = "Get", - ReRouteIsCaseSensitive = true + ReRouteIsCaseSensitive = true, } } }; @@ -119,7 +119,7 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamPathTemplate = "/PRODUCTS/{productId}", UpstreamHttpMethod = "Get", - ReRouteIsCaseSensitive = true + ReRouteIsCaseSensitive = true, } } }; @@ -147,7 +147,7 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamPathTemplate = "/products/{productId}", UpstreamHttpMethod = "Get", - ReRouteIsCaseSensitive = true + ReRouteIsCaseSensitive = true, } } }; @@ -175,7 +175,7 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamPathTemplate = "/PRODUCTS/{productId}", UpstreamHttpMethod = "Get", - ReRouteIsCaseSensitive = true + ReRouteIsCaseSensitive = true, } } }; diff --git a/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs b/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs index 085ce2a5..7d33febb 100644 --- a/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs +++ b/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs @@ -88,6 +88,7 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamPathTemplate = "/", UpstreamHttpMethod = "Get", + } } }; @@ -125,6 +126,7 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamPathTemplate = "/", UpstreamHttpMethod = "Get", + } } }; diff --git a/test/Ocelot.AcceptanceTests/RequestIdTests.cs b/test/Ocelot.AcceptanceTests/RequestIdTests.cs index 8b9cd805..46a5fc13 100644 --- a/test/Ocelot.AcceptanceTests/RequestIdTests.cs +++ b/test/Ocelot.AcceptanceTests/RequestIdTests.cs @@ -39,8 +39,8 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamPathTemplate = "/", UpstreamHttpMethod = "Get", - RequestIdKey = _steps.RequestIdKey - } + RequestIdKey = _steps.RequestIdKey, + } } }; @@ -67,7 +67,7 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", UpstreamPathTemplate = "/", UpstreamHttpMethod = "Get", - RequestIdKey = _steps.RequestIdKey + } } }; diff --git a/test/Ocelot.AcceptanceTests/RoutingTests.cs b/test/Ocelot.AcceptanceTests/RoutingTests.cs index 14f5af8a..58e65bff 100644 --- a/test/Ocelot.AcceptanceTests/RoutingTests.cs +++ b/test/Ocelot.AcceptanceTests/RoutingTests.cs @@ -46,6 +46,7 @@ namespace Ocelot.AcceptanceTests DownstreamPort = 51879, UpstreamPathTemplate = "/", UpstreamHttpMethod = "Get", + } } }; @@ -74,6 +75,7 @@ namespace Ocelot.AcceptanceTests DownstreamPort = 51879, UpstreamPathTemplate = "/", UpstreamHttpMethod = "Get", + } } }; @@ -102,6 +104,7 @@ namespace Ocelot.AcceptanceTests DownstreamPort = 51879, UpstreamPathTemplate = "/", UpstreamHttpMethod = "Get", + } } }; @@ -130,6 +133,7 @@ namespace Ocelot.AcceptanceTests DownstreamPort = 51879, UpstreamPathTemplate = "/products/", UpstreamHttpMethod = "Get", + } } }; @@ -177,17 +181,23 @@ namespace Ocelot.AcceptanceTests var configuration = new FileConfiguration { ReRoutes = new List + { + new FileReRoute { - new FileReRoute + DownstreamPathTemplate = "/products", + DownstreamScheme = "http", + DownstreamHost = "localhost", + DownstreamPort = 51879, + UpstreamPathTemplate = "/products/{productId}", + UpstreamHttpMethod = "Get", + QoSOptions = new FileQoSOptions() { - DownstreamPathTemplate = "/products", - DownstreamScheme = "http", - DownstreamHost = "localhost", - DownstreamPort = 51879, - UpstreamPathTemplate = "/products/{productId}", - UpstreamHttpMethod = "Get", + ExceptionsAllowedBeforeBreaking = 3, + DurationOfBreak = 5, + TimeoutValue = 5000 } } + } }; this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/products", 200, "Hello from Laura")) @@ -212,7 +222,7 @@ namespace Ocelot.AcceptanceTests DownstreamHost = "localhost", DownstreamPort = 51879, UpstreamPathTemplate = "/products/{productId}", - UpstreamHttpMethod = "Get" + UpstreamHttpMethod = "Get", } } }; @@ -240,7 +250,7 @@ namespace Ocelot.AcceptanceTests DownstreamPort = 51879, DownstreamScheme = "http", UpstreamPathTemplate = "/", - UpstreamHttpMethod = "Post" + UpstreamHttpMethod = "Post", } } }; diff --git a/test/Ocelot.AcceptanceTests/configuration.json b/test/Ocelot.AcceptanceTests/configuration.json deleted file mode 100755 index aa2ba18f..00000000 --- a/test/Ocelot.AcceptanceTests/configuration.json +++ /dev/null @@ -1 +0,0 @@ -{"ReRoutes":[{"DownstreamPathTemplate":"41879/","UpstreamPathTemplate":"/","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,"LoadBalancer":null}],"GlobalConfiguration":{"RequestIdKey":null,"ServiceDiscoveryProvider":{"Provider":null,"Host":null,"Port":0}}} diff --git a/test/Ocelot.ManualTest/configuration.json b/test/Ocelot.ManualTest/configuration.json index f7e2bb75..9b5fcb7e 100644 --- a/test/Ocelot.ManualTest/configuration.json +++ b/test/Ocelot.ManualTest/configuration.json @@ -1,211 +1,305 @@ { - "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": "/posts", - "DownstreamScheme": "http", - "DownstreamHost": "jsonplaceholder.typicode.com", - "DownstreamPort": 80, - "UpstreamTemplate": "/posts", - "UpstreamHttpMethod": "Get", - "FileCacheOptions": { "TtlSeconds": 15 } - }, - { - "DownstreamPathTemplate": "/posts/{postId}", - "DownstreamScheme": "http", - "DownstreamHost": "jsonplaceholder.typicode.com", - "DownstreamPort": 80, - "UpstreamTemplate": "/posts/{postId}", - "UpstreamHttpMethod": "Get" - }, - { - "DownstreamPathTemplate": "/posts/{postId}/comments", - "DownstreamScheme": "http", - "DownstreamHost": "jsonplaceholder.typicode.com", - "DownstreamPort": 80, - "UpstreamTemplate": "/posts/{postId}/comments", - "UpstreamHttpMethod": "Get" - }, - { - "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 } - }, - { - "DownstreamPathTemplate": "/api/products/{productId}", - "DownstreamScheme": "http", - "DownstreamHost": "jsonplaceholder.typicode.com", - "DownstreamPort": 80, - "UpstreamTemplate": "/products/{productId}", - "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 } - } - ], - "GlobalConfiguration": { - "RequestIdKey": "OcRequestId" + "ReRoutes": [ + { + "DownstreamPathTemplate": "/", + "DownstreamScheme": "http", + "DownstreamHost": "localhost", + "DownstreamPort": 52876, + "UpstreamTemplate": "/identityserverexample", + "UpstreamHttpMethod": "Get", + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + }, + "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": "/posts", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamTemplate": "/posts", + "UpstreamHttpMethod": "Get", + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + } + }, + { + "DownstreamPathTemplate": "/posts/{postId}", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamTemplate": "/posts/{postId}", + "UpstreamHttpMethod": "Get", + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + } + }, + { + "DownstreamPathTemplate": "/posts/{postId}/comments", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamTemplate": "/posts/{postId}/comments", + "UpstreamHttpMethod": "Get", + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + } + }, + { + "DownstreamPathTemplate": "/comments", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamTemplate": "/comments", + "UpstreamHttpMethod": "Get", + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + } + }, + { + "DownstreamPathTemplate": "/posts", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamTemplate": "/posts", + "UpstreamHttpMethod": "Post", + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + } + }, + { + "DownstreamPathTemplate": "/posts/{postId}", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamTemplate": "/posts/{postId}", + "UpstreamHttpMethod": "Put", + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + } + }, + { + "DownstreamPathTemplate": "/posts/{postId}", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamTemplate": "/posts/{postId}", + "UpstreamHttpMethod": "Patch", + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + } + }, + { + "DownstreamPathTemplate": "/posts/{postId}", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamTemplate": "/posts/{postId}", + "UpstreamHttpMethod": "Delete", + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + } + }, + { + "DownstreamPathTemplate": "/api/products", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamTemplate": "/products", + "UpstreamHttpMethod": "Get", + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + }, + "FileCacheOptions": { "TtlSeconds": 15 } + }, + { + "DownstreamPathTemplate": "/api/products/{productId}", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamTemplate": "/products/{productId}", + "UpstreamHttpMethod": "Get", + "FileCacheOptions": { "TtlSeconds": 15 } + }, + { + "DownstreamPathTemplate": "/api/products", + "DownstreamScheme": "http", + "DownstreamHost": "products20161126090340.azurewebsites.net", + "DownstreamPort": 80, + "UpstreamTemplate": "/products", + "UpstreamHttpMethod": "Post", + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + } + }, + { + "DownstreamPathTemplate": "/api/products/{productId}", + "DownstreamScheme": "http", + "DownstreamHost": "products20161126090340.azurewebsites.net", + "DownstreamPort": 80, + "UpstreamTemplate": "/products/{productId}", + "UpstreamHttpMethod": "Put", + "QoSOptions": { + "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", + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + }, + "FileCacheOptions": { "TtlSeconds": 15 } + }, + { + "DownstreamPathTemplate": "/api/customers", + "DownstreamScheme": "http", + "DownstreamHost": "customers20161126090811.azurewebsites.net", + "DownstreamPort": 80, + "UpstreamTemplate": "/customers", + "UpstreamHttpMethod": "Get", + "QoSOptions": { + "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", + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + }, + "FileCacheOptions": { "TtlSeconds": 15 } + }, + { + "DownstreamPathTemplate": "/api/customers", + "DownstreamScheme": "http", + "DownstreamHost": "customers20161126090811.azurewebsites.net", + "DownstreamPort": 80, + "UpstreamTemplate": "/customers", + "UpstreamHttpMethod": "Post", + "QoSOptions": { + "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", + "QoSOptions": { + "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", + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + }, + "FileCacheOptions": { "TtlSeconds": 15 } + }, + { + "DownstreamPathTemplate": "/posts", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, + "UpstreamTemplate": "/posts/", + "UpstreamHttpMethod": "Get", + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 3, + "DurationOfBreak": 10, + "TimeoutValue": 5000 + }, + "FileCacheOptions": { "TtlSeconds": 15 } } + ], + + "GlobalConfiguration": { + "RequestIdKey": "OcRequestId" + } } \ No newline at end of file diff --git a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs index 1d544366..e76f3c2f 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs @@ -29,7 +29,6 @@ namespace Ocelot.UnitTests.LoadBalancer private readonly HttpClient _client; private HttpResponseMessage _result; private HostAndPort _hostAndPort; - private OkResponse _request; private OkResponse _downstreamUrl; private OkResponse _downstreamRoute; private ErrorResponse _getLoadBalancerHouseError; diff --git a/test/Ocelot.UnitTests/Request/HttpRequestBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/Request/HttpRequestBuilderMiddlewareTests.cs index b46877db..da5d2031 100644 --- a/test/Ocelot.UnitTests/Request/HttpRequestBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Request/HttpRequestBuilderMiddlewareTests.cs @@ -19,6 +19,7 @@ using Ocelot.Request.Middleware; using Ocelot.Responses; using TestStack.BDDfy; using Xunit; +using Ocelot.Configuration; namespace Ocelot.UnitTests.Request { @@ -74,7 +75,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(), true, new QoSOptions(3, 8 ,5000, Polly.Timeout.TimeoutStrategy.Pessimistic)))) .When(x => x.WhenICallTheMiddleware()) .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) .BDDfy(); @@ -93,7 +94,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(), It.IsAny())) .ReturnsAsync(_request); } diff --git a/test/Ocelot.UnitTests/Request/RequestBuilderTests.cs b/test/Ocelot.UnitTests/Request/RequestBuilderTests.cs index 3a07532e..c317c8d7 100644 --- a/test/Ocelot.UnitTests/Request/RequestBuilderTests.cs +++ b/test/Ocelot.UnitTests/Request/RequestBuilderTests.cs @@ -10,6 +10,7 @@ using Ocelot.Responses; using Shouldly; using TestStack.BDDfy; using Xunit; +using Ocelot.Configuration; namespace Ocelot.UnitTests.Request { @@ -25,6 +26,8 @@ namespace Ocelot.UnitTests.Request private readonly IRequestCreator _requestCreator; private Response _result; private Ocelot.RequestId.RequestId _requestId; + private bool _isQos; + private QoSOptions _qos; public RequestBuilderTests() { @@ -37,6 +40,7 @@ namespace Ocelot.UnitTests.Request { this.Given(x => x.GivenIHaveHttpMethod("GET")) .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) + .And(x=> x.GivenTheQos(true,new QoSOptions(3, 8, 5000, Polly.Timeout.TimeoutStrategy.Pessimistic))) .When(x => x.WhenICreateARequest()) .And(x => x.ThenTheCorrectDownstreamUrlIsUsed("http://www.bbc.co.uk/")) .BDDfy(); @@ -47,6 +51,8 @@ namespace Ocelot.UnitTests.Request { this.Given(x => x.GivenIHaveHttpMethod("POST")) .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) + .And(x => x.GivenTheQos(true,new QoSOptions(3, 8, 5000, Polly.Timeout.TimeoutStrategy.Pessimistic))) + .When(x => x.WhenICreateARequest()) .And(x => x.ThenTheCorrectHttpMethodIsUsed(HttpMethod.Post)) .BDDfy(); @@ -59,7 +65,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(true, new QoSOptions(3, 8, 5000, Polly.Timeout.TimeoutStrategy.Pessimistic))) + + .When(x => x.WhenICreateARequest()) .And(x => x.ThenTheCorrectContentIsUsed(new StringContent("Hi from Tom"))) .BDDfy(); } @@ -71,6 +79,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(true, new QoSOptions(3, 8, 5000, Polly.Timeout.TimeoutStrategy.Pessimistic))) + .When(x => x.WhenICreateARequest()) .And(x => x.ThenTheCorrectContentHeadersAreUsed(new HeaderDictionary { @@ -88,6 +98,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(true, new QoSOptions(3, 8, 5000, Polly.Timeout.TimeoutStrategy.Pessimistic))) + .When(x => x.WhenICreateARequest()) .And(x => x.ThenTheCorrectContentHeadersAreUsed(new HeaderDictionary { @@ -107,6 +119,8 @@ namespace Ocelot.UnitTests.Request { {"ChopSticks", "Bubbles" } })) + .And(x => x.GivenTheQos(true, new QoSOptions(3, 8, 5000, Polly.Timeout.TimeoutStrategy.Pessimistic))) + .When(x => x.WhenICreateARequest()) .And(x => x.ThenTheCorrectHeadersAreUsed(new HeaderDictionary { @@ -124,7 +138,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(true, new QoSOptions(3, 8, 5000, Polly.Timeout.TimeoutStrategy.Pessimistic))) + .When(x => x.WhenICreateARequest()) .And(x => x.ThenTheCorrectHeadersAreUsed(new HeaderDictionary { {"RequestId", requestId } @@ -142,7 +157,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(true, new QoSOptions(3, 8, 5000, Polly.Timeout.TimeoutStrategy.Pessimistic))) + .When(x => x.WhenICreateARequest()) .And(x => x.ThenTheCorrectHeadersAreUsed(new HeaderDictionary { {"RequestId", "534534gv54gv45g" } @@ -161,7 +177,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(true, new QoSOptions(3, 8, 5000, Polly.Timeout.TimeoutStrategy.Pessimistic))) + .When(x => x.WhenICreateARequest()) .And(x => x.ThenTheRequestIdIsNotInTheHeaders()) .BDDfy(); } @@ -171,6 +188,12 @@ namespace Ocelot.UnitTests.Request _requestId = requestId; } + private void GivenTheQos(bool isQos, QoSOptions qos) + { + _isQos = isQos; + _qos = qos; + } + [Fact] public void should_use_cookies() { @@ -281,7 +304,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,_isQos,_qos).Result; } diff --git a/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs b/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs index d99a99eb..d2d62923 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(),true, new Ocelot.Configuration.QoSOptions(3, 8, 5000, Polly.Timeout.TimeoutStrategy.Pessimistic)))) .And(x => x.GivenTheRequesterReturns(new HttpResponseMessage())) .And(x => x.GivenTheScopedRepoReturns()) .When(x => x.WhenICallTheMiddleware()) diff --git a/test/Ocelot.UnitTests/ServiceDiscovery/ConfigurationServiceProviderTests.cs b/test/Ocelot.UnitTests/ServiceDiscovery/ConfigurationServiceProviderTests.cs index f1e732e7..282f8ec1 100644 --- a/test/Ocelot.UnitTests/ServiceDiscovery/ConfigurationServiceProviderTests.cs +++ b/test/Ocelot.UnitTests/ServiceDiscovery/ConfigurationServiceProviderTests.cs @@ -10,7 +10,6 @@ namespace Ocelot.UnitTests.ServiceDiscovery public class ConfigurationServiceProviderTests { private ConfigurationServiceProvider _serviceProvider; - private HostAndPort _hostAndPort; private List _result; private List _expected;