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 _serviceProviderHost;
private int _serviceProviderPort;
private bool _useQos;
private QoSOptions _qosOptions;
public ReRouteBuilder()
{
@ -202,6 +205,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;
@ -226,7 +242,10 @@ namespace Ocelot.Configuration.Builder
_isAuthenticated, new AuthenticationOptions(_authenticationProvider, _authenticationProviderUrl, _scopeName,
_requireHttps, _additionalScopes, _scopeSecret), _configHeaderExtractorProperties, _claimToClaims, _routeClaimRequirement,
_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 isQos = fileReRoute.QoSOptions.ExceptionsAllowedBeforeBreaking > 0 && fileReRoute.QoSOptions.TimeoutValue >0;
var requestIdKey = globalRequestIdConfiguration
? globalConfiguration.RequestIdKey
: fileReRoute.RequestIdKey;
@ -103,11 +105,12 @@ namespace Ocelot.Configuration.Creator
var useServiceDiscovery = !string.IsNullOrEmpty(fileReRoute.ServiceName)
&& !string.IsNullOrEmpty(globalConfiguration?.ServiceDiscoveryProvider?.Provider);
//note - not sure if this is the correct key, but this is probably the only unique key i can think of given my poor brain
//note - not sure if this is the correct key, but this is probably the only unique key i can think of given my poor brain
var loadBalancerKey = $"{fileReRoute.UpstreamTemplate}{fileReRoute.UpstreamHttpMethod}";
ReRoute reRoute;
var serviceProviderPort = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0;
var serviceProviderConfiguration = new ServiceProviderConfiguraion(fileReRoute.ServiceName,
@ -127,14 +130,15 @@ namespace Ocelot.Configuration.Creator
var claimsToQueries = GetAddThingsToRequest(fileReRoute.AddQueriesToRequest);
reRoute = new ReRoute(new DownstreamPathTemplate(fileReRoute.DownstreamPathTemplate),
fileReRoute.UpstreamTemplate,
fileReRoute.UpstreamHttpMethod, upstreamTemplate, isAuthenticated,
authOptionsForRoute, claimsToHeaders, claimsToClaims,
fileReRoute.RouteClaimsRequirement, isAuthorised, claimsToQueries,
requestIdKey, isCached, new CacheOptions(fileReRoute.FileCacheOptions.TtlSeconds)
, fileReRoute.DownstreamScheme,
fileReRoute.LoadBalancer, fileReRoute.DownstreamHost, fileReRoute.DownstreamPort, loadBalancerKey,
serviceProviderConfiguration);
fileReRoute.UpstreamTemplate,
fileReRoute.UpstreamHttpMethod, upstreamTemplate, isAuthenticated,
authOptionsForRoute, claimsToHeaders, claimsToClaims,
fileReRoute.RouteClaimsRequirement, isAuthorised, claimsToQueries,
requestIdKey, isCached, new CacheOptions(fileReRoute.FileCacheOptions.TtlSeconds)
, fileReRoute.DownstreamScheme,
fileReRoute.LoadBalancer, fileReRoute.DownstreamHost, fileReRoute.DownstreamPort, loadBalancerKey,
serviceProviderConfiguration, isQos,
new QoSOptions(fileReRoute.QoSOptions.ExceptionsAllowedBeforeBreaking, fileReRoute.QoSOptions.DurationOfBreak, fileReRoute.QoSOptions.TimeoutValue));
}
else
{
@ -146,7 +150,8 @@ namespace Ocelot.Configuration.Creator
requestIdKey, isCached, new CacheOptions(fileReRoute.FileCacheOptions.TtlSeconds),
fileReRoute.DownstreamScheme,
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);

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>();
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;}
}
}

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

View File

@ -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>(request);

View File

@ -2,6 +2,7 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Ocelot.Responses;
using Ocelot.Configuration;
namespace Ocelot.Request.Builder
{
@ -14,6 +15,8 @@ namespace Ocelot.Request.Builder
IRequestCookieCollection cookies,
QueryString queryString,
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 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<Request> 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()

View File

@ -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)
{

View File

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

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,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<HttpClientHttpRequester>();
}
public async Task<Response<HttpResponseMessage>> 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<HttpResponseMessage>(response);
builder.WithCircuitBreaker(request.Qos, _logger, handler);
}
catch (Exception exception)
using (var httpClient = builder.Build(handler))
{
return
new ErrorResponse<HttpResponseMessage>(new List<Error>
{
new UnableToCompleteRequestError(exception)
});
try
{
var response = await httpClient.SendAsync(request.HttpRequestMessage);
return new OkResponse<HttpResponseMessage>(response);
}
catch (Exception exception)
{
return
new ErrorResponse<HttpResponseMessage>(new List<Error>
{
new UnableToCompleteRequestError(exception)
});
}
}
}
}

View File

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

View File

@ -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": {

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

@ -19,6 +19,7 @@ using Ocelot.Request.Middleware;
using Ocelot.Responses;
using TestStack.BDDfy;
using Xunit;
using Ocelot.Configuration;
namespace Ocelot.UnitTests.Request
{
@ -72,7 +73,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();
@ -91,7 +92,7 @@ namespace Ocelot.UnitTests.Request
_request = new OkResponse<Ocelot.Request.Request>(request);
_requestBuilder
.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);
}

View File

@ -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<Ocelot.Request.Request> _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;
}

View File

@ -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())

View File

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