Now defaults to case insensitive routing but you can override with a setting, also global request id setting available

This commit is contained in:
TomPallister
2016-11-06 11:50:33 +00:00
parent 30c668bfdf
commit ff5776613f
11 changed files with 552 additions and 109 deletions

View File

@ -0,0 +1,200 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
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 CaseSensitiveRoutingTests : IDisposable
{
private IWebHost _builder;
private readonly Steps _steps;
public CaseSensitiveRoutingTests()
{
_steps = new Steps();
}
[Fact]
public void should_return_response_200_when_global_ignore_case_sensitivity_set()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamTemplate = "http://localhost:51879/api/products/{productId}",
UpstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get"
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/api/products/1", 200, "Some Product"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/PRODUCTS/1"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.BDDfy();
}
[Fact]
public void should_return_response_200_when_reroute_ignore_case_sensitivity_set()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamTemplate = "http://localhost:51879/api/products/{productId}",
UpstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = false
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/api/products/1", 200, "Some Product"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/PRODUCTS/1"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.BDDfy();
}
[Fact]
public void should_return_response_404_when_reroute_respect_case_sensitivity_set()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamTemplate = "http://localhost:51879/api/products/{productId}",
UpstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/api/products/1", 200, "Some Product"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/PRODUCTS/1"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound))
.BDDfy();
}
[Fact]
public void should_return_response_200_when_reroute_respect_case_sensitivity_set()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamTemplate = "http://localhost:51879/api/products/{productId}",
UpstreamTemplate = "/PRODUCTS/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/api/products/1", 200, "Some Product"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/PRODUCTS/1"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.BDDfy();
}
[Fact]
public void should_return_response_404_when_global_respect_case_sensitivity_set()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamTemplate = "http://localhost:51879/api/products/{productId}",
UpstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/api/products/1", 200, "Some Product"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/PRODUCTS/1"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound))
.BDDfy();
}
[Fact]
public void should_return_response_200_when_global_respect_case_sensitivity_set()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamTemplate = "http://localhost:51879/api/products/{productId}",
UpstreamTemplate = "/PRODUCTS/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/api/products/1", 200, "Some Product"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/PRODUCTS/1"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody)
{
_builder = 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();
_builder.Start();
}
public void Dispose()
{
_builder?.Dispose();
_steps.Dispose();
}
}
}

View File

@ -76,6 +76,36 @@ namespace Ocelot.AcceptanceTests
.BDDfy();
}
[Fact]
public void should_use_global_request_id_and_forward()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamTemplate = "http://localhost:51879/",
UpstreamTemplate = "/",
UpstreamHttpMethod = "Get",
}
},
GlobalConfiguration = new FileGlobalConfiguration
{
RequestIdKey = _steps.RequestIdKey
}
};
var requestId = Guid.NewGuid().ToString();
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/", requestId))
.Then(x => _steps.ThenTheRequestIdIsReturned(requestId))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string url)
{
_builder = new WebHostBuilder()

View File

@ -1 +1 @@
{"ReRoutes":[{"DownstreamTemplate":"http://localhost: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}}]}
{"ReRoutes":[{"DownstreamTemplate":"http://localhost: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}],"GlobalConfiguration":{"RequestIdKey":null}}

View File

@ -36,7 +36,37 @@ namespace Ocelot.UnitTests.Configuration
}
[Fact]
public void should_create_template_pattern_that_matches_anything_to_end_of_string()
public void should_use_reroute_case_sensitivity_value()
{
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
UpstreamTemplate = "/api/products/{productId}",
DownstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = false
}
}
}))
.And(x => x.GivenTheConfigIsValid())
.When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheReRoutesAre(new List<ReRoute>
{
new ReRouteBuilder()
.WithDownstreamTemplate("/products/{productId}")
.WithUpstreamTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod("Get")
.WithUpstreamTemplatePattern("(?i)/api/products/.*$")
.Build()
}))
.BDDfy();
}
[Fact]
public void should_set_upstream_template_pattern_to_ignore_case_sensitivity()
{
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
{
@ -49,6 +79,101 @@ namespace Ocelot.UnitTests.Configuration
UpstreamHttpMethod = "Get"
}
}
}))
.And(x => x.GivenTheConfigIsValid())
.When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheReRoutesAre(new List<ReRoute>
{
new ReRouteBuilder()
.WithDownstreamTemplate("/products/{productId}")
.WithUpstreamTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod("Get")
.WithUpstreamTemplatePattern("(?i)/api/products/.*$")
.Build()
}))
.BDDfy();
}
[Fact]
public void should_set_upstream_template_pattern_to_respect_case_sensitivity()
{
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
UpstreamTemplate = "/api/products/{productId}",
DownstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true
}
}
}))
.And(x => x.GivenTheConfigIsValid())
.When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheReRoutesAre(new List<ReRoute>
{
new ReRouteBuilder()
.WithDownstreamTemplate("/products/{productId}")
.WithUpstreamTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod("Get")
.WithUpstreamTemplatePattern("/api/products/.*$")
.Build()
}))
.BDDfy();
}
[Fact]
public void should_set_global_request_id_key()
{
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
UpstreamTemplate = "/api/products/{productId}",
DownstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true
}
},
GlobalConfiguration = new FileGlobalConfiguration
{
RequestIdKey = "blahhhh"
}
}))
.And(x => x.GivenTheConfigIsValid())
.When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheReRoutesAre(new List<ReRoute>
{
new ReRouteBuilder()
.WithDownstreamTemplate("/products/{productId}")
.WithUpstreamTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod("Get")
.WithUpstreamTemplatePattern("/api/products/.*$")
.WithRequestIdKey("blahhhh")
.Build()
}))
.BDDfy();
}
[Fact]
public void should_create_template_pattern_that_matches_anything_to_end_of_string()
{
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
UpstreamTemplate = "/api/products/{productId}",
DownstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true
}
}
}))
.And(x => x.GivenTheConfigIsValid())
.When(x => x.WhenICreateTheConfig())
@ -95,6 +220,7 @@ namespace Ocelot.UnitTests.Configuration
UpstreamTemplate = "/api/products/{productId}",
DownstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true,
AuthenticationOptions = new FileAuthenticationOptions
{
AdditionalScopes = new List<string>(),
@ -153,6 +279,7 @@ namespace Ocelot.UnitTests.Configuration
UpstreamTemplate = "/api/products/{productId}",
DownstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true,
AuthenticationOptions = new FileAuthenticationOptions
{
AdditionalScopes = new List<string>(),
@ -183,7 +310,8 @@ namespace Ocelot.UnitTests.Configuration
{
UpstreamTemplate = "/api/products/{productId}/variants/{variantId}",
DownstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get"
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true
}
}
}))
@ -212,7 +340,8 @@ namespace Ocelot.UnitTests.Configuration
{
UpstreamTemplate = "/api/products/{productId}/variants/{variantId}/",
DownstreamTemplate = "/products/{productId}",
UpstreamHttpMethod = "Get"
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true
}
}
}))
@ -241,7 +370,8 @@ namespace Ocelot.UnitTests.Configuration
{
UpstreamTemplate = "/",
DownstreamTemplate = "/api/products/",
UpstreamHttpMethod = "Get"
UpstreamHttpMethod = "Get",
ReRouteIsCaseSensitive = true
}
}
}))

View File

@ -128,6 +128,27 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
.BDDfy();
}
[Fact]
public void should_ignore_case_sensitivity()
{
this.Given(x => x.GivenIHaveAUpstreamPath("API/product/products/1/categories/2/variant/"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("(?i)api/product/products/.*/categories/.*/variant/$"))
.When(x => x.WhenIMatchThePaths())
.Then(x => x.ThenTheResultIsTrue())
.BDDfy();
}
[Fact]
public void should_respect_case_sensitivity()
{
this.Given(x => x.GivenIHaveAUpstreamPath("API/product/products/1/categories/2/variant/"))
.And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/.*/categories/.*/variant/$"))
.When(x => x.WhenIMatchThePaths())
.Then(x => x.ThenTheResultIsFalse())
.BDDfy();
}
private void GivenIHaveAUpstreamPath(string downstreamPath)
{
_downstreamUrlPath = downstreamPath;