diff --git a/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs index c5eababe..646af96c 100644 --- a/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs +++ b/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs @@ -117,12 +117,8 @@ namespace Ocelot.Configuration.Creator rateLimitOption = new RateLimitOptions(enableRateLimiting, globalConfiguration.RateLimitOptions.ClientIdHeader, fileReRoute.RateLimitOptions.ClientWhitelist, globalConfiguration.RateLimitOptions.DisableRateLimitHeaders, globalConfiguration.RateLimitOptions.QuotaExceededMessage, globalConfiguration.RateLimitOptions.RateLimitCounterPrefix, - new RateLimitRule() - { - Limit = fileReRoute.RateLimitOptions.Limit, - Period = fileReRoute.RateLimitOptions.Period, - PeriodTimespan = TimeSpan.FromSeconds(fileReRoute.RateLimitOptions.PeriodTimespan) - }, globalConfiguration.RateLimitOptions.HttpStatusCode); + new RateLimitRule(fileReRoute.RateLimitOptions.Period, TimeSpan.FromSeconds(fileReRoute.RateLimitOptions.PeriodTimespan), fileReRoute.RateLimitOptions.Limit) + , globalConfiguration.RateLimitOptions.HttpStatusCode); } var serviceProviderPort = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0; diff --git a/src/Ocelot/Configuration/File/FileRateLimitOptions.cs b/src/Ocelot/Configuration/File/FileRateLimitOptions.cs index 655b2442..afb3fab5 100644 --- a/src/Ocelot/Configuration/File/FileRateLimitOptions.cs +++ b/src/Ocelot/Configuration/File/FileRateLimitOptions.cs @@ -32,7 +32,7 @@ namespace Ocelot.Configuration.File /// /// Gets or sets the HTTP Status code returned when rate limiting occurs, by default value is set to 429 (Too Many Requests) /// - public int HttpStatusCode { get; private set; } = 429; + public int HttpStatusCode { get; set; } = 429; } diff --git a/src/Ocelot/Configuration/File/FileRateLimitRule.cs b/src/Ocelot/Configuration/File/FileRateLimitRule.cs index 58d171de..727a9e82 100644 --- a/src/Ocelot/Configuration/File/FileRateLimitRule.cs +++ b/src/Ocelot/Configuration/File/FileRateLimitRule.cs @@ -25,7 +25,7 @@ namespace Ocelot.Configuration.File /// public string Period { get; set; } - public int PeriodTimespan { get; set; } + public double PeriodTimespan { get; set; } /// /// Maximum number of requests that a client can make in a defined period /// diff --git a/src/Ocelot/Configuration/RateLimitOptions.cs b/src/Ocelot/Configuration/RateLimitOptions.cs index d5c68d23..85a3bf78 100644 --- a/src/Ocelot/Configuration/RateLimitOptions.cs +++ b/src/Ocelot/Configuration/RateLimitOptions.cs @@ -15,7 +15,7 @@ namespace Ocelot.Configuration { EnableRateLimiting = enbleRateLimiting; ClientIdHeader = clientIdHeader; - ClientWhitelist = clientWhitelist; + ClientWhitelist = clientWhitelist?? new List(); DisableRateLimitHeaders = disableRateLimitHeaders; QuotaExceededMessage = quotaExceededMessage; RateLimitCounterPrefix = rateLimitCounterPrefix; @@ -62,15 +62,22 @@ namespace Ocelot.Configuration public class RateLimitRule { - /// - /// Rate limit period as in 1s, 1m, 1h - /// - public string Period { get; set; } + public RateLimitRule(string period, TimeSpan periodTimespan, long limit) + { + Period = period; + PeriodTimespan = periodTimespan; + Limit = limit; + } - public TimeSpan? PeriodTimespan { get; set; } + /// + /// Rate limit period as in 1s, 1m, 1h,1d + /// + public string Period { get; private set; } + + public TimeSpan PeriodTimespan { get; private set; } /// /// Maximum number of requests that a client can make in a defined period /// - public long Limit { get; set; } + public long Limit { get; private set; } } } diff --git a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs index e83ad30c..446720ca 100644 --- a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs @@ -91,7 +91,7 @@ namespace Ocelot.DependencyInjection // could maybe use a scoped data repository services.AddSingleton(); services.AddScoped(); - + services.AddMemoryCache(); return services; } } diff --git a/src/Ocelot/RateLimit/ClientRateLimitProcessor.cs b/src/Ocelot/RateLimit/ClientRateLimitProcessor.cs index 38141b49..a2ee1202 100644 --- a/src/Ocelot/RateLimit/ClientRateLimitProcessor.cs +++ b/src/Ocelot/RateLimit/ClientRateLimitProcessor.cs @@ -1,4 +1,5 @@ -using Ocelot.Configuration; +using Microsoft.AspNetCore.Http; +using Ocelot.Configuration; using System; using System.Collections.Generic; using System.Linq; @@ -27,9 +28,9 @@ namespace Ocelot.RateLimit 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); } } diff --git a/src/Ocelot/RateLimit/ClientRequestIdentity.cs b/src/Ocelot/RateLimit/ClientRequestIdentity.cs index 9cceeb9e..a27bc994 100644 --- a/src/Ocelot/RateLimit/ClientRequestIdentity.cs +++ b/src/Ocelot/RateLimit/ClientRequestIdentity.cs @@ -2,10 +2,17 @@ { 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; } } } \ No newline at end of file diff --git a/src/Ocelot/RateLimit/Middleware/ClientRateLimitMiddleware.cs b/src/Ocelot/RateLimit/Middleware/ClientRateLimitMiddleware.cs index 64ac40c0..4dbaeed1 100644 --- a/src/Ocelot/RateLimit/Middleware/ClientRateLimitMiddleware.cs +++ b/src/Ocelot/RateLimit/Middleware/ClientRateLimitMiddleware.cs @@ -72,9 +72,7 @@ namespace Ocelot.RateLimit.Middleware //set X-Rate-Limit headers for the longest period if (!options.DisableRateLimitHeaders) { - var headers = _processor.GetRateLimitHeaders(identity, options); - headers.Context = context; - + var headers = _processor.GetRateLimitHeaders( context,identity, options); context.Response.OnStarting(SetRateLimitHeaders, state: headers); } @@ -89,21 +87,19 @@ namespace Ocelot.RateLimit.Middleware clientId = httpContext.Request.Headers[option.ClientIdHeader].First(); } - return new ClientRequestIdentity - { - Path = httpContext.Request.Path.ToString().ToLowerInvariant(), - HttpVerb = httpContext.Request.Method.ToLowerInvariant(), - ClientId = clientId, - }; - } + return new ClientRequestIdentity( + clientId, + httpContext.Request.Path.ToString().ToLowerInvariant(), + httpContext.Request.Method.ToLowerInvariant() + ); + } 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 false; } diff --git a/src/Ocelot/RateLimit/RateLimitCore.cs b/src/Ocelot/RateLimit/RateLimitCore.cs index 39904b06..07627f8d 100644 --- a/src/Ocelot/RateLimit/RateLimitCore.cs +++ b/src/Ocelot/RateLimit/RateLimitCore.cs @@ -1,8 +1,11 @@ -using Ocelot.Configuration; +using Microsoft.AspNetCore.Http; +using Ocelot.Configuration; using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Security.Cryptography; +using System.Text; using System.Threading.Tasks; namespace Ocelot.RateLimit @@ -19,11 +22,7 @@ namespace Ocelot.RateLimit public RateLimitCounter ProcessRequest(ClientRequestIdentity requestIdentity, RateLimitOptions option) { - var counter = new RateLimitCounter - { - Timestamp = DateTime.UtcNow, - TotalRequests = 1 - }; + RateLimitCounter counter = new RateLimitCounter(DateTime.UtcNow, 1); var rule = option.RateLimitRule; var counterId = ComputeCounterKey(requestIdentity, option); @@ -35,59 +34,57 @@ namespace Ocelot.RateLimit if (entry.HasValue) { // entry has not expired - if (entry.Value.Timestamp + rule.PeriodTimespan.Value >= DateTime.UtcNow) + if (entry.Value.Timestamp + rule.PeriodTimespan >= DateTime.UtcNow) { // increment request count var totalRequests = entry.Value.TotalRequests + 1; // deep copy - counter = new RateLimitCounter - { - Timestamp = entry.Value.Timestamp, - TotalRequests = totalRequests - }; + counter = new RateLimitCounter(entry.Value.Timestamp, totalRequests); + } } - // stores: id (string) - timestamp (datetime) - total_requests (long) - _counterHandler.Set(counterId, counter, rule.PeriodTimespan.Value); + _counterHandler.Set(counterId, counter, rule.PeriodTimespan); } return counter; } - public RateLimitHeaders GetRateLimitHeaders(ClientRequestIdentity requestIdentity, RateLimitOptions option) + public RateLimitHeaders GetRateLimitHeaders(HttpContext context, ClientRequestIdentity requestIdentity, RateLimitOptions option) { var rule = option.RateLimitRule; - var headers = new RateLimitHeaders(); + RateLimitHeaders headers = null; var counterId = ComputeCounterKey(requestIdentity, option); var entry = _counterHandler.Get(counterId); if (entry.HasValue) { - headers.Reset = (entry.Value.Timestamp + ConvertToTimeSpan(rule.Period)).ToUniversalTime().ToString("o", DateTimeFormatInfo.InvariantInfo); - headers.Limit = rule.Period; - headers.Remaining = (rule.Limit - entry.Value.TotalRequests).ToString(); - } + headers = new RateLimitHeaders(context, rule.Period, + (rule.Limit - entry.Value.TotalRequests).ToString(), + (entry.Value.Timestamp + ConvertToTimeSpan(rule.Period)).ToUniversalTime().ToString("o", DateTimeFormatInfo.InvariantInfo) + ); + } else { - headers.Reset = (DateTime.UtcNow + ConvertToTimeSpan(rule.Period)).ToUniversalTime().ToString("o", DateTimeFormatInfo.InvariantInfo); - headers.Limit = rule.Period; - headers.Remaining = rule.Limit.ToString(); + headers = new RateLimitHeaders(context, + rule.Period, + rule.Limit.ToString(), + (DateTime.UtcNow + ConvertToTimeSpan(rule.Period)).ToUniversalTime().ToString("o", DateTimeFormatInfo.InvariantInfo)); + } return headers; - throw new NotImplementedException(); - } + } public string ComputeCounterKey(ClientRequestIdentity requestIdentity, RateLimitOptions option) { 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; - using (var algorithm = System.Security.Cryptography.SHA1.Create()) + using (var algorithm = SHA1.Create()) { hashBytes = algorithm.ComputeHash(idBytes); } @@ -98,7 +95,7 @@ namespace Ocelot.RateLimit public string RetryAfterFrom(DateTime timestamp, RateLimitRule rule) { 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; return retryAfter.ToString(System.Globalization.CultureInfo.InvariantCulture); } @@ -111,11 +108,16 @@ namespace Ocelot.RateLimit switch (type) { - case "d": return TimeSpan.FromDays(double.Parse(value)); - case "h": return TimeSpan.FromHours(double.Parse(value)); - 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}"); + case "d": + return TimeSpan.FromDays(double.Parse(value)); + case "h": + return TimeSpan.FromHours(double.Parse(value)); + 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}"); } } diff --git a/src/Ocelot/RateLimit/RateLimitCounter.cs b/src/Ocelot/RateLimit/RateLimitCounter.cs index f0133b25..42dd03b7 100644 --- a/src/Ocelot/RateLimit/RateLimitCounter.cs +++ b/src/Ocelot/RateLimit/RateLimitCounter.cs @@ -10,8 +10,14 @@ namespace Ocelot.RateLimit /// 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; } } } diff --git a/src/Ocelot/RateLimit/RateLimitHeaders.cs b/src/Ocelot/RateLimit/RateLimitHeaders.cs index a7bd4ae6..909f656d 100644 --- a/src/Ocelot/RateLimit/RateLimitHeaders.cs +++ b/src/Ocelot/RateLimit/RateLimitHeaders.cs @@ -8,12 +8,20 @@ namespace Ocelot.RateLimit { 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; } } } diff --git a/test/Ocelot.AcceptanceTests/ClientRateLimitTests.cs b/test/Ocelot.AcceptanceTests/ClientRateLimitTests.cs index 2e8c3c90..dc2b2b31 100644 --- a/test/Ocelot.AcceptanceTests/ClientRateLimitTests.cs +++ b/test/Ocelot.AcceptanceTests/ClientRateLimitTests.cs @@ -67,7 +67,9 @@ namespace Ocelot.AcceptanceTests ClientIdHeader = "ClientId", DisableRateLimitHeaders = false, QuotaExceededMessage = "", - RateLimitCounterPrefix = "" + RateLimitCounterPrefix = "", + HttpStatusCode = 428 + }, RequestIdKey ="oceclientrequest" } @@ -76,8 +78,12 @@ namespace Ocelot.AcceptanceTests this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/api/ClientRateLimit")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) - .When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/api/ClientRateLimit", 5)) - .Then(x => _steps.ThenTheStatusCodeShouldBe(429)) + .When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/api/ClientRateLimit",1)) + .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(); } @@ -154,55 +160,6 @@ namespace Ocelot.AcceptanceTests _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); - //} + } } \ No newline at end of file diff --git a/test/Ocelot.AcceptanceTests/Steps.cs b/test/Ocelot.AcceptanceTests/Steps.cs index 5981c343..ebced901 100644 --- a/test/Ocelot.AcceptanceTests/Steps.cs +++ b/test/Ocelot.AcceptanceTests/Steps.cs @@ -101,7 +101,6 @@ namespace Ocelot.AcceptanceTests }) .WithDictionaryHandle(); }; - s.AddMemoryCache(); s.AddOcelotOutputCaching(settings); s.AddOcelotFileConfiguration(configuration); s.AddOcelot(); diff --git a/test/Ocelot.AcceptanceTests/configuration.json b/test/Ocelot.AcceptanceTests/configuration.json index af289aab..0a65abc2 100755 --- a/test/Ocelot.AcceptanceTests/configuration.json +++ b/test/Ocelot.AcceptanceTests/configuration.json @@ -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}}} \ No newline at end of file +{"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}}} \ No newline at end of file diff --git a/test/Ocelot.AcceptanceTests/project.json b/test/Ocelot.AcceptanceTests/project.json index 5457280f..2dd3094e 100644 --- a/test/Ocelot.AcceptanceTests/project.json +++ b/test/Ocelot.AcceptanceTests/project.json @@ -23,7 +23,6 @@ "Microsoft.AspNetCore.Http": "1.1.0", "Microsoft.DotNet.InternalAbstractions": "1.0.0", "Ocelot": "0.0.0-dev", - "xunit": "2.2.0-beta2-build3300", "dotnet-test-xunit": "2.2.0-preview2-build1029", "Ocelot.ManualTest": "0.0.0-dev", "Microsoft.AspNetCore.TestHost": "1.1.0", @@ -34,7 +33,8 @@ "Shouldly": "2.8.2", "TestStack.BDDfy": "4.3.2", "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": { "win10-x64": {}, diff --git a/test/Ocelot.ManualTest/Startup.cs b/test/Ocelot.ManualTest/Startup.cs index 2d8b7653..767aed43 100644 --- a/test/Ocelot.ManualTest/Startup.cs +++ b/test/Ocelot.ManualTest/Startup.cs @@ -37,7 +37,6 @@ namespace Ocelot.ManualTest }) .WithDictionaryHandle(); }; - services.AddMemoryCache(); services.AddOcelotOutputCaching(settings); services.AddOcelotFileConfiguration(Configuration); services.AddOcelot(); diff --git a/test/Ocelot.UnitTests/RateLimit/ClientRateLimitMiddlewareTests.cs b/test/Ocelot.UnitTests/RateLimit/ClientRateLimitMiddlewareTests.cs index 11bca113..72f66faa 100644 --- a/test/Ocelot.UnitTests/RateLimit/ClientRateLimitMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/RateLimit/ClientRateLimitMiddlewareTests.cs @@ -20,6 +20,7 @@ using Xunit; using TestStack.BDDfy; using Ocelot.Configuration.Builder; using Shouldly; +using Ocelot.Configuration; namespace Ocelot.UnitTests.RateLimit { @@ -70,11 +71,13 @@ namespace Ocelot.UnitTests.RateLimit { var downstreamRoute = new DownstreamRoute(new List(), new ReRouteBuilder().WithEnableRateLimiting(true).WithRateLimitOptions( - new Ocelot.Configuration.RateLimitOptions(true, "ClientId", new List(), false, "", "", new Ocelot.Configuration.RateLimitRule() { Limit = 3, Period = "1s", PeriodTimespan = TimeSpan.FromSeconds(100) },429)) + new Ocelot.Configuration.RateLimitOptions(true, "ClientId", new List(), false, "", "", new Ocelot.Configuration.RateLimitRule("1s", TimeSpan.FromSeconds(100), 3), 429)) .Build()); 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()) .BDDfy(); } @@ -84,7 +87,7 @@ namespace Ocelot.UnitTests.RateLimit { var downstreamRoute = new DownstreamRoute(new List(), new ReRouteBuilder().WithEnableRateLimiting(true).WithRateLimitOptions( - new Ocelot.Configuration.RateLimitOptions(true, "ClientId", new List() { "ocelotclient2" }, false, "", "", new Ocelot.Configuration.RateLimitRule() { Limit = 3, Period = "1s", PeriodTimespan = TimeSpan.FromSeconds(100) },429)) + new Ocelot.Configuration.RateLimitOptions(true, "ClientId", new List() { "ocelotclient2" }, false, "", "", new RateLimitRule( "1s", TimeSpan.FromSeconds(100),3),429)) .Build()); this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) @@ -102,11 +105,11 @@ namespace Ocelot.UnitTests.RateLimit .Returns(_downstreamRoute); } - private void WhenICallTheMiddleware() + private void WhenICallTheMiddlewareMultipleTime(int times) { var clientId = "ocelotclient1"; // Act - for (int i = 0; i <10; i++) + for (int i = 0; i < times; i++) { var request = new HttpRequestMessage(new HttpMethod("GET"), _url); request.Headers.Add("ClientId", clientId); diff --git a/test/Ocelot.UnitTests/project.json b/test/Ocelot.UnitTests/project.json index 3151ac57..2f42c283 100644 --- a/test/Ocelot.UnitTests/project.json +++ b/test/Ocelot.UnitTests/project.json @@ -14,7 +14,6 @@ "Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0", "Microsoft.AspNetCore.Http": "1.1.0", "Ocelot": "0.0.0-dev", - "xunit": "2.2.0-beta2-build3300", "dotnet-test-xunit": "2.2.0-preview2-build1029", "Moq": "4.6.38-alpha", "Microsoft.AspNetCore.TestHost": "1.1.0", @@ -24,7 +23,8 @@ "Shouldly": "2.8.2", "TestStack.BDDfy": "4.3.2", "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": { "win10-x64": {},