Merge pull request #27 from geffzhang/CircuitBreakerPattern

Circuit breaker pattern
This commit is contained in:
Tom Pallister 2017-02-09 19:32:23 +00:00 committed by GitHub
commit ce83c7dfff
28 changed files with 664 additions and 295 deletions

View File

@ -36,6 +36,9 @@ namespace Ocelot.Configuration.Builder
private string _loadBalancer; private string _loadBalancer;
private string _serviceProviderHost; private string _serviceProviderHost;
private int _serviceProviderPort; private int _serviceProviderPort;
private bool _useQos;
private QoSOptions _qosOptions;
public ReRouteBuilder() public ReRouteBuilder()
{ {
@ -202,6 +205,19 @@ namespace Ocelot.Configuration.Builder
return this; 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) public ReRouteBuilder WithLoadBalancerKey(string loadBalancerKey)
{ {
_loadBalancerKey = loadBalancerKey; _loadBalancerKey = loadBalancerKey;
@ -226,7 +242,10 @@ namespace Ocelot.Configuration.Builder
_isAuthenticated, new AuthenticationOptions(_authenticationProvider, _authenticationProviderUrl, _scopeName, _isAuthenticated, new AuthenticationOptions(_authenticationProvider, _authenticationProviderUrl, _scopeName,
_requireHttps, _additionalScopes, _scopeSecret), _configHeaderExtractorProperties, _claimToClaims, _routeClaimRequirement, _requireHttps, _additionalScopes, _scopeSecret), _configHeaderExtractorProperties, _claimToClaims, _routeClaimRequirement,
_isAuthorised, _claimToQueries, _requestIdHeaderKey, _isCached, _fileCacheOptions, _downstreamScheme, _loadBalancer, _isAuthorised, _claimToQueries, _requestIdHeaderKey, _isCached, _fileCacheOptions, _downstreamScheme, _loadBalancer,
_downstreamHost, _dsPort, _loadBalancerKey, new ServiceProviderConfiguraion(_serviceName, _downstreamHost, _dsPort, _useServiceDiscovery, _serviceDiscoveryProvider, _serviceProviderHost, _serviceProviderPort)); _downstreamHost, _dsPort, _loadBalancerKey, new ServiceProviderConfiguraion(_serviceName, _downstreamHost, _dsPort, _useServiceDiscovery,
_serviceDiscoveryProvider, _serviceProviderHost, _serviceProviderPort),
_useQos,_qosOptions);
} }
} }
} }

View File

@ -96,6 +96,8 @@ namespace Ocelot.Configuration.Creator
var isCached = fileReRoute.FileCacheOptions.TtlSeconds > 0; var isCached = fileReRoute.FileCacheOptions.TtlSeconds > 0;
var isQos = fileReRoute.QoSOptions.ExceptionsAllowedBeforeBreaking > 0 && fileReRoute.QoSOptions.TimeoutValue >0;
var requestIdKey = globalRequestIdConfiguration var requestIdKey = globalRequestIdConfiguration
? globalConfiguration.RequestIdKey ? globalConfiguration.RequestIdKey
: fileReRoute.RequestIdKey; : fileReRoute.RequestIdKey;
@ -108,6 +110,7 @@ namespace Ocelot.Configuration.Creator
ReRoute reRoute; ReRoute reRoute;
var serviceProviderPort = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0; var serviceProviderPort = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0;
var serviceProviderConfiguration = new ServiceProviderConfiguraion(fileReRoute.ServiceName, var serviceProviderConfiguration = new ServiceProviderConfiguraion(fileReRoute.ServiceName,
@ -134,7 +137,8 @@ namespace Ocelot.Configuration.Creator
requestIdKey, isCached, new CacheOptions(fileReRoute.FileCacheOptions.TtlSeconds) requestIdKey, isCached, new CacheOptions(fileReRoute.FileCacheOptions.TtlSeconds)
, fileReRoute.DownstreamScheme, , fileReRoute.DownstreamScheme,
fileReRoute.LoadBalancer, fileReRoute.DownstreamHost, fileReRoute.DownstreamPort, loadBalancerKey, fileReRoute.LoadBalancer, fileReRoute.DownstreamHost, fileReRoute.DownstreamPort, loadBalancerKey,
serviceProviderConfiguration); serviceProviderConfiguration, isQos,
new QoSOptions(fileReRoute.QoSOptions.ExceptionsAllowedBeforeBreaking, fileReRoute.QoSOptions.DurationOfBreak, fileReRoute.QoSOptions.TimeoutValue));
} }
else else
{ {
@ -146,7 +150,8 @@ namespace Ocelot.Configuration.Creator
requestIdKey, isCached, new CacheOptions(fileReRoute.FileCacheOptions.TtlSeconds), requestIdKey, isCached, new CacheOptions(fileReRoute.FileCacheOptions.TtlSeconds),
fileReRoute.DownstreamScheme, fileReRoute.DownstreamScheme,
fileReRoute.LoadBalancer, fileReRoute.DownstreamHost, fileReRoute.DownstreamPort, loadBalancerKey, fileReRoute.LoadBalancer, fileReRoute.DownstreamHost, fileReRoute.DownstreamPort, loadBalancerKey,
serviceProviderConfiguration); serviceProviderConfiguration, isQos,
new QoSOptions(fileReRoute.QoSOptions.ExceptionsAllowedBeforeBreaking, fileReRoute.QoSOptions.DurationOfBreak, fileReRoute.QoSOptions.TimeoutValue));
} }
var loadBalancer = await _loadBalanceFactory.Get(reRoute); var loadBalancer = await _loadBalanceFactory.Get(reRoute);

