Merge remote-tracking branch 'refs/remotes/origin/develop' into RateLimit

# Conflicts:
#	src/Ocelot/Configuration/Builder/ReRouteBuilder.cs
#	src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs
#	src/Ocelot/Configuration/QoSOptions.cs
#	src/Ocelot/Configuration/ReRoute.cs
#	test/Ocelot.AcceptanceTests/configuration.json
This commit is contained in:
geffzhang
2017-02-15 08:49:40 +08:00
83 changed files with 1854 additions and 345 deletions

View File

@ -47,7 +47,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = _downstreamServicePort,
DownstreamHost = _downstreamServiceHost,
DownstreamScheme = _downstreamServiceScheme,
UpstreamTemplate = "/",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Post",
AuthenticationOptions = new FileAuthenticationOptions
{
@ -85,7 +85,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = _downstreamServicePort,
DownstreamHost = _downstreamServiceHost,
DownstreamScheme = _downstreamServiceScheme,
UpstreamTemplate = "/",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Post",
AuthenticationOptions = new FileAuthenticationOptions
{
@ -123,7 +123,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = _downstreamServicePort,
DownstreamHost = _downstreamServiceHost,
DownstreamScheme = _downstreamServiceScheme,
UpstreamTemplate = "/",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Get",
AuthenticationOptions = new FileAuthenticationOptions
{
@ -163,7 +163,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = _downstreamServicePort,
DownstreamHost = _downstreamServiceHost,
DownstreamScheme = _downstreamServiceScheme,
UpstreamTemplate = "/",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Post",
AuthenticationOptions = new FileAuthenticationOptions
@ -204,7 +204,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = _downstreamServicePort,
DownstreamHost = _downstreamServiceHost,
DownstreamScheme = _downstreamServiceScheme,
UpstreamTemplate = "/",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Post",
AuthenticationOptions = new FileAuthenticationOptions
{

View File

@ -41,7 +41,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 51876,
DownstreamScheme = "http",
DownstreamHost = "localhost",
UpstreamTemplate = "/",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Get",
AuthenticationOptions = new FileAuthenticationOptions
{
@ -98,7 +98,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 51876,
DownstreamScheme = "http",
DownstreamHost = "localhost",
UpstreamTemplate = "/",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Get",
AuthenticationOptions = new FileAuthenticationOptions
{

View File

@ -35,7 +35,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 51879,
DownstreamScheme = "http",
DownstreamHost = "localhost",
UpstreamTemplate = "/",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Get",
FileCacheOptions = new FileCacheOptions
{
@ -71,7 +71,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 51879,
DownstreamScheme = "http",
DownstreamHost = "localhost",
UpstreamTemplate = "/",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Get",
FileCacheOptions = new FileCacheOptions
{

View File

@ -34,7 +34,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 51879,
DownstreamScheme = "http",
DownstreamHost = "localhost",
UpstreamTemplate = "/products/{productId}",
UpstreamPathTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
}
}
@ -61,7 +61,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 51879,
DownstreamScheme = "http",
DownstreamHost = "localhost",
UpstreamTemplate = "/products/{productId}",
UpstreamPathTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = false,
}
@ -89,7 +89,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 51879,
DownstreamScheme = "http",
DownstreamHost = "localhost",
UpstreamTemplate = "/products/{productId}",
UpstreamPathTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true,
}
@ -117,7 +117,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 51879,
DownstreamScheme = "http",
DownstreamHost = "localhost",
UpstreamTemplate = "/PRODUCTS/{productId}",
UpstreamPathTemplate = "/PRODUCTS/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true,
}
@ -145,7 +145,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 51879,
DownstreamScheme = "http",
DownstreamHost = "localhost",
UpstreamTemplate = "/products/{productId}",
UpstreamPathTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true,
}
@ -173,7 +173,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 51879,
DownstreamScheme = "http",
DownstreamHost = "localhost",
UpstreamTemplate = "/PRODUCTS/{productId}",
UpstreamPathTemplate = "/PRODUCTS/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true,
}

View File

@ -55,7 +55,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 52876,
DownstreamScheme = "http",
DownstreamHost = "localhost",
UpstreamTemplate = "/",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Get",
AuthenticationOptions = new FileAuthenticationOptions
{

View File

@ -55,7 +55,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 57876,
DownstreamScheme = "http",
DownstreamHost = "localhost",
UpstreamTemplate = "/",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Get",
AuthenticationOptions = new FileAuthenticationOptions
{

View File

@ -46,7 +46,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 51879,
DownstreamScheme = "http",
DownstreamHost = "localhost",
UpstreamTemplate = "/api/ClientRateLimit",
UpstreamPathTemplate = "/api/ClientRateLimit",
UpstreamHttpMethod = "Get",
RequestIdKey = _steps.RequestIdKey,
@ -56,7 +56,7 @@ namespace Ocelot.AcceptanceTests
ClientWhitelist = new List<string>(),
Limit = 3,
Period = "1s",
PeriodTimespan = 100
PeriodTimespan = 1000
}
}
},
@ -101,7 +101,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 51879,
DownstreamScheme = "http",
DownstreamHost = "localhost",
UpstreamTemplate = "/api/ClientRateLimit",
UpstreamPathTemplate = "/api/ClientRateLimit",
UpstreamHttpMethod = "Get",
RequestIdKey = _steps.RequestIdKey,

