refactor code

This commit is contained in:
geffzhang 2017-02-13 08:29:29 +08:00
parent 659d124780
commit 2fa6e66dd4
18 changed files with 119 additions and 138 deletions

View File

@ -117,12 +117,8 @@ namespace Ocelot.Configuration.Creator
rateLimitOption = new RateLimitOptions(enableRateLimiting, globalConfiguration.RateLimitOptions.ClientIdHeader, rateLimitOption = new RateLimitOptions(enableRateLimiting, globalConfiguration.RateLimitOptions.ClientIdHeader,
fileReRoute.RateLimitOptions.ClientWhitelist, globalConfiguration.RateLimitOptions.DisableRateLimitHeaders, fileReRoute.RateLimitOptions.ClientWhitelist, globalConfiguration.RateLimitOptions.DisableRateLimitHeaders,
globalConfiguration.RateLimitOptions.QuotaExceededMessage, globalConfiguration.RateLimitOptions.RateLimitCounterPrefix, globalConfiguration.RateLimitOptions.QuotaExceededMessage, globalConfiguration.RateLimitOptions.RateLimitCounterPrefix,
new RateLimitRule() new RateLimitRule(fileReRoute.RateLimitOptions.Period, TimeSpan.FromSeconds(fileReRoute.RateLimitOptions.PeriodTimespan), fileReRoute.RateLimitOptions.Limit)
{ , globalConfiguration.RateLimitOptions.HttpStatusCode);
Limit = fileReRoute.RateLimitOptions.Limit,
Period = fileReRoute.RateLimitOptions.Period,
PeriodTimespan = TimeSpan.FromSeconds(fileReRoute.RateLimitOptions.PeriodTimespan)
}, globalConfiguration.RateLimitOptions.HttpStatusCode);
} }
var serviceProviderPort = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0; var serviceProviderPort = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0;

View File

@ -32,7 +32,7 @@ namespace Ocelot.Configuration.File
/// <summary> /// <summary>
/// Gets or sets the HTTP Status code returned when rate limiting occurs, by default value is set to 429 (Too Many Requests) /// Gets or sets the HTTP Status code returned when rate limiting occurs, by default value is set to 429 (Too Many Requests)
/// </summary> /// </summary>
public int HttpStatusCode { get; private set; } = 429; public int HttpStatusCode { get; set; } = 429;
} }

View File

@ -25,7 +25,7 @@ namespace Ocelot.Configuration.File
/// </summary> /// </summary>
public string Period { get; set; } public string Period { get; set; }
public int PeriodTimespan { get; set; } public double PeriodTimespan { get; set; }
/// <summary> /// <summary>
/// Maximum number of requests that a client can make in a defined period /// Maximum number of requests that a client can make in a defined period
/// </summary> /// </summary>

View File

@ -15,7 +15,7 @@ namespace Ocelot.Configuration
{ {
EnableRateLimiting = enbleRateLimiting; EnableRateLimiting = enbleRateLimiting;
ClientIdHeader = clientIdHeader; ClientIdHeader = clientIdHeader;
ClientWhitelist = clientWhitelist; ClientWhitelist = clientWhitelist?? new List<string>();
DisableRateLimitHeaders = disableRateLimitHeaders; DisableRateLimitHeaders = disableRateLimitHeaders;
QuotaExceededMessage = quotaExceededMessage; QuotaExceededMessage = quotaExceededMessage;
RateLimitCounterPrefix = rateLimitCounterPrefix; RateLimitCounterPrefix = rateLimitCounterPrefix;
@ -62,15 +62,22 @@ namespace Ocelot.Configuration
public class RateLimitRule public class RateLimitRule
{ {
/// <summary> public RateLimitRule(string period, TimeSpan periodTimespan, long limit)
/// Rate limit period as in 1s, 1m, 1h {
/// </summary> Period = period;
public string Period { get; set; } PeriodTimespan = periodTimespan;
Limit = limit;
}
public TimeSpan? PeriodTimespan { get; set; } /// <summary>
/// Rate limit period as in 1s, 1m, 1h,1d
/// </summary>
public string Period { get; private set; }
public TimeSpan PeriodTimespan { get; private set; }
/// <summary> /// <summary>
/// Maximum number of requests that a client can make in a defined period /// Maximum number of requests that a client can make in a defined period
/// </summary> /// </summary>
public long Limit { get; set; } public long Limit { get; private set; }
} }
} }