View File

@ -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; }
}
}

View File

@ -12,6 +12,7 @@ namespace Ocelot.Configuration.File
AddQueriesToRequest = new Dictionary<string, string>(); AddQueriesToRequest = new Dictionary<string, string>();
AuthenticationOptions = new FileAuthenticationOptions(); AuthenticationOptions = new FileAuthenticationOptions();
FileCacheOptions = new FileCacheOptions(); FileCacheOptions = new FileCacheOptions();
QoSOptions = new FileQoSOptions();
} }
public string DownstreamPathTemplate { get; set; } public string DownstreamPathTemplate { get; set; }
@ -29,6 +30,7 @@ namespace Ocelot.Configuration.File
public string DownstreamScheme {get;set;} public string DownstreamScheme {get;set;}
public string DownstreamHost {get;set;} public string DownstreamHost {get;set;}
public int DownstreamPort { get; set; } public int DownstreamPort { get; set; }
public FileQoSOptions QoSOptions { get; set; }
public string LoadBalancer {get;set;} public string LoadBalancer {get;set;}
} }
} }

View File

@ -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; }
}
}

View File

@ -16,7 +16,8 @@ namespace Ocelot.Configuration
List<ClaimToThing> claimsToQueries, List<ClaimToThing> claimsToQueries,
string requestIdKey, bool isCached, CacheOptions fileCacheOptions, string requestIdKey, bool isCached, CacheOptions fileCacheOptions,
string downstreamScheme, string loadBalancer, string downstreamHost, string downstreamScheme, string loadBalancer, string downstreamHost,
int downstreamPort, string loadBalancerKey, ServiceProviderConfiguraion serviceProviderConfiguraion) int downstreamPort, string loadBalancerKey, ServiceProviderConfiguraion serviceProviderConfiguraion,
bool isQos,QoSOptions qos)
{ {
LoadBalancerKey = loadBalancerKey; LoadBalancerKey = loadBalancerKey;
ServiceProviderConfiguraion = serviceProviderConfiguraion; ServiceProviderConfiguraion = serviceProviderConfiguraion;
@ -41,6 +42,8 @@ namespace Ocelot.Configuration
ClaimsToHeaders = configurationHeaderExtractorProperties ClaimsToHeaders = configurationHeaderExtractorProperties
?? new List<ClaimToThing>(); ?? new List<ClaimToThing>();
DownstreamScheme = downstreamScheme; DownstreamScheme = downstreamScheme;
IsQos = isQos;
QosOptions = qos;
} }
public string LoadBalancerKey {get;private set;} public string LoadBalancerKey {get;private set;}
@ -59,6 +62,8 @@ namespace Ocelot.Configuration
public bool IsCached { get; private set; } public bool IsCached { get; private set; }
public CacheOptions FileCacheOptions { get; private set; } public CacheOptions FileCacheOptions { get; private set; }
public string DownstreamScheme {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 LoadBalancer {get;private set;}
public string DownstreamHost { get; private set; } public string DownstreamHost { get; private set; }
public int DownstreamPort { get; private set; } public int DownstreamPort { get; private set; }

View File

@ -2,6 +2,7 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Ocelot.Responses; using Ocelot.Responses;
using Ocelot.Configuration;
namespace Ocelot.Request.Builder namespace Ocelot.Request.Builder
{ {
@ -15,7 +16,9 @@ namespace Ocelot.Request.Builder
IRequestCookieCollection cookies, IRequestCookieCollection cookies,
QueryString queryString, QueryString queryString,
string contentType, string contentType,
RequestId.RequestId requestId) RequestId.RequestId requestId,
bool isQos,
QoSOptions qos)
{ {
var request = await new RequestBuilder() var request = await new RequestBuilder()
.WithHttpMethod(httpMethod) .WithHttpMethod(httpMethod)
@ -26,6 +29,8 @@ namespace Ocelot.Request.Builder
.WithHeaders(headers) .WithHeaders(headers)
.WithRequestId(requestId) .WithRequestId(requestId)
.WithCookies(cookies) .WithCookies(cookies)
.WithIsQos(isQos)
.WithQos(qos)
.Build(); .Build();
return new OkResponse<Request>(request); return new OkResponse<Request>(request);

View File

@ -2,6 +2,7 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Ocelot.Responses; using Ocelot.Responses;
using Ocelot.Configuration;
namespace Ocelot.Request.Builder namespace Ocelot.Request.Builder
{ {
@ -14,6 +15,8 @@ namespace Ocelot.Request.Builder
IRequestCookieCollection cookies, IRequestCookieCollection cookies,
QueryString queryString, QueryString queryString,
string contentType, string contentType,
RequestId.RequestId requestId); RequestId.RequestId requestId,
bool isQos,
QoSOptions qos);
} }
} }

View File

