implemented simple priority in the routing

This commit is contained in:
Tom Gardham-Pallister 2018-01-05 21:14:17 +00:00
parent 9f8da1fbe4
commit 9de00d6a46
12 changed files with 197 additions and 46 deletions

View File

@ -80,9 +80,7 @@ Ocelot's routing also supports a catch all style routing where the user can spec
"UpstreamHttpMethod": [ "Get" ] "UpstreamHttpMethod": [ "Get" ]
} }
There is a gotcha if you want to do this kind of thing. The order of the ReRoutes in the config will now matter. The catch all has a lower priority than any other ReRoute. If you also have the ReRoute below in your config then Ocelot would match it before the catch all.
If you had this ReRoute after the catch all then it would never be matched. However if it was before the catch all it would match first.
.. code-block:: json .. code-block:: json
@ -94,5 +92,3 @@ If you had this ReRoute after the catch all then it would never be matched. Howe
"UpstreamPathTemplate": "/", "UpstreamPathTemplate": "/",
"UpstreamHttpMethod": [ "Get" ] "UpstreamHttpMethod": [ "Get" ]
} }
This is because when Ocelot tries to match a request to a ReRoute it has to look at all the possible matches and uses a regular expression to test the url.

View File

@ -2,6 +2,7 @@
using System.Net.Http; using System.Net.Http;
using Ocelot.Values; using Ocelot.Values;
using System.Linq; using System.Linq;
using Ocelot.Configuration.Creator;
namespace Ocelot.Configuration.Builder namespace Ocelot.Configuration.Builder
{ {
@ -11,7 +12,7 @@ namespace Ocelot.Configuration.Builder
private string _loadBalancerKey; private string _loadBalancerKey;
private string _downstreamPathTemplate; private string _downstreamPathTemplate;
private string _upstreamTemplate; private string _upstreamTemplate;
private string _upstreamTemplatePattern; private UpstreamPathTemplate _upstreamTemplatePattern;
private List<HttpMethod> _upstreamHttpMethod; private List<HttpMethod> _upstreamHttpMethod;
private bool _isAuthenticated; private bool _isAuthenticated;
private List<ClaimToThing> _configHeaderExtractorProperties; private List<ClaimToThing> _configHeaderExtractorProperties;
@ -65,7 +66,7 @@ namespace Ocelot.Configuration.Builder
return this; return this;
} }
public ReRouteBuilder WithUpstreamTemplatePattern(string input) public ReRouteBuilder WithUpstreamTemplatePattern(UpstreamPathTemplate input)
{ {
_upstreamTemplatePattern = input; _upstreamTemplatePattern = input;
return this; return this;

View File

@ -1,9 +1,10 @@
using Ocelot.Configuration.File; using Ocelot.Configuration.File;
using Ocelot.Values;
namespace Ocelot.Configuration.Creator namespace Ocelot.Configuration.Creator
{ {
public interface IUpstreamTemplatePatternCreator public interface IUpstreamTemplatePatternCreator
{ {
string Create(FileReRoute reRoute); UpstreamPathTemplate Create(FileReRoute reRoute);
} }
} }

View File

@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using Ocelot.Configuration.File; using Ocelot.Configuration.File;
using Ocelot.Values;
namespace Ocelot.Configuration.Creator namespace Ocelot.Configuration.Creator
{ {
@ -11,7 +12,7 @@ namespace Ocelot.Configuration.Creator
private const string RegExForwardSlashOnly = "^/$"; private const string RegExForwardSlashOnly = "^/$";
private const string RegExForwardSlashAndOnePlaceHolder = "^/.*"; private const string RegExForwardSlashAndOnePlaceHolder = "^/.*";
public string Create(FileReRoute reRoute) public UpstreamPathTemplate Create(FileReRoute reRoute)
{ {
var upstreamTemplate = reRoute.UpstreamPathTemplate; var upstreamTemplate = reRoute.UpstreamPathTemplate;
@ -29,7 +30,7 @@ namespace Ocelot.Configuration.Creator
//hack to handle /{url} case //hack to handle /{url} case
if(ForwardSlashAndOnePlaceHolder(upstreamTemplate, placeholders, postitionOfPlaceHolderClosingBracket)) if(ForwardSlashAndOnePlaceHolder(upstreamTemplate, placeholders, postitionOfPlaceHolderClosingBracket))
{ {
return RegExForwardSlashAndOnePlaceHolder; return new UpstreamPathTemplate(RegExForwardSlashAndOnePlaceHolder, 0);
} }
} }
} }
@ -41,7 +42,7 @@ namespace Ocelot.Configuration.Creator
if (upstreamTemplate == "/") if (upstreamTemplate == "/")
{ {
return RegExForwardSlashOnly; return new UpstreamPathTemplate(RegExForwardSlashOnly, 1);
} }
if(upstreamTemplate.EndsWith("/")) if(upstreamTemplate.EndsWith("/"))
@ -53,7 +54,7 @@ namespace Ocelot.Configuration.Creator
? $"^{upstreamTemplate}{RegExMatchEndString}" ? $"^{upstreamTemplate}{RegExMatchEndString}"
: $"^{RegExIgnoreCase}{upstreamTemplate}{RegExMatchEndString}"; : $"^{RegExIgnoreCase}{upstreamTemplate}{RegExMatchEndString}";
return route; return new UpstreamPathTemplate(route, 1);
} }
private bool ForwardSlashAndOnePlaceHolder(string upstreamTemplate, List<string> placeholders, int postitionOfPlaceHolderClosingBracket) private bool ForwardSlashAndOnePlaceHolder(string upstreamTemplate, List<string> placeholders, int postitionOfPlaceHolderClosingBracket)