View File

@ -91,7 +91,7 @@ namespace Ocelot.DependencyInjection
// could maybe use a scoped data repository // could maybe use a scoped data repository
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<IRequestScopedDataRepository, HttpDataRepository>(); services.AddScoped<IRequestScopedDataRepository, HttpDataRepository>();
services.AddMemoryCache();
return services; return services;
} }
} }

View File

@ -1,4 +1,5 @@
using Ocelot.Configuration; using Microsoft.AspNetCore.Http;
using Ocelot.Configuration;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -27,9 +28,9 @@ namespace Ocelot.RateLimit
return _core.RetryAfterFrom(timestamp, rule); return _core.RetryAfterFrom(timestamp, rule);
} }
public RateLimitHeaders GetRateLimitHeaders(ClientRequestIdentity requestIdentity, RateLimitOptions option) public RateLimitHeaders GetRateLimitHeaders(HttpContext context, ClientRequestIdentity requestIdentity, RateLimitOptions option)
{ {
return _core.GetRateLimitHeaders(requestIdentity, option); return _core.GetRateLimitHeaders(context, requestIdentity, option);
} }
} }

View File

@ -2,10 +2,17 @@
{ {
public class ClientRequestIdentity public class ClientRequestIdentity
{ {
public string ClientId { get; set; } public ClientRequestIdentity(string clientId, string path, string httpverb)
{
ClientId = clientId;
Path = path;
HttpVerb = httpverb;
}
public string Path { get; set; } public string ClientId { get; private set; }
public string HttpVerb { get; set; } public string Path { get; private set; }
public string HttpVerb { get; private set; }
} }
} }

View File

@ -72,9 +72,7 @@ namespace Ocelot.RateLimit.Middleware
//set X-Rate-Limit headers for the longest period //set X-Rate-Limit headers for the longest period
if (!options.DisableRateLimitHeaders) if (!options.DisableRateLimitHeaders)
{ {
var headers = _processor.GetRateLimitHeaders(identity, options); var headers = _processor.GetRateLimitHeaders( context,identity, options);
headers.Context = context;
context.Response.OnStarting(SetRateLimitHeaders, state: headers); context.Response.OnStarting(SetRateLimitHeaders, state: headers);
} }
@ -89,21 +87,19 @@ namespace Ocelot.RateLimit.Middleware
clientId = httpContext.Request.Headers[option.ClientIdHeader].First(); clientId = httpContext.Request.Headers[option.ClientIdHeader].First();
} }
return new ClientRequestIdentity return new ClientRequestIdentity(
{ clientId,
Path = httpContext.Request.Path.ToString().ToLowerInvariant(), httpContext.Request.Path.ToString().ToLowerInvariant(),
HttpVerb = httpContext.Request.Method.ToLowerInvariant(), httpContext.Request.Method.ToLowerInvariant()
ClientId = clientId, );
}; }
}
public bool IsWhitelisted(ClientRequestIdentity requestIdentity, RateLimitOptions option) public bool IsWhitelisted(ClientRequestIdentity requestIdentity, RateLimitOptions option)
{ {
if (option.ClientWhitelist != null && option.ClientWhitelist.Contains(requestIdentity.ClientId)) if (option.ClientWhitelist.Contains(requestIdentity.ClientId))
{ {
return true; return true;
} }
return false; return false;
} }

View File