@ -8,6 +8,7 @@ using System.Net.Http.Headers;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using Ocelot.Configuration;
namespace Ocelot.Request.Builder namespace Ocelot.Request.Builder
{ {
@ -22,6 +23,8 @@ namespace Ocelot.Request.Builder
private RequestId.RequestId _requestId; private RequestId.RequestId _requestId;
private IRequestCookieCollection _cookies; private IRequestCookieCollection _cookies;
private readonly string[] _unsupportedHeaders = {"host"}; private readonly string[] _unsupportedHeaders = {"host"};
private bool _isQos;
private QoSOptions _qos;
public RequestBuilder WithHttpMethod(string httpMethod) public RequestBuilder WithHttpMethod(string httpMethod)
{ {
@ -71,6 +74,18 @@ namespace Ocelot.Request.Builder
return this; return this;
} }
public RequestBuilder WithIsQos(bool isqos)
{
_isQos = isqos;
return this;
}
public RequestBuilder WithQos(QoSOptions qos)
{
_qos = qos;
return this;
}
public async Task<Request> Build() public async Task<Request> Build()
{ {
var uri = CreateUri(); var uri = CreateUri();
@ -90,7 +105,7 @@ namespace Ocelot.Request.Builder
var cookieContainer = CreateCookieContainer(uri); var cookieContainer = CreateCookieContainer(uri);
return new Request(httpRequestMessage, cookieContainer); return new Request(httpRequestMessage, cookieContainer,_isQos,_qos);
} }
private Uri CreateUri() private Uri CreateUri()

View File

@ -32,7 +32,8 @@ namespace Ocelot.Request.Middleware
var buildResult = await _requestCreator var buildResult = await _requestCreator
.Build(context.Request.Method, DownstreamUrl, context.Request.Body, .Build(context.Request.Method, DownstreamUrl, context.Request.Body,
context.Request.Headers, context.Request.Cookies, context.Request.QueryString, 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) if (buildResult.IsError)
{ {

View File

@ -1,17 +1,23 @@
using System.Net; using Ocelot.Configuration;
using Ocelot.Values;
using System.Net;
using System.Net.Http; using System.Net.Http;
namespace Ocelot.Request namespace Ocelot.Request
{ {
public class Request public class Request
{ {
public Request(HttpRequestMessage httpRequestMessage, CookieContainer cookieContainer) public Request(HttpRequestMessage httpRequestMessage, CookieContainer cookieContainer,bool isQos, QoSOptions qos)
{ {
HttpRequestMessage = httpRequestMessage; HttpRequestMessage = httpRequestMessage;
CookieContainer = cookieContainer; CookieContainer = cookieContainer;
IsQos = isQos;
Qos = qos;
} }
public HttpRequestMessage HttpRequestMessage { get; private set; } public HttpRequestMessage HttpRequestMessage { get; private set; }
public CookieContainer CookieContainer { get; private set; } public CookieContainer CookieContainer { get; private set; }
public bool IsQos { get; private set; }
public QoSOptions Qos { get; private set; }
} }
} }

View File

@ -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<HttpRequestException>()
.Or<TimeoutRejectedException>()
.Or<TimeoutException>()
.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<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
Task<HttpResponseMessage> responseTask = null;
try
{
responseTask = Policy.WrapAsync(_circuitBreakerPolicy, _timeoutPolicy).ExecuteAsync<HttpResponseMessage>(() =>
{
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;
}
}
}

View File

@ -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<int, Func<DelegatingHandler>> handlers = new Dictionary<int, Func<DelegatingHandler>>();
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;
}
}
}

View File

@ -4,15 +4,30 @@ using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ocelot.Errors; using Ocelot.Errors;
using Ocelot.Responses; using Ocelot.Responses;
using Ocelot.Logging;
namespace Ocelot.Requester namespace Ocelot.Requester
{ {
public class HttpClientHttpRequester : IHttpRequester public class HttpClientHttpRequester : IHttpRequester
{ {
private readonly IOcelotLogger _logger;
public HttpClientHttpRequester(IOcelotLoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<HttpClientHttpRequester>();
}
public async Task<Response<HttpResponseMessage>> GetResponse(Request.Request request) public async Task<Response<HttpResponseMessage>> GetResponse(Request.Request request)
{ {
HttpClientBuilder builder = new HttpClientBuilder();
using (var handler = new HttpClientHandler { CookieContainer = request.CookieContainer }) using (var handler = new HttpClientHandler { CookieContainer = request.CookieContainer })
using (var httpClient = new HttpClient(handler)) {
if (request.IsQos)
{
builder.WithCircuitBreaker(request.Qos, _logger, handler);
}
using (var httpClient = builder.Build(handler))
{ {
try try
{ {
@ -31,3 +46,4 @@ namespace Ocelot.Requester
} }
} }
} }
}

View File

@ -7,5 +7,7 @@ namespace Ocelot.Requester
public interface IHttpRequester public interface IHttpRequester
{ {
Task<Response<HttpResponseMessage>> GetResponse(Request.Request request); Task<Response<HttpResponseMessage>> GetResponse(Request.Request request);
} }
} }

View File

@ -1,6 +1,5 @@
{ {
"version": "0.0.0-dev", "version": "0.0.0-dev",
"dependencies": { "dependencies": {
"Microsoft.AspNetCore.Server.IISIntegration": "1.1.0", "Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0", "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0",
@ -28,7 +27,8 @@
"CacheManager.Core": "0.9.2", "CacheManager.Core": "0.9.2",
"CacheManager.Microsoft.Extensions.Configuration": "0.9.2", "CacheManager.Microsoft.Extensions.Configuration": "0.9.2",
"CacheManager.Microsoft.Extensions.Logging": "0.9.2", "CacheManager.Microsoft.Extensions.Logging": "0.9.2",
"Consul": "0.7.2.1" "Consul": "0.7.2.1",
"Polly": "5.0.3"
}, },
"runtimes": { "runtimes": {
"win10-x64": {}, "win10-x64": {},

View File

@ -165,6 +165,7 @@ namespace Ocelot.AcceptanceTests
DownstreamScheme = _downstreamServiceScheme, DownstreamScheme = _downstreamServiceScheme,
UpstreamTemplate = "/", UpstreamTemplate = "/",
UpstreamHttpMethod = "Post", UpstreamHttpMethod = "Post",
AuthenticationOptions = new FileAuthenticationOptions AuthenticationOptions = new FileAuthenticationOptions
{ {
AdditionalScopes = new List<string>(), AdditionalScopes = new List<string>(),

View File

@ -35,7 +35,7 @@ namespace Ocelot.AcceptanceTests
DownstreamScheme = "http", DownstreamScheme = "http",
DownstreamHost = "localhost", DownstreamHost = "localhost",
UpstreamTemplate = "/products/{productId}", UpstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get" UpstreamHttpMethod = "Get",
} }
} }
}; };
@ -63,7 +63,7 @@ namespace Ocelot.AcceptanceTests
DownstreamHost = "localhost", DownstreamHost = "localhost",
UpstreamTemplate = "/products/{productId}", UpstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get", UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = false ReRouteIsCaseSensitive = false,
} }
} }
}; };
@ -91,7 +91,7 @@ namespace Ocelot.AcceptanceTests
DownstreamHost = "localhost", DownstreamHost = "localhost",
UpstreamTemplate = "/products/{productId}", UpstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get", UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true ReRouteIsCaseSensitive = true,
} }
} }
}; };
@ -119,7 +119,7 @@ namespace Ocelot.AcceptanceTests
DownstreamHost = "localhost", DownstreamHost = "localhost",
UpstreamTemplate = "/PRODUCTS/{productId}", UpstreamTemplate = "/PRODUCTS/{productId}",
UpstreamHttpMethod = "Get", UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true ReRouteIsCaseSensitive = true,
} }
} }
}; };
@ -147,7 +147,7 @@ namespace Ocelot.AcceptanceTests
DownstreamHost = "localhost", DownstreamHost = "localhost",
UpstreamTemplate = "/products/{productId}", UpstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get", UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true ReRouteIsCaseSensitive = true,
} }
} }
}; };
@ -175,7 +175,7 @@ namespace Ocelot.AcceptanceTests
DownstreamHost = "localhost", DownstreamHost = "localhost",
UpstreamTemplate = "/PRODUCTS/{productId}", UpstreamTemplate = "/PRODUCTS/{productId}",
UpstreamHttpMethod = "Get", UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true ReRouteIsCaseSensitive = true,
} }
} }
}; };