View File

@ -49,7 +49,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 41879,
DownstreamScheme = "http",
DownstreamHost = "localhost",
UpstreamTemplate = "/",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Get",
}
}
@ -86,7 +86,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 41879,
DownstreamScheme = "http",
DownstreamHost = "localhost",
UpstreamTemplate = "/",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Get",
}
@ -124,7 +124,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 41879,
DownstreamScheme = "http",
DownstreamHost = "localhost",
UpstreamTemplate = "/",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Get",
}
@ -162,7 +162,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 41879,
DownstreamScheme = "http",
DownstreamHost = "localhost",
UpstreamTemplate = "/",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Get",
}
}
@ -199,7 +199,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 41879,
DownstreamScheme = "http",
DownstreamHost = "localhost",
UpstreamTemplate = "/",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Get",
}
}
@ -236,7 +236,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 41879,
DownstreamScheme = "http",
DownstreamHost = "localhost",
UpstreamTemplate = "/",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Get",
}
}

View File

@ -0,0 +1,206 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.AcceptanceTests
{
public class QoSTests : IDisposable
{
private IWebHost _brokenService;
private readonly Steps _steps;
private int _requestCount;
private IWebHost _workingService;
public QoSTests()
{
_steps = new Steps();
}
[Fact]
public void should_open_circuit_breaker_then_close()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHost = "localhost",
DownstreamPort = 51879,
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Get",
QoSOptions = new FileQoSOptions
{
ExceptionsAllowedBeforeBreaking = 1,
TimeoutValue = 500,
DurationOfBreak = 1000
}
}
}
};
this.Given(x => x.GivenThereIsAPossiblyBrokenServiceRunningOn("http://localhost:51879", "Hello from Laura"))
.Given(x => _steps.GivenThereIsAConfiguration(configuration))
.Given(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.Given(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Given(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
.Given(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Given(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
.Given(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Given(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
.Given(x => x.GivenIWaitMilliseconds(3000))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void open_circuit_should_not_effect_different_reRoute()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHost = "localhost",
DownstreamPort = 51879,
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Get",
QoSOptions = new FileQoSOptions
{
ExceptionsAllowedBeforeBreaking = 1,
TimeoutValue = 500,
DurationOfBreak = 1000
}
},
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHost = "localhost",
DownstreamPort = 51880,
UpstreamPathTemplate = "working",
UpstreamHttpMethod = "Get",
}
}
};
this.Given(x => x.GivenThereIsAPossiblyBrokenServiceRunningOn("http://localhost:51879", "Hello from Laura"))
.And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51880/", 200, "Hello from Tom"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.And(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.And(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
.And(x => _steps.WhenIGetUrlOnTheApiGateway("/working"))
.And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Tom"))
.And(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
.And(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
.And(x => x.GivenIWaitMilliseconds(3000))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
private void GivenIWaitMilliseconds(int ms)
{
Thread.Sleep(ms);
}
private void GivenThereIsAPossiblyBrokenServiceRunningOn(string url, string responseBody)
{
_brokenService = new WebHostBuilder()
.UseUrls(url)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseUrls(url)
.Configure(app =>
{
app.Run(async context =>
{
//circuit starts closed
if (_requestCount == 0)
{
_requestCount++;
context.Response.StatusCode = 200;
await context.Response.WriteAsync(responseBody);
return;
}
//request one times out and polly throws exception, circuit opens
if (_requestCount == 1)
{
_requestCount++;
await Task.Delay(1000);
context.Response.StatusCode = 200;
return;
}
//after break closes we return 200 OK
if (_requestCount == 2)
{
context.Response.StatusCode = 200;
await context.Response.WriteAsync(responseBody);
return;
}
});
})
.Build();
_brokenService.Start();
}
private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody)
{
_workingService = new WebHostBuilder()
.UseUrls(url)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseUrls(url)
.Configure(app =>
{
app.Run(async context =>
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
});
})
.Build();
_workingService.Start();
}
public void Dispose()
{
_workingService?.Dispose();
_brokenService?.Dispose();
_steps.Dispose();
}
}
}

View File

@ -37,7 +37,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 51879,
DownstreamScheme = "http",
DownstreamHost = "localhost",
UpstreamTemplate = "/",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Get",
RequestIdKey = _steps.RequestIdKey,
}
@ -65,7 +65,7 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 51879,
DownstreamScheme = "http",
DownstreamHost = "localhost",
UpstreamTemplate = "/",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Get",
}
@ -95,8 +95,8 @@ namespace Ocelot.AcceptanceTests
DownstreamPort = 51879,
DownstreamScheme = "http",
DownstreamHost = "localhost",
UpstreamTemplate = "/",
UpstreamHttpMethod ="Get"
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Get",
}
},
GlobalConfiguration = new FileGlobalConfiguration

View File

@ -30,7 +30,7 @@ namespace Ocelot.AcceptanceTests
new FileReRoute
{
DownstreamPathTemplate = "http://localhost:53876/",
UpstreamTemplate = "/",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Get"
}
}

View File

@ -44,7 +44,7 @@ namespace Ocelot.AcceptanceTests
DownstreamScheme = "http",
DownstreamHost = "localhost",
DownstreamPort = 51879,
UpstreamTemplate = "/",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Get",
}
@ -73,7 +73,7 @@ namespace Ocelot.AcceptanceTests
DownstreamScheme = "http",
DownstreamHost = "localhost",
DownstreamPort = 51879,
UpstreamTemplate = "/",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Get",
}
@ -102,7 +102,7 @@ namespace Ocelot.AcceptanceTests
DownstreamScheme = "http",
DownstreamHost = "localhost/",
DownstreamPort = 51879,
UpstreamTemplate = "/",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Get",
}
@ -131,7 +131,7 @@ namespace Ocelot.AcceptanceTests
DownstreamScheme = "http",
DownstreamHost = "localhost",
DownstreamPort = 51879,
UpstreamTemplate = "/products/",
UpstreamPathTemplate = "/products/",
UpstreamHttpMethod = "Get",
}
@ -160,9 +160,8 @@ namespace Ocelot.AcceptanceTests
DownstreamScheme = "http",
DownstreamHost = "localhost",
DownstreamPort = 51879,
UpstreamTemplate = "/products",
UpstreamPathTemplate = "/products",
UpstreamHttpMethod = "Get",
}
}
};
@ -182,22 +181,23 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
new FileReRoute
DownstreamPathTemplate = "/products",
DownstreamScheme = "http",
DownstreamHost = "localhost",
DownstreamPort = 51879,
UpstreamPathTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
QoSOptions = new FileQoSOptions()
{
DownstreamPathTemplate = "/products",
DownstreamScheme = "http",
DownstreamHost = "localhost",
DownstreamPort = 51879,
UpstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
QoSOptions = new FileQoSOptions()
{
ExceptionsAllowedBeforeBreaking = 3,
DurationOfBreak =5,
TimeoutValue = 5000 }
DurationOfBreak = 5,
TimeoutValue = 5000
}
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/products", 200, "Hello from Laura"))
@ -221,7 +221,7 @@ namespace Ocelot.AcceptanceTests
DownstreamScheme = "http",
DownstreamHost = "localhost",
DownstreamPort = 51879,
UpstreamTemplate = "/products/{productId}",
UpstreamPathTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
}
}
@ -249,7 +249,7 @@ namespace Ocelot.AcceptanceTests
DownstreamHost = "localhost",
DownstreamPort = 51879,
DownstreamScheme = "http",
UpstreamTemplate = "/",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Post",
}
}
@ -274,7 +274,7 @@ namespace Ocelot.AcceptanceTests
new FileReRoute
{
DownstreamPathTemplate = "/newThing",
UpstreamTemplate = "/newThing",
UpstreamPathTemplate = "/newThing",
DownstreamScheme = "http",
DownstreamHost = "localhost",
DownstreamPort = 51879,

View File

@ -68,7 +68,7 @@ namespace Ocelot.AcceptanceTests
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
UpstreamTemplate = "/",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = "Get",
ServiceName = serviceName,
LoadBalancer = "LeastConnection",