View File

@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Http; using System.Net.Http;
using Ocelot.Configuration.Creator;
using Ocelot.Values; using Ocelot.Values;
namespace Ocelot.Configuration namespace Ocelot.Configuration
@ -9,7 +10,7 @@ namespace Ocelot.Configuration
public ReRoute(PathTemplate downstreamPathTemplate, public ReRoute(PathTemplate downstreamPathTemplate,
PathTemplate upstreamPathTemplate, PathTemplate upstreamPathTemplate,
List<HttpMethod> upstreamHttpMethod, List<HttpMethod> upstreamHttpMethod,
string upstreamTemplatePattern, UpstreamPathTemplate upstreamTemplatePattern,
bool isAuthenticated, bool isAuthenticated,
AuthenticationOptions authenticationOptions, AuthenticationOptions authenticationOptions,
List<ClaimToThing> claimsToHeaders, List<ClaimToThing> claimsToHeaders,
@ -67,7 +68,7 @@ namespace Ocelot.Configuration
public string ReRouteKey {get;private set;} public string ReRouteKey {get;private set;}
public PathTemplate DownstreamPathTemplate { get; private set; } public PathTemplate DownstreamPathTemplate { get; private set; }
public PathTemplate UpstreamPathTemplate { get; private set; } public PathTemplate UpstreamPathTemplate { get; private set; }
public string UpstreamTemplatePattern { get; private set; } public UpstreamPathTemplate UpstreamTemplatePattern { get; private set; }
public List<HttpMethod> UpstreamHttpMethod { get; private set; } public List<HttpMethod> UpstreamHttpMethod { get; private set; }
public bool IsAuthenticated { get; private set; } public bool IsAuthenticated { get; private set; }
public bool IsAuthorised { get; private set; } public bool IsAuthorised { get; private set; }

View File

@ -13,34 +13,30 @@ namespace Ocelot.DownstreamRouteFinder.Finder
public class DownstreamRouteFinder : IDownstreamRouteFinder public class DownstreamRouteFinder : IDownstreamRouteFinder
{ {
private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; private readonly IUrlPathToUrlTemplateMatcher _urlMatcher;
private readonly IPlaceholderNameAndValueFinder _urlPathPlaceholderNameAndValueFinder; private readonly IPlaceholderNameAndValueFinder __placeholderNameAndValueFinder;
public DownstreamRouteFinder(IUrlPathToUrlTemplateMatcher urlMatcher, IPlaceholderNameAndValueFinder urlPathPlaceholderNameAndValueFinder) public DownstreamRouteFinder(IUrlPathToUrlTemplateMatcher urlMatcher, IPlaceholderNameAndValueFinder urlPathPlaceholderNameAndValueFinder)
{ {
_urlMatcher = urlMatcher; _urlMatcher = urlMatcher;
_urlPathPlaceholderNameAndValueFinder = urlPathPlaceholderNameAndValueFinder; __placeholderNameAndValueFinder = urlPathPlaceholderNameAndValueFinder;
} }
public Response<DownstreamRoute> FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod, IOcelotConfiguration configuration) public Response<DownstreamRoute> FindDownstreamRoute(string path, string httpMethod, IOcelotConfiguration configuration)
{ {
var applicableReRoutes = configuration.ReRoutes.Where(r => r.UpstreamHttpMethod.Count == 0 || r.UpstreamHttpMethod.Select(x => x.Method.ToLower()).Contains(upstreamHttpMethod.ToLower())); var applicableReRoutes = configuration.ReRoutes.Where(r => r.UpstreamHttpMethod.Count == 0 || r.UpstreamHttpMethod.Select(x => x.Method.ToLower()).Contains(httpMethod.ToLower())).OrderByDescending(x => x.UpstreamTemplatePattern.Priority);
foreach (var reRoute in applicableReRoutes) foreach (var reRoute in applicableReRoutes)
{ {
if (upstreamUrlPath == reRoute.UpstreamTemplatePattern) if (path == reRoute.UpstreamTemplatePattern.Template)
{ {
var templateVariableNameAndValues = _urlPathPlaceholderNameAndValueFinder.Find(upstreamUrlPath, reRoute.UpstreamPathTemplate.Value); return GetPlaceholderNamesAndValues(path, reRoute);
return new OkResponse<DownstreamRoute>(new DownstreamRoute(templateVariableNameAndValues.Data, reRoute));
} }
var urlMatch = _urlMatcher.Match(upstreamUrlPath, reRoute.UpstreamTemplatePattern); var urlMatch = _urlMatcher.Match(path, reRoute.UpstreamTemplatePattern.Template);
if (urlMatch.Data.Match) if (urlMatch.Data.Match)
{ {
var templateVariableNameAndValues = _urlPathPlaceholderNameAndValueFinder.Find(upstreamUrlPath, reRoute.UpstreamPathTemplate.Value); return GetPlaceholderNamesAndValues(path, reRoute);
return new OkResponse<DownstreamRoute>(new DownstreamRoute(templateVariableNameAndValues.Data, reRoute));
} }
} }
@ -49,5 +45,12 @@ namespace Ocelot.DownstreamRouteFinder.Finder
new UnableToFindDownstreamRouteError() new UnableToFindDownstreamRouteError()
}); });
} }
private OkResponse<DownstreamRoute> GetPlaceholderNamesAndValues(string path, ReRoute reRoute)
{
var templatePlaceholderNameAndValues = __placeholderNameAndValueFinder.Find(path, reRoute.UpstreamPathTemplate.Value);
return new OkResponse<DownstreamRoute>(new DownstreamRoute(templatePlaceholderNameAndValues.Data, reRoute));
}
} }
} }