View File

@ -88,6 +88,7 @@ namespace Ocelot.AcceptanceTests
DownstreamHost = "localhost", DownstreamHost = "localhost",
UpstreamTemplate = "/", UpstreamTemplate = "/",
UpstreamHttpMethod = "Get", UpstreamHttpMethod = "Get",
} }
} }
}; };
@ -125,6 +126,7 @@ namespace Ocelot.AcceptanceTests
DownstreamHost = "localhost", DownstreamHost = "localhost",
UpstreamTemplate = "/", UpstreamTemplate = "/",
UpstreamHttpMethod = "Get", UpstreamHttpMethod = "Get",
} }
} }
}; };

View File

@ -39,7 +39,7 @@ namespace Ocelot.AcceptanceTests
DownstreamHost = "localhost", DownstreamHost = "localhost",
UpstreamTemplate = "/", UpstreamTemplate = "/",
UpstreamHttpMethod = "Get", UpstreamHttpMethod = "Get",
RequestIdKey = _steps.RequestIdKey RequestIdKey = _steps.RequestIdKey,
} }
} }
}; };
@ -67,7 +67,7 @@ namespace Ocelot.AcceptanceTests
DownstreamHost = "localhost", DownstreamHost = "localhost",
UpstreamTemplate = "/", UpstreamTemplate = "/",
UpstreamHttpMethod = "Get", UpstreamHttpMethod = "Get",
RequestIdKey = _steps.RequestIdKey
} }
} }
}; };
@ -96,7 +96,7 @@ namespace Ocelot.AcceptanceTests
DownstreamScheme = "http", DownstreamScheme = "http",
DownstreamHost = "localhost", DownstreamHost = "localhost",
UpstreamTemplate = "/", UpstreamTemplate = "/",
UpstreamHttpMethod = "Get", UpstreamHttpMethod ="Get"
} }
}, },
GlobalConfiguration = new FileGlobalConfiguration GlobalConfiguration = new FileGlobalConfiguration

View File