@ -1,8 +1,11 @@
using Ocelot.Configuration; using Microsoft.AspNetCore.Http;
using Ocelot.Configuration;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Ocelot.RateLimit namespace Ocelot.RateLimit
@ -19,11 +22,7 @@ namespace Ocelot.RateLimit
public RateLimitCounter ProcessRequest(ClientRequestIdentity requestIdentity, RateLimitOptions option) public RateLimitCounter ProcessRequest(ClientRequestIdentity requestIdentity, RateLimitOptions option)
{ {
var counter = new RateLimitCounter RateLimitCounter counter = new RateLimitCounter(DateTime.UtcNow, 1);
{
Timestamp = DateTime.UtcNow,
TotalRequests = 1
};
var rule = option.RateLimitRule; var rule = option.RateLimitRule;
var counterId = ComputeCounterKey(requestIdentity, option); var counterId = ComputeCounterKey(requestIdentity, option);
@ -35,59 +34,57 @@ namespace Ocelot.RateLimit
if (entry.HasValue) if (entry.HasValue)
{ {
// entry has not expired // entry has not expired
if (entry.Value.Timestamp + rule.PeriodTimespan.Value >= DateTime.UtcNow) if (entry.Value.Timestamp + rule.PeriodTimespan >= DateTime.UtcNow)
{ {
// increment request count // increment request count
var totalRequests = entry.Value.TotalRequests + 1; var totalRequests = entry.Value.TotalRequests + 1;
// deep copy // deep copy
counter = new RateLimitCounter counter = new RateLimitCounter(entry.Value.Timestamp, totalRequests);
{
Timestamp = entry.Value.Timestamp,
TotalRequests = totalRequests
};
} }
} }
// stores: id (string) - timestamp (datetime) - total_requests (long) // stores: id (string) - timestamp (datetime) - total_requests (long)
_counterHandler.Set(counterId, counter, rule.PeriodTimespan.Value); _counterHandler.Set(counterId, counter, rule.PeriodTimespan);
} }
return counter; return counter;
} }
public RateLimitHeaders GetRateLimitHeaders(ClientRequestIdentity requestIdentity, RateLimitOptions option) public RateLimitHeaders GetRateLimitHeaders(HttpContext context, ClientRequestIdentity requestIdentity, RateLimitOptions option)
{ {
var rule = option.RateLimitRule; var rule = option.RateLimitRule;
var headers = new RateLimitHeaders(); RateLimitHeaders headers = null;
var counterId = ComputeCounterKey(requestIdentity, option); var counterId = ComputeCounterKey(requestIdentity, option);
var entry = _counterHandler.Get(counterId); var entry = _counterHandler.Get(counterId);
if (entry.HasValue) if (entry.HasValue)
{ {
headers.Reset = (entry.Value.Timestamp + ConvertToTimeSpan(rule.Period)).ToUniversalTime().ToString("o", DateTimeFormatInfo.InvariantInfo); headers = new RateLimitHeaders(context, rule.Period,
headers.Limit = rule.Period; (rule.Limit - entry.Value.TotalRequests).ToString(),
headers.Remaining = (rule.Limit - entry.Value.TotalRequests).ToString(); (entry.Value.Timestamp + ConvertToTimeSpan(rule.Period)).ToUniversalTime().ToString("o", DateTimeFormatInfo.InvariantInfo)
} );
}
else else
{ {
headers.Reset = (DateTime.UtcNow + ConvertToTimeSpan(rule.Period)).ToUniversalTime().ToString("o", DateTimeFormatInfo.InvariantInfo); headers = new RateLimitHeaders(context,
headers.Limit = rule.Period; rule.Period,
headers.Remaining = rule.Limit.ToString(); rule.Limit.ToString(),
(DateTime.UtcNow + ConvertToTimeSpan(rule.Period)).ToUniversalTime().ToString("o", DateTimeFormatInfo.InvariantInfo));
} }
return headers; return headers;
throw new NotImplementedException(); }
}
public string ComputeCounterKey(ClientRequestIdentity requestIdentity, RateLimitOptions option) public string ComputeCounterKey(ClientRequestIdentity requestIdentity, RateLimitOptions option)
{ {
var key = $"{option.RateLimitCounterPrefix}_{requestIdentity.ClientId}_{option.RateLimitRule.Period}_{requestIdentity.HttpVerb}_{requestIdentity.Path}"; var key = $"{option.RateLimitCounterPrefix}_{requestIdentity.ClientId}_{option.RateLimitRule.Period}_{requestIdentity.HttpVerb}_{requestIdentity.Path}";
var idBytes = System.Text.Encoding.UTF8.GetBytes(key); var idBytes = Encoding.UTF8.GetBytes(key);
byte[] hashBytes; byte[] hashBytes;
using (var algorithm = System.Security.Cryptography.SHA1.Create()) using (var algorithm = SHA1.Create())
{ {
hashBytes = algorithm.ComputeHash(idBytes); hashBytes = algorithm.ComputeHash(idBytes);
} }
@ -98,7 +95,7 @@ namespace Ocelot.RateLimit
public string RetryAfterFrom(DateTime timestamp, RateLimitRule rule) public string RetryAfterFrom(DateTime timestamp, RateLimitRule rule)
{ {
var secondsPast = Convert.ToInt32((DateTime.UtcNow - timestamp).TotalSeconds); var secondsPast = Convert.ToInt32((DateTime.UtcNow - timestamp).TotalSeconds);
var retryAfter = Convert.ToInt32(rule.PeriodTimespan.Value.TotalSeconds); var retryAfter = Convert.ToInt32(rule.PeriodTimespan.TotalSeconds);
retryAfter = retryAfter > 1 ? retryAfter - secondsPast : 1; retryAfter = retryAfter > 1 ? retryAfter - secondsPast : 1;
return retryAfter.ToString(System.Globalization.CultureInfo.InvariantCulture); return retryAfter.ToString(System.Globalization.CultureInfo.InvariantCulture);
} }
@ -111,11 +108,16 @@ namespace Ocelot.RateLimit
switch (type) switch (type)
{ {
case "d": return TimeSpan.FromDays(double.Parse(value)); case "d":
case "h": return TimeSpan.FromHours(double.Parse(value)); return TimeSpan.FromDays(double.Parse(value));
case "m": return TimeSpan.FromMinutes(double.Parse(value)); case "h":
case "s": return TimeSpan.FromSeconds(double.Parse(value)); return TimeSpan.FromHours(double.Parse(value));
default: throw new FormatException($"{timeSpan} can't be converted to TimeSpan, unknown type {type}"); case "m":
return TimeSpan.FromMinutes(double.Parse(value));
case "s":
return TimeSpan.FromSeconds(double.Parse(value));
default:
throw new FormatException($"{timeSpan} can't be converted to TimeSpan, unknown type {type}");
} }
} }

View File

@ -10,8 +10,14 @@ namespace Ocelot.RateLimit
/// </summary> /// </summary>
public struct RateLimitCounter public struct RateLimitCounter
{ {
public DateTime Timestamp { get; set; } public RateLimitCounter(DateTime timestamp, long totalRequest)
{
Timestamp = timestamp;
TotalRequests = totalRequest;
}
public long TotalRequests { get; set; } public DateTime Timestamp { get; private set; }
public long TotalRequests { get; private set; }
} }
} }

View File

@ -8,12 +8,20 @@ namespace Ocelot.RateLimit
{ {
public class RateLimitHeaders public class RateLimitHeaders
{ {
public HttpContext Context { get; set; } public RateLimitHeaders(HttpContext context, string limit, string remaining, string reset)
{
Context = context;
Limit = limit;
Remaining = remaining;
Reset = reset;
}
public string Limit { get; set; } public HttpContext Context { get; private set; }
public string Remaining { get; set; } public string Limit { get; private set; }
public string Reset { get; set; } public string Remaining { get; private set; }
public string Reset { get; private set; }
} }
} }

View File

@ -67,7 +67,9 @@ namespace Ocelot.AcceptanceTests
ClientIdHeader = "ClientId", ClientIdHeader = "ClientId",
DisableRateLimitHeaders = false, DisableRateLimitHeaders = false,
QuotaExceededMessage = "", QuotaExceededMessage = "",
RateLimitCounterPrefix = "" RateLimitCounterPrefix = "",
HttpStatusCode = 428
}, },
RequestIdKey ="oceclientrequest" RequestIdKey ="oceclientrequest"
} }
@ -76,8 +78,12 @@ namespace Ocelot.AcceptanceTests
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/api/ClientRateLimit")) this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/api/ClientRateLimit"))
.And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning()) .And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/api/ClientRateLimit", 5)) .When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/api/ClientRateLimit",1))
.Then(x => _steps.ThenTheStatusCodeShouldBe(429)) .Then(x => _steps.ThenTheStatusCodeShouldBe(200))
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/api/ClientRateLimit", 2))
.Then(x => _steps.ThenTheStatusCodeShouldBe(200))
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/api/ClientRateLimit",1))
.Then(x => _steps.ThenTheStatusCodeShouldBe(428))
.BDDfy(); .BDDfy();
} }
@ -154,55 +160,6 @@ namespace Ocelot.AcceptanceTests
_builder.Start(); _builder.Start();
} }
//private void GetApiRateLimait(string url)
//{
// var clientId = "ocelotclient1";
// var request = new HttpRequestMessage(new HttpMethod("GET"), url);
// request.Headers.Add("ClientId", clientId);
// var response = _client.SendAsync(request);
// responseStatusCode = (int)response.Result.StatusCode;
// }
//}
//public void WhenIGetUrlOnTheApiGatewayMultipleTimes(string url, int times)
//{
// var clientId = "ocelotclient1";
// var tasks = new Task[times];
// for (int i = 0; i < times; i++)
// {
// var urlCopy = url;
// tasks[i] = GetForServiceDiscoveryTest(urlCopy);
// Thread.Sleep(_random.Next(40, 60));
// }
// Task.WaitAll(tasks);
//}
//private void WhenICallTheMiddlewareWithWhiteClient()
//{
// var clientId = "ocelotclient2";
// // Act
// for (int i = 0; i < 2; i++)
// {
// var request = new HttpRequestMessage(new HttpMethod("GET"), apiRateLimitPath);
// request.Headers.Add("ClientId", clientId);
// var response = _client.SendAsync(request);
// responseStatusCode = (int)response.Result.StatusCode;
// }
//}
//private void ThenresponseStatusCodeIs429()
//{
// responseStatusCode.ShouldBe(429);
//}
//private void ThenresponseStatusCodeIs200()
//{
// responseStatusCode.ShouldBe(200);
//}
} }
} }

View File

@ -101,7 +101,6 @@ namespace Ocelot.AcceptanceTests
}) })
.WithDictionaryHandle(); .WithDictionaryHandle();
}; };
s.AddMemoryCache();
s.AddOcelotOutputCaching(settings); s.AddOcelotOutputCaching(settings);
s.AddOcelotFileConfiguration(configuration); s.AddOcelotFileConfiguration(configuration);
s.AddOcelot(); s.AddOcelot();

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,"QoSOptions":{"ExceptionsAllowedBeforeBreaking":0,"DurationOfBreak":0,"TimeoutValue":0},"LoadBalancer":null,"RateLimitOptions":{"ClientWhitelist":[],"EnableRateLimiting":false,"Period":null,"PeriodTimespan":0,"Limit":0}}],"GlobalConfiguration":{"RequestIdKey":null,"ServiceDiscoveryProvider":{"Provider":null,"Host":null,"Port":0},"RateLimitOptions":{"ClientIdHeader":"ClientId","QuotaExceededMessage":null,"RateLimitCounterPrefix":"ocelot","DisableRateLimitHeaders":false,"HttpStatusCode":429}}} {"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,"RateLimitOptions":{"ClientWhitelist":[],"EnableRateLimiting":false,"Period":null,"PeriodTimespan":0.0,"Limit":0}}],"GlobalConfiguration":{"RequestIdKey":null,"ServiceDiscoveryProvider":{"Provider":null,"Host":null,"Port":0},"RateLimitOptions":{"ClientIdHeader":"ClientId","QuotaExceededMessage":null,"RateLimitCounterPrefix":"ocelot","DisableRateLimitHeaders":false,"HttpStatusCode":429}}}

View File

@ -23,7 +23,6 @@
"Microsoft.AspNetCore.Http": "1.1.0", "Microsoft.AspNetCore.Http": "1.1.0",
"Microsoft.DotNet.InternalAbstractions": "1.0.0", "Microsoft.DotNet.InternalAbstractions": "1.0.0",
"Ocelot": "0.0.0-dev", "Ocelot": "0.0.0-dev",
"xunit": "2.2.0-beta2-build3300",
"dotnet-test-xunit": "2.2.0-preview2-build1029", "dotnet-test-xunit": "2.2.0-preview2-build1029",
"Ocelot.ManualTest": "0.0.0-dev", "Ocelot.ManualTest": "0.0.0-dev",
"Microsoft.AspNetCore.TestHost": "1.1.0", "Microsoft.AspNetCore.TestHost": "1.1.0",
@ -34,7 +33,8 @@
"Shouldly": "2.8.2", "Shouldly": "2.8.2",
"TestStack.BDDfy": "4.3.2", "TestStack.BDDfy": "4.3.2",
"Consul": "0.7.2.1", "Consul": "0.7.2.1",
"Microsoft.Extensions.Caching.Memory": "1.1.0" "Microsoft.Extensions.Caching.Memory": "1.1.0",
"xunit": "2.2.0-rc1-build3507"
}, },
"runtimes": { "runtimes": {
"win10-x64": {}, "win10-x64": {},

View File

@ -37,7 +37,6 @@ namespace Ocelot.ManualTest
}) })
.WithDictionaryHandle(); .WithDictionaryHandle();
}; };
services.AddMemoryCache();
services.AddOcelotOutputCaching(settings); services.AddOcelotOutputCaching(settings);
services.AddOcelotFileConfiguration(Configuration); services.AddOcelotFileConfiguration(Configuration);
services.AddOcelot(); services.AddOcelot();

View File

@ -20,6 +20,7 @@ using Xunit;
using TestStack.BDDfy; using TestStack.BDDfy;
using Ocelot.Configuration.Builder; using Ocelot.Configuration.Builder;
using Shouldly; using Shouldly;
using Ocelot.Configuration;
namespace Ocelot.UnitTests.RateLimit namespace Ocelot.UnitTests.RateLimit
{ {
@ -70,11 +71,13 @@ namespace Ocelot.UnitTests.RateLimit
{ {
var downstreamRoute = new DownstreamRoute(new List<Ocelot.DownstreamRouteFinder.UrlMatcher.UrlPathPlaceholderNameAndValue>(), var downstreamRoute = new DownstreamRoute(new List<Ocelot.DownstreamRouteFinder.UrlMatcher.UrlPathPlaceholderNameAndValue>(),
new ReRouteBuilder().WithEnableRateLimiting(true).WithRateLimitOptions( new ReRouteBuilder().WithEnableRateLimiting(true).WithRateLimitOptions(
new Ocelot.Configuration.RateLimitOptions(true, "ClientId", new List<string>(), false, "", "", new Ocelot.Configuration.RateLimitRule() { Limit = 3, Period = "1s", PeriodTimespan = TimeSpan.FromSeconds(100) },429)) new Ocelot.Configuration.RateLimitOptions(true, "ClientId", new List<string>(), false, "", "", new Ocelot.Configuration.RateLimitRule("1s", TimeSpan.FromSeconds(100), 3), 429))
.Build()); .Build());
this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
.When(x => x.WhenICallTheMiddleware()) .When(x => x.WhenICallTheMiddlewareMultipleTime(2))
.Then(x => x.ThenresponseStatusCodeIs200())
.When(x => x.WhenICallTheMiddlewareMultipleTime(2))
.Then(x => x.ThenresponseStatusCodeIs429()) .Then(x => x.ThenresponseStatusCodeIs429())
.BDDfy(); .BDDfy();
} }
@ -84,7 +87,7 @@ namespace Ocelot.UnitTests.RateLimit
{ {
var downstreamRoute = new DownstreamRoute(new List<Ocelot.DownstreamRouteFinder.UrlMatcher.UrlPathPlaceholderNameAndValue>(), var downstreamRoute = new DownstreamRoute(new List<Ocelot.DownstreamRouteFinder.UrlMatcher.UrlPathPlaceholderNameAndValue>(),
new ReRouteBuilder().WithEnableRateLimiting(true).WithRateLimitOptions( new ReRouteBuilder().WithEnableRateLimiting(true).WithRateLimitOptions(
new Ocelot.Configuration.RateLimitOptions(true, "ClientId", new List<string>() { "ocelotclient2" }, false, "", "", new Ocelot.Configuration.RateLimitRule() { Limit = 3, Period = "1s", PeriodTimespan = TimeSpan.FromSeconds(100) },429)) new Ocelot.Configuration.RateLimitOptions(true, "ClientId", new List<string>() { "ocelotclient2" }, false, "", "", new RateLimitRule( "1s", TimeSpan.FromSeconds(100),3),429))
.Build()); .Build());
this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
@ -102,11 +105,11 @@ namespace Ocelot.UnitTests.RateLimit
.Returns(_downstreamRoute); .Returns(_downstreamRoute);
} }
private void WhenICallTheMiddleware() private void WhenICallTheMiddlewareMultipleTime(int times)
{ {
var clientId = "ocelotclient1"; var clientId = "ocelotclient1";
// Act // Act
for (int i = 0; i <10; i++) for (int i = 0; i < times; i++)
{ {
var request = new HttpRequestMessage(new HttpMethod("GET"), _url); var request = new HttpRequestMessage(new HttpMethod("GET"), _url);
request.Headers.Add("ClientId", clientId); request.Headers.Add("ClientId", clientId);

View File

@ -14,7 +14,6 @@
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0", "Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0",
"Microsoft.AspNetCore.Http": "1.1.0", "Microsoft.AspNetCore.Http": "1.1.0",
"Ocelot": "0.0.0-dev", "Ocelot": "0.0.0-dev",
"xunit": "2.2.0-beta2-build3300",
"dotnet-test-xunit": "2.2.0-preview2-build1029", "dotnet-test-xunit": "2.2.0-preview2-build1029",
"Moq": "4.6.38-alpha", "Moq": "4.6.38-alpha",
"Microsoft.AspNetCore.TestHost": "1.1.0", "Microsoft.AspNetCore.TestHost": "1.1.0",
@ -24,7 +23,8 @@
"Shouldly": "2.8.2", "Shouldly": "2.8.2",
"TestStack.BDDfy": "4.3.2", "TestStack.BDDfy": "4.3.2",
"Microsoft.AspNetCore.Authentication.OAuth": "1.1.0", "Microsoft.AspNetCore.Authentication.OAuth": "1.1.0",
"Microsoft.DotNet.InternalAbstractions": "1.0.0" "Microsoft.DotNet.InternalAbstractions": "1.0.0",
"xunit": "2.2.0-rc1-build3507"
}, },
"runtimes": { "runtimes": {
"win10-x64": {}, "win10-x64": {},