View File

@ -0,0 +1,14 @@
namespace Ocelot.Values
{
public class UpstreamPathTemplate
{
public UpstreamPathTemplate(string template, int priority)
{
Template = template;
Priority = priority;
}
public string Template {get;}
public int Priority {get;}
}
}

View File

@ -98,6 +98,43 @@ namespace Ocelot.AcceptanceTests
.BDDfy(); .BDDfy();
} }
[Fact]
public void should_return_response_200_favouring_forward_slash()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/{url}",
DownstreamScheme = "http",
DownstreamHost = "localhost",
DownstreamPort = 51880,
UpstreamPathTemplate = "/{url}",
UpstreamHttpMethod = new List<string> { "Get" },
},
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHost = "localhost",
DownstreamPort = 51879,
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/", "/", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact] [Fact]
public void should_return_response_200_favouring_forward_slash_route_because_it_is_first() public void should_return_response_200_favouring_forward_slash_route_because_it_is_first()
{ {

View File

@ -18,6 +18,7 @@ namespace Ocelot.UnitTests.Configuration
using Ocelot.DependencyInjection; using Ocelot.DependencyInjection;
using Ocelot.Errors; using Ocelot.Errors;
using Ocelot.UnitTests.TestData; using Ocelot.UnitTests.TestData;
using Ocelot.Values;
public class FileConfigurationCreatorTests public class FileConfigurationCreatorTests
{ {
@ -367,7 +368,7 @@ namespace Ocelot.UnitTests.Configuration
.WithDownstreamPathTemplate("/products/{productId}") .WithDownstreamPathTemplate("/products/{productId}")
.WithUpstreamPathTemplate("/api/products/{productId}") .WithUpstreamPathTemplate("/api/products/{productId}")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern("(?i)/api/products/.*/$") .WithUpstreamTemplatePattern(new UpstreamPathTemplate("(?i)/api/products/.*/$", 1))
.Build() .Build()
})) }))
.BDDfy(); .BDDfy();
@ -580,7 +581,7 @@ namespace Ocelot.UnitTests.Configuration
result.DownstreamPathTemplate.Value.ShouldBe(expected.DownstreamPathTemplate.Value); result.DownstreamPathTemplate.Value.ShouldBe(expected.DownstreamPathTemplate.Value);
result.UpstreamHttpMethod.ShouldBe(expected.UpstreamHttpMethod); result.UpstreamHttpMethod.ShouldBe(expected.UpstreamHttpMethod);
result.UpstreamPathTemplate.Value.ShouldBe(expected.UpstreamPathTemplate.Value); result.UpstreamPathTemplate.Value.ShouldBe(expected.UpstreamPathTemplate.Value);
result.UpstreamTemplatePattern.ShouldBe(expected.UpstreamTemplatePattern); result.UpstreamTemplatePattern?.Template.ShouldBe(expected.UpstreamTemplatePattern?.Template);
result.ClaimsToClaims.Count.ShouldBe(expected.ClaimsToClaims.Count); result.ClaimsToClaims.Count.ShouldBe(expected.ClaimsToClaims.Count);
result.ClaimsToHeaders.Count.ShouldBe(expected.ClaimsToHeaders.Count); result.ClaimsToHeaders.Count.ShouldBe(expected.ClaimsToHeaders.Count);
result.ClaimsToQueries.Count.ShouldBe(expected.ClaimsToQueries.Count); result.ClaimsToQueries.Count.ShouldBe(expected.ClaimsToQueries.Count);
@ -623,7 +624,7 @@ namespace Ocelot.UnitTests.Configuration
{ {
_upstreamTemplatePatternCreator _upstreamTemplatePatternCreator
.Setup(x => x.Create(It.IsAny<FileReRoute>())) .Setup(x => x.Create(It.IsAny<FileReRoute>()))
.Returns(pattern); .Returns(new UpstreamPathTemplate(pattern, 1));
} }
private void ThenTheRequestIdKeyCreatorIsCalledCorrectly() private void ThenTheRequestIdKeyCreatorIsCalledCorrectly()

View File

@ -1,5 +1,7 @@
using System;
using Ocelot.Configuration.Creator; using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File; using Ocelot.Configuration.File;
using Ocelot.Values;
using Shouldly; using Shouldly;
using TestStack.BDDfy; using TestStack.BDDfy;
using Xunit; using Xunit;
@ -10,7 +12,7 @@ namespace Ocelot.UnitTests.Configuration
{ {
private FileReRoute _fileReRoute; private FileReRoute _fileReRoute;
private UpstreamTemplatePatternCreator _creator; private UpstreamTemplatePatternCreator _creator;
private string _result; private UpstreamPathTemplate _result;
public UpstreamTemplatePatternCreatorTests() public UpstreamTemplatePatternCreatorTests()
{ {
@ -29,6 +31,7 @@ namespace Ocelot.UnitTests.Configuration
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern()) .When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^(?i)/PRODUCTS/[0-9a-zA-Z].*$")) .Then(x => x.ThenTheFollowingIsReturned("^(?i)/PRODUCTS/[0-9a-zA-Z].*$"))
.And(x => ThenThePriorityIs(1))
.BDDfy(); .BDDfy();
} }
@ -45,6 +48,7 @@ namespace Ocelot.UnitTests.Configuration
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern()) .When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^(?i)/PRODUCTS(/|)$")) .Then(x => x.ThenTheFollowingIsReturned("^(?i)/PRODUCTS(/|)$"))
.And(x => ThenThePriorityIs(1))
.BDDfy(); .BDDfy();
} }
@ -59,6 +63,7 @@ namespace Ocelot.UnitTests.Configuration
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern()) .When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^/PRODUCTS/[0-9a-zA-Z].*$")) .Then(x => x.ThenTheFollowingIsReturned("^/PRODUCTS/[0-9a-zA-Z].*$"))
.And(x => ThenThePriorityIs(1))
.BDDfy(); .BDDfy();
} }
@ -74,6 +79,7 @@ namespace Ocelot.UnitTests.Configuration
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern()) .When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^/api/products/[0-9a-zA-Z].*$")) .Then(x => x.ThenTheFollowingIsReturned("^/api/products/[0-9a-zA-Z].*$"))
.And(x => ThenThePriorityIs(1))
.BDDfy(); .BDDfy();
} }
@ -89,6 +95,7 @@ namespace Ocelot.UnitTests.Configuration
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern()) .When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^/api/products/[0-9a-zA-Z].*/variants/[0-9a-zA-Z].*$")) .Then(x => x.ThenTheFollowingIsReturned("^/api/products/[0-9a-zA-Z].*/variants/[0-9a-zA-Z].*$"))
.And(x => ThenThePriorityIs(1))
.BDDfy(); .BDDfy();
} }
@ -104,6 +111,7 @@ namespace Ocelot.UnitTests.Configuration
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern()) .When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^/api/products/[0-9a-zA-Z].*/variants/[0-9a-zA-Z].*(/|)$")) .Then(x => x.ThenTheFollowingIsReturned("^/api/products/[0-9a-zA-Z].*/variants/[0-9a-zA-Z].*(/|)$"))
.And(x => ThenThePriorityIs(1))
.BDDfy(); .BDDfy();
} }
@ -118,6 +126,7 @@ namespace Ocelot.UnitTests.Configuration
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern()) .When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^/$")) .Then(x => x.ThenTheFollowingIsReturned("^/$"))
.And(x => ThenThePriorityIs(1))
.BDDfy(); .BDDfy();
} }
@ -132,6 +141,7 @@ namespace Ocelot.UnitTests.Configuration
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern()) .When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^/.*")) .Then(x => x.ThenTheFollowingIsReturned("^/.*"))
.And(x => ThenThePriorityIs(0))
.BDDfy(); .BDDfy();
} }
@ -147,6 +157,7 @@ namespace Ocelot.UnitTests.Configuration
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern()) .When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^/[0-9a-zA-Z].*/products/variants/[0-9a-zA-Z].*(/|)$")) .Then(x => x.ThenTheFollowingIsReturned("^/[0-9a-zA-Z].*/products/variants/[0-9a-zA-Z].*(/|)$"))
.And(x => ThenThePriorityIs(1))
.BDDfy(); .BDDfy();
} }
@ -162,7 +173,12 @@ namespace Ocelot.UnitTests.Configuration
private void ThenTheFollowingIsReturned(string expected) private void ThenTheFollowingIsReturned(string expected)
{ {
_result.ShouldBe(expected); _result.Template.ShouldBe(expected);
}
private void ThenThePriorityIs(int v)
{
_result.Priority.ShouldBe(v);
} }
} }
} }

View File

@ -2,11 +2,13 @@
using Moq; using Moq;
using Ocelot.Configuration; using Ocelot.Configuration;
using Ocelot.Configuration.Builder; using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.Provider; using Ocelot.Configuration.Provider;
using Ocelot.DownstreamRouteFinder; using Ocelot.DownstreamRouteFinder;
using Ocelot.DownstreamRouteFinder.Finder; using Ocelot.DownstreamRouteFinder.Finder;
using Ocelot.DownstreamRouteFinder.UrlMatcher; using Ocelot.DownstreamRouteFinder.UrlMatcher;
using Ocelot.Responses; using Ocelot.Responses;
using Ocelot.Values;
using Shouldly; using Shouldly;
using TestStack.BDDfy; using TestStack.BDDfy;
using Xunit; using Xunit;
@ -32,6 +34,80 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
_downstreamRouteFinder = new Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteFinder(_mockMatcher.Object, _finder.Object); _downstreamRouteFinder = new Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteFinder(_mockMatcher.Object, _finder.Object);
} }
[Fact]
public void should_return_highest_priority_when_first()
{
var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath"))
.And(x => x.GivenTheTemplateVariableAndNameFinderReturns(
new OkResponse<List<PlaceholderNameAndValue>>(new List<PlaceholderNameAndValue>())))
.And(x => x.GivenTheConfigurationIs(new List<ReRoute>
{
new ReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1))
.Build(),
new ReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 0))
.Build()
}, string.Empty, serviceProviderConfig))
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
.And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
.When(x => x.WhenICallTheFinder())
.Then(x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List<PlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1))
.WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1))
.Build()
)))
.BDDfy();
}
[Fact]
public void should_return_highest_priority_when_lowest()
{
var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath"))
.And(x => x.GivenTheTemplateVariableAndNameFinderReturns(
new OkResponse<List<PlaceholderNameAndValue>>(new List<PlaceholderNameAndValue>())))
.And(x => x.GivenTheConfigurationIs(new List<ReRoute>
{
new ReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 0))
.Build(),
new ReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1))
.Build()
}, string.Empty, serviceProviderConfig))
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
.And(x => x.GivenTheUpstreamHttpMethodIs("Post"))
.When(x => x.WhenICallTheFinder())
.Then(x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List<PlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1))
.WithUpstreamHttpMethod(new List<string> { "Post" })
.Build()
)))
.BDDfy();
}
[Fact] [Fact]
public void should_return_route() public void should_return_route()
{ {
@ -47,7 +123,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern("someUpstreamPath") .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1))
.Build() .Build()
}, string.Empty, serviceProviderConfig }, string.Empty, serviceProviderConfig
)) ))
@ -60,6 +136,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
new ReRouteBuilder() new ReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1))
.Build() .Build()
))) )))
.And(x => x.ThenTheUrlMatcherIsCalledCorrectly()) .And(x => x.ThenTheUrlMatcherIsCalledCorrectly())
@ -82,7 +159,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern("someUpstreamPath") .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1))
.Build() .Build()
}, string.Empty, serviceProviderConfig }, string.Empty, serviceProviderConfig
)) ))
@ -95,6 +172,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
new ReRouteBuilder() new ReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1))
.Build() .Build()
))) )))
.And(x => x.ThenTheUrlMatcherIsCalledCorrectly("matchInUrlMatcher")) .And(x => x.ThenTheUrlMatcherIsCalledCorrectly("matchInUrlMatcher"))
@ -117,7 +195,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern("someUpstreamPath") .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1))
.Build() .Build()
}, string.Empty, serviceProviderConfig }, string.Empty, serviceProviderConfig
)) ))
@ -129,6 +207,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
new ReRouteBuilder() new ReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1))
.Build() .Build()
))) )))
.And(x => x.ThenTheUrlMatcherIsNotCalled()) .And(x => x.ThenTheUrlMatcherIsNotCalled())
@ -151,13 +230,13 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern("") .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1))
.Build(), .Build(),
new ReRouteBuilder() new ReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPathForAPost") .WithDownstreamPathTemplate("someDownstreamPathForAPost")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Post" }) .WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern("") .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1))
.Build() .Build()
}, string.Empty, serviceProviderConfig }, string.Empty, serviceProviderConfig
)) ))
@ -169,6 +248,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
new ReRouteBuilder() new ReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPathForAPost") .WithDownstreamPathTemplate("someDownstreamPathForAPost")
.WithUpstreamHttpMethod(new List<string> { "Post" }) .WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1))
.Build() .Build()
))) )))
.BDDfy(); .BDDfy();
@ -186,7 +266,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamPathTemplate("somPath") .WithDownstreamPathTemplate("somPath")
.WithUpstreamPathTemplate("somePath") .WithUpstreamPathTemplate("somePath")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern("somePath") .WithUpstreamTemplatePattern(new UpstreamPathTemplate("somePath", 1))
.Build(), .Build(),
}, string.Empty, serviceProviderConfig }, string.Empty, serviceProviderConfig
)) ))
@ -215,7 +295,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get", "Post" }) .WithUpstreamHttpMethod(new List<string> { "Get", "Post" })
.WithUpstreamTemplatePattern("") .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1))
.Build() .Build()
}, string.Empty, serviceProviderConfig }, string.Empty, serviceProviderConfig
)) ))
@ -227,6 +307,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
new ReRouteBuilder() new ReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Post" }) .WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1))
.Build() .Build()
))) )))
.BDDfy(); .BDDfy();
@ -248,7 +329,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string>()) .WithUpstreamHttpMethod(new List<string>())
.WithUpstreamTemplatePattern("") .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1))
.Build() .Build()
}, string.Empty, serviceProviderConfig }, string.Empty, serviceProviderConfig
)) ))
@ -260,6 +341,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
new ReRouteBuilder() new ReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Post" }) .WithUpstreamHttpMethod(new List<string> { "Post" })
.WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1))
.Build() .Build()
))) )))
.BDDfy(); .BDDfy();
@ -281,7 +363,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.WithDownstreamPathTemplate("someDownstreamPath") .WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get", "Patch", "Delete" }) .WithUpstreamHttpMethod(new List<string> { "Get", "Patch", "Delete" })
.WithUpstreamTemplatePattern("") .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1))
.Build() .Build()
}, string.Empty, serviceProviderConfig }, string.Empty, serviceProviderConfig
)) ))
@ -356,14 +438,12 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
private void ThenTheFollowingIsReturned(DownstreamRoute expected) private void ThenTheFollowingIsReturned(DownstreamRoute expected)
{ {
_result.Data.ReRoute.DownstreamPathTemplate.Value.ShouldBe(expected.ReRoute.DownstreamPathTemplate.Value); _result.Data.ReRoute.DownstreamPathTemplate.Value.ShouldBe(expected.ReRoute.DownstreamPathTemplate.Value);
_result.Data.ReRoute.UpstreamTemplatePattern.Priority.ShouldBe(expected.ReRoute.UpstreamTemplatePattern.Priority);
for (int i = 0; i < _result.Data.TemplatePlaceholderNameAndValues.Count; i++) for (int i = 0; i < _result.Data.TemplatePlaceholderNameAndValues.Count; i++)
{ {
_result.Data.TemplatePlaceholderNameAndValues[i].Name.ShouldBe( _result.Data.TemplatePlaceholderNameAndValues[i].Name.ShouldBe(expected.TemplatePlaceholderNameAndValues[i].Name);
expected.TemplatePlaceholderNameAndValues[i].Name); _result.Data.TemplatePlaceholderNameAndValues[i].Value.ShouldBe(expected.TemplatePlaceholderNameAndValues[i].Value);
_result.Data.TemplatePlaceholderNameAndValues[i].Value.ShouldBe(
expected.TemplatePlaceholderNameAndValues[i].Value);
} }
_result.IsError.ShouldBeFalse(); _result.IsError.ShouldBeFalse();