@ -46,6 +46,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 51879, DownstreamPort = 51879,
UpstreamTemplate = "/", UpstreamTemplate = "/",
UpstreamHttpMethod = "Get", UpstreamHttpMethod = "Get",
} }
} }
}; };
@ -74,6 +75,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 51879, DownstreamPort = 51879,
UpstreamTemplate = "/", UpstreamTemplate = "/",
UpstreamHttpMethod = "Get", UpstreamHttpMethod = "Get",
} }
} }
}; };
@ -102,6 +104,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 51879, DownstreamPort = 51879,
UpstreamTemplate = "/", UpstreamTemplate = "/",
UpstreamHttpMethod = "Get", UpstreamHttpMethod = "Get",
} }
} }
}; };
@ -130,6 +133,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 51879, DownstreamPort = 51879,
UpstreamTemplate = "/products/", UpstreamTemplate = "/products/",
UpstreamHttpMethod = "Get", UpstreamHttpMethod = "Get",
} }
} }
}; };
@ -158,6 +162,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 51879, DownstreamPort = 51879,
UpstreamTemplate = "/products", UpstreamTemplate = "/products",
UpstreamHttpMethod = "Get", UpstreamHttpMethod = "Get",
} }
} }
}; };
@ -186,6 +191,11 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 51879, DownstreamPort = 51879,
UpstreamTemplate = "/products/{productId}", UpstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get", UpstreamHttpMethod = "Get",
QoSOptions = new FileQoSOptions()
{
ExceptionsAllowedBeforeBreaking = 3,
DurationOfBreak =5,
TimeoutValue = 5000 }
} }
} }
}; };
@ -212,7 +222,7 @@ namespace Ocelot.AcceptanceTests
DownstreamHost = "localhost", DownstreamHost = "localhost",
DownstreamPort = 51879, DownstreamPort = 51879,
UpstreamTemplate = "/products/{productId}", UpstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get" UpstreamHttpMethod = "Get",
} }
} }
}; };
@ -240,7 +250,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 51879, DownstreamPort = 51879,
DownstreamScheme = "http", DownstreamScheme = "http",
UpstreamTemplate = "/", UpstreamTemplate = "/",
UpstreamHttpMethod = "Post" UpstreamHttpMethod = "Post",
} }
} }
}; };

View File

@ -1 +1 @@
{"ReRoutes":[{"DownstreamPathTemplate":"41879/","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,"LoadBalancer":null}],"GlobalConfiguration":{"RequestIdKey":null,"ServiceDiscoveryProvider":{"Provider":null,"Host":null,"Port":0}}} {"ReRoutes":[{"DownstreamPathTemplate":"41879/","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,"QoSOptions":{"ExceptionsAllowedBeforeBreaking":0,"DurationOfBreak":0,"TimeoutValue":0},"LoadBalancer":null}],"GlobalConfiguration":{"RequestIdKey":null,"ServiceDiscoveryProvider":{"Provider":null,"Host":null,"Port":0}}}

View File

@ -7,6 +7,11 @@
"DownstreamPort": 52876, "DownstreamPort": 52876,
"UpstreamTemplate": "/identityserverexample", "UpstreamTemplate": "/identityserverexample",
"UpstreamHttpMethod": "Get", "UpstreamHttpMethod": "Get",
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
},
"AuthenticationOptions": { "AuthenticationOptions": {
"Provider": "IdentityServer", "Provider": "IdentityServer",
"ProviderRootUrl": "http://localhost:52888", "ProviderRootUrl": "http://localhost:52888",
@ -47,7 +52,11 @@
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/posts", "UpstreamTemplate": "/posts",
"UpstreamHttpMethod": "Get", "UpstreamHttpMethod": "Get",
"FileCacheOptions": { "TtlSeconds": 15 } "QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
}, },
{ {
"DownstreamPathTemplate": "/posts/{postId}", "DownstreamPathTemplate": "/posts/{postId}",
@ -55,7 +64,12 @@
"DownstreamHost": "jsonplaceholder.typicode.com", "DownstreamHost": "jsonplaceholder.typicode.com",
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/posts/{postId}", "UpstreamTemplate": "/posts/{postId}",
"UpstreamHttpMethod": "Get" "UpstreamHttpMethod": "Get",
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
}, },
{ {
"DownstreamPathTemplate": "/posts/{postId}/comments", "DownstreamPathTemplate": "/posts/{postId}/comments",
@ -63,7 +77,12 @@
"DownstreamHost": "jsonplaceholder.typicode.com", "DownstreamHost": "jsonplaceholder.typicode.com",
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/posts/{postId}/comments", "UpstreamTemplate": "/posts/{postId}/comments",
"UpstreamHttpMethod": "Get" "UpstreamHttpMethod": "Get",
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
}, },
{ {
"DownstreamPathTemplate": "/comments", "DownstreamPathTemplate": "/comments",
@ -71,7 +90,12 @@
"DownstreamHost": "jsonplaceholder.typicode.com", "DownstreamHost": "jsonplaceholder.typicode.com",
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/comments", "UpstreamTemplate": "/comments",
"UpstreamHttpMethod": "Get" "UpstreamHttpMethod": "Get",
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
}, },
{ {
"DownstreamPathTemplate": "/posts", "DownstreamPathTemplate": "/posts",
@ -79,7 +103,12 @@
"DownstreamHost": "jsonplaceholder.typicode.com", "DownstreamHost": "jsonplaceholder.typicode.com",
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/posts", "UpstreamTemplate": "/posts",
"UpstreamHttpMethod": "Post" "UpstreamHttpMethod": "Post",
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
}, },
{ {
"DownstreamPathTemplate": "/posts/{postId}", "DownstreamPathTemplate": "/posts/{postId}",
@ -87,7 +116,12 @@
"DownstreamHost": "jsonplaceholder.typicode.com", "DownstreamHost": "jsonplaceholder.typicode.com",
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/posts/{postId}", "UpstreamTemplate": "/posts/{postId}",
"UpstreamHttpMethod": "Put" "UpstreamHttpMethod": "Put",
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
}, },
{ {
"DownstreamPathTemplate": "/posts/{postId}", "DownstreamPathTemplate": "/posts/{postId}",
@ -95,7 +129,12 @@
"DownstreamHost": "jsonplaceholder.typicode.com", "DownstreamHost": "jsonplaceholder.typicode.com",
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/posts/{postId}", "UpstreamTemplate": "/posts/{postId}",
"UpstreamHttpMethod": "Patch" "UpstreamHttpMethod": "Patch",
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
}, },
{ {
"DownstreamPathTemplate": "/posts/{postId}", "DownstreamPathTemplate": "/posts/{postId}",
@ -103,7 +142,12 @@
"DownstreamHost": "jsonplaceholder.typicode.com", "DownstreamHost": "jsonplaceholder.typicode.com",
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/posts/{postId}", "UpstreamTemplate": "/posts/{postId}",
"UpstreamHttpMethod": "Delete" "UpstreamHttpMethod": "Delete",
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
}, },
{ {
"DownstreamPathTemplate": "/api/products", "DownstreamPathTemplate": "/api/products",
@ -112,6 +156,11 @@
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/products", "UpstreamTemplate": "/products",
"UpstreamHttpMethod": "Get", "UpstreamHttpMethod": "Get",
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
},
"FileCacheOptions": { "TtlSeconds": 15 } "FileCacheOptions": { "TtlSeconds": 15 }
}, },
{ {
@ -130,7 +179,11 @@
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/products", "UpstreamTemplate": "/products",
"UpstreamHttpMethod": "Post", "UpstreamHttpMethod": "Post",
"FileCacheOptions": { "TtlSeconds": 15 } "QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
}, },
{ {
"DownstreamPathTemplate": "/api/products/{productId}", "DownstreamPathTemplate": "/api/products/{productId}",
@ -139,6 +192,11 @@
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/products/{productId}", "UpstreamTemplate": "/products/{productId}",
"UpstreamHttpMethod": "Put", "UpstreamHttpMethod": "Put",
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
},
"FileCacheOptions": { "TtlSeconds": 15 } "FileCacheOptions": { "TtlSeconds": 15 }
}, },
{ {
@ -148,6 +206,11 @@
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/products/{productId}", "UpstreamTemplate": "/products/{productId}",
"UpstreamHttpMethod": "Delete", "UpstreamHttpMethod": "Delete",
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
},
"FileCacheOptions": { "TtlSeconds": 15 } "FileCacheOptions": { "TtlSeconds": 15 }
}, },
{ {
@ -157,6 +220,11 @@
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/customers", "UpstreamTemplate": "/customers",
"UpstreamHttpMethod": "Get", "UpstreamHttpMethod": "Get",
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
},
"FileCacheOptions": { "TtlSeconds": 15 } "FileCacheOptions": { "TtlSeconds": 15 }
}, },
{ {
@ -166,6 +234,11 @@
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/customers/{customerId}", "UpstreamTemplate": "/customers/{customerId}",
"UpstreamHttpMethod": "Get", "UpstreamHttpMethod": "Get",
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
},
"FileCacheOptions": { "TtlSeconds": 15 } "FileCacheOptions": { "TtlSeconds": 15 }
}, },
{ {
@ -175,6 +248,11 @@
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/customers", "UpstreamTemplate": "/customers",
"UpstreamHttpMethod": "Post", "UpstreamHttpMethod": "Post",
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
},
"FileCacheOptions": { "TtlSeconds": 15 } "FileCacheOptions": { "TtlSeconds": 15 }
}, },
{ {
@ -184,6 +262,11 @@
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/customers/{customerId}", "UpstreamTemplate": "/customers/{customerId}",
"UpstreamHttpMethod": "Put", "UpstreamHttpMethod": "Put",
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
},
"FileCacheOptions": { "TtlSeconds": 15 } "FileCacheOptions": { "TtlSeconds": 15 }
}, },
{ {
@ -193,6 +276,11 @@
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/customers/{customerId}", "UpstreamTemplate": "/customers/{customerId}",
"UpstreamHttpMethod": "Delete", "UpstreamHttpMethod": "Delete",
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
},
"FileCacheOptions": { "TtlSeconds": 15 } "FileCacheOptions": { "TtlSeconds": 15 }
}, },
{ {
@ -202,9 +290,15 @@
"DownstreamPort": 80, "DownstreamPort": 80,
"UpstreamTemplate": "/posts/", "UpstreamTemplate": "/posts/",
"UpstreamHttpMethod": "Get", "UpstreamHttpMethod": "Get",
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
},
"FileCacheOptions": { "TtlSeconds": 15 } "FileCacheOptions": { "TtlSeconds": 15 }
} }
], ],
"GlobalConfiguration": { "GlobalConfiguration": {
"RequestIdKey": "OcRequestId" "RequestIdKey": "OcRequestId"
} }

View File

@ -29,7 +29,6 @@ namespace Ocelot.UnitTests.LoadBalancer
private readonly HttpClient _client; private readonly HttpClient _client;
private HttpResponseMessage _result; private HttpResponseMessage _result;
private HostAndPort _hostAndPort; private HostAndPort _hostAndPort;
private OkResponse<Ocelot.Request.Request> _request;
private OkResponse<string> _downstreamUrl; private OkResponse<string> _downstreamUrl;
private OkResponse<DownstreamRoute> _downstreamRoute; private OkResponse<DownstreamRoute> _downstreamRoute;
private ErrorResponse<ILoadBalancer> _getLoadBalancerHouseError; private ErrorResponse<ILoadBalancer> _getLoadBalancerHouseError;

View File

@ -19,6 +19,7 @@ using Ocelot.Request.Middleware;
using Ocelot.Responses; using Ocelot.Responses;
using TestStack.BDDfy; using TestStack.BDDfy;
using Xunit; using Xunit;
using Ocelot.Configuration;
namespace Ocelot.UnitTests.Request namespace Ocelot.UnitTests.Request
{ {
@ -72,7 +73,7 @@ namespace Ocelot.UnitTests.Request
this.Given(x => x.GivenTheDownStreamUrlIs("any old string")) this.Given(x => x.GivenTheDownStreamUrlIs("any old string"))
.And(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) .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()) .When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly())
.BDDfy(); .BDDfy();
@ -91,7 +92,7 @@ namespace Ocelot.UnitTests.Request
_request = new OkResponse<Ocelot.Request.Request>(request); _request = new OkResponse<Ocelot.Request.Request>(request);
_requestBuilder _requestBuilder
.Setup(x => x.Build(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<Stream>(), It.IsAny<IHeaderDictionary>(), .Setup(x => x.Build(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<Stream>(), It.IsAny<IHeaderDictionary>(),
It.IsAny<IRequestCookieCollection>(), It.IsAny<QueryString>(), It.IsAny<string>(), It.IsAny<Ocelot.RequestId.RequestId>())) It.IsAny<IRequestCookieCollection>(), It.IsAny<QueryString>(), It.IsAny<string>(), It.IsAny<Ocelot.RequestId.RequestId>(),It.IsAny<bool>(), It.IsAny<QoSOptions>()))
.ReturnsAsync(_request); .ReturnsAsync(_request);
} }

View File

@ -10,6 +10,7 @@ using Ocelot.Responses;
using Shouldly; using Shouldly;
using TestStack.BDDfy; using TestStack.BDDfy;
using Xunit; using Xunit;
using Ocelot.Configuration;
namespace Ocelot.UnitTests.Request namespace Ocelot.UnitTests.Request
{ {
@ -25,6 +26,8 @@ namespace Ocelot.UnitTests.Request
private readonly IRequestCreator _requestCreator; private readonly IRequestCreator _requestCreator;
private Response<Ocelot.Request.Request> _result; private Response<Ocelot.Request.Request> _result;
private Ocelot.RequestId.RequestId _requestId; private Ocelot.RequestId.RequestId _requestId;
private bool _isQos;
private QoSOptions _qos;
public RequestBuilderTests() public RequestBuilderTests()
{ {
@ -37,6 +40,7 @@ namespace Ocelot.UnitTests.Request
{ {
this.Given(x => x.GivenIHaveHttpMethod("GET")) this.Given(x => x.GivenIHaveHttpMethod("GET"))
.And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) .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()) .When(x => x.WhenICreateARequest())
.And(x => x.ThenTheCorrectDownstreamUrlIsUsed("http://www.bbc.co.uk/")) .And(x => x.ThenTheCorrectDownstreamUrlIsUsed("http://www.bbc.co.uk/"))
.BDDfy(); .BDDfy();
@ -47,6 +51,8 @@ namespace Ocelot.UnitTests.Request
{ {
this.Given(x => x.GivenIHaveHttpMethod("POST")) this.Given(x => x.GivenIHaveHttpMethod("POST"))
.And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) .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()) .When(x => x.WhenICreateARequest())
.And(x => x.ThenTheCorrectHttpMethodIsUsed(HttpMethod.Post)) .And(x => x.ThenTheCorrectHttpMethodIsUsed(HttpMethod.Post))
.BDDfy(); .BDDfy();
@ -59,6 +65,8 @@ namespace Ocelot.UnitTests.Request
.And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk"))
.And(x => x.GivenIHaveTheHttpContent(new StringContent("Hi from Tom"))) .And(x => x.GivenIHaveTheHttpContent(new StringContent("Hi from Tom")))
.And(x => x.GivenTheContentTypeIs("application/json")) .And(x => x.GivenTheContentTypeIs("application/json"))
.And(x => x.GivenTheQos(true, new QoSOptions(3, 8, 5000, Polly.Timeout.TimeoutStrategy.Pessimistic)))
.When(x => x.WhenICreateARequest()) .When(x => x.WhenICreateARequest())
.And(x => x.ThenTheCorrectContentIsUsed(new StringContent("Hi from Tom"))) .And(x => x.ThenTheCorrectContentIsUsed(new StringContent("Hi from Tom")))
.BDDfy(); .BDDfy();
@ -71,6 +79,8 @@ namespace Ocelot.UnitTests.Request
.And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk"))
.And(x => x.GivenIHaveTheHttpContent(new StringContent("Hi from Tom"))) .And(x => x.GivenIHaveTheHttpContent(new StringContent("Hi from Tom")))
.And(x => x.GivenTheContentTypeIs("application/json")) .And(x => x.GivenTheContentTypeIs("application/json"))
.And(x => x.GivenTheQos(true, new QoSOptions(3, 8, 5000, Polly.Timeout.TimeoutStrategy.Pessimistic)))
.When(x => x.WhenICreateARequest()) .When(x => x.WhenICreateARequest())
.And(x => x.ThenTheCorrectContentHeadersAreUsed(new HeaderDictionary .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.GivenIHaveDownstreamUrl("http://www.bbc.co.uk"))
.And(x => x.GivenIHaveTheHttpContent(new StringContent("Hi from Tom"))) .And(x => x.GivenIHaveTheHttpContent(new StringContent("Hi from Tom")))
.And(x => x.GivenTheContentTypeIs("application/json; charset=utf-8")) .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()) .When(x => x.WhenICreateARequest())
.And(x => x.ThenTheCorrectContentHeadersAreUsed(new HeaderDictionary .And(x => x.ThenTheCorrectContentHeadersAreUsed(new HeaderDictionary
{ {
@ -107,6 +119,8 @@ namespace Ocelot.UnitTests.Request
{ {
{"ChopSticks", "Bubbles" } {"ChopSticks", "Bubbles" }
})) }))
.And(x => x.GivenTheQos(true, new QoSOptions(3, 8, 5000, Polly.Timeout.TimeoutStrategy.Pessimistic)))
.When(x => x.WhenICreateARequest()) .When(x => x.WhenICreateARequest())
.And(x => x.ThenTheCorrectHeadersAreUsed(new HeaderDictionary .And(x => x.ThenTheCorrectHeadersAreUsed(new HeaderDictionary
{ {
@ -124,6 +138,7 @@ namespace Ocelot.UnitTests.Request
.And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk"))
.And(x => x.GivenTheHttpHeadersAre(new HeaderDictionary())) .And(x => x.GivenTheHttpHeadersAre(new HeaderDictionary()))
.And(x => x.GivenTheRequestIdIs(new Ocelot.RequestId.RequestId("RequestId", requestId))) .And(x => x.GivenTheRequestIdIs(new Ocelot.RequestId.RequestId("RequestId", requestId)))
.And(x => x.GivenTheQos(true, new QoSOptions(3, 8, 5000, Polly.Timeout.TimeoutStrategy.Pessimistic)))
.When(x => x.WhenICreateARequest()) .When(x => x.WhenICreateARequest())
.And(x => x.ThenTheCorrectHeadersAreUsed(new HeaderDictionary .And(x => x.ThenTheCorrectHeadersAreUsed(new HeaderDictionary
{ {
@ -142,6 +157,7 @@ namespace Ocelot.UnitTests.Request
{"RequestId", "534534gv54gv45g" } {"RequestId", "534534gv54gv45g" }
})) }))
.And(x => x.GivenTheRequestIdIs(new Ocelot.RequestId.RequestId("RequestId", Guid.NewGuid().ToString()))) .And(x => x.GivenTheRequestIdIs(new Ocelot.RequestId.RequestId("RequestId", Guid.NewGuid().ToString())))
.And(x => x.GivenTheQos(true, new QoSOptions(3, 8, 5000, Polly.Timeout.TimeoutStrategy.Pessimistic)))
.When(x => x.WhenICreateARequest()) .When(x => x.WhenICreateARequest())
.And(x => x.ThenTheCorrectHeadersAreUsed(new HeaderDictionary .And(x => x.ThenTheCorrectHeadersAreUsed(new HeaderDictionary
{ {
@ -161,6 +177,7 @@ namespace Ocelot.UnitTests.Request
.And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk"))
.And(x => x.GivenTheHttpHeadersAre(new HeaderDictionary())) .And(x => x.GivenTheHttpHeadersAre(new HeaderDictionary()))
.And(x => x.GivenTheRequestIdIs(new Ocelot.RequestId.RequestId(requestIdKey, requestIdValue))) .And(x => x.GivenTheRequestIdIs(new Ocelot.RequestId.RequestId(requestIdKey, requestIdValue)))
.And(x => x.GivenTheQos(true, new QoSOptions(3, 8, 5000, Polly.Timeout.TimeoutStrategy.Pessimistic)))
.When(x => x.WhenICreateARequest()) .When(x => x.WhenICreateARequest())
.And(x => x.ThenTheRequestIdIsNotInTheHeaders()) .And(x => x.ThenTheRequestIdIsNotInTheHeaders())
.BDDfy(); .BDDfy();
@ -171,6 +188,12 @@ namespace Ocelot.UnitTests.Request
_requestId = requestId; _requestId = requestId;
} }
private void GivenTheQos(bool isQos, QoSOptions qos)
{
_isQos = isQos;
_qos = qos;
}
[Fact] [Fact]
public void should_use_cookies() public void should_use_cookies()
{ {
@ -281,7 +304,7 @@ namespace Ocelot.UnitTests.Request
private void WhenICreateARequest() private void WhenICreateARequest()
{ {
_result = _requestCreator.Build(_httpMethod, _downstreamUrl, _content?.ReadAsStreamAsync().Result, _headers, _result = _requestCreator.Build(_httpMethod, _downstreamUrl, _content?.ReadAsStreamAsync().Result, _headers,
_cookies, _query, _contentType, _requestId).Result; _cookies, _query, _contentType, _requestId,_isQos,_qos).Result;
} }

View File

@ -61,7 +61,7 @@ namespace Ocelot.UnitTests.Requester
[Fact] [Fact]
public void should_call_scoped_data_repository_correctly() public void should_call_scoped_data_repository_correctly()
{ {
this.Given(x => x.GivenTheRequestIs(new Ocelot.Request.Request(new HttpRequestMessage(),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.GivenTheRequesterReturns(new HttpResponseMessage()))
.And(x => x.GivenTheScopedRepoReturns()) .And(x => x.GivenTheScopedRepoReturns())
.When(x => x.WhenICallTheMiddleware()) .When(x => x.WhenICallTheMiddleware())

View File

@ -10,7 +10,6 @@ namespace Ocelot.UnitTests.ServiceDiscovery
public class ConfigurationServiceProviderTests public class ConfigurationServiceProviderTests
{ {
private ConfigurationServiceProvider _serviceProvider; private ConfigurationServiceProvider _serviceProvider;
private HostAndPort _hostAndPort;
private List<Service> _result; private List<Service> _result;
private List<Service> _expected; private List<Service> _expected;