From 9de00d6a46f635bb4faa1a08958b23f8bafd6e7c Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Fri, 5 Jan 2018 21:14:17 +0000 Subject: [PATCH] implemented simple priority in the routing --- docs/features/routing.rst | 8 +- .../Configuration/Builder/ReRouteBuilder.cs | 5 +- .../IUpstreamTemplatePatternCreator.cs | 3 +- .../Creator/UpstreamTemplatePatternCreator.cs | 9 +- src/Ocelot/Configuration/ReRoute.cs | 5 +- .../Finder/DownstreamRouteFinder.cs | 27 +++-- ...nstreamPathTemplate.cs => PathTemplate.cs} | 0 src/Ocelot/Values/UpstreamPathTemplate.cs | 14 +++ test/Ocelot.AcceptanceTests/RoutingTests.cs | 37 ++++++ .../FileConfigurationCreatorTests.cs | 7 +- .../UpstreamTemplatePatternCreatorTests.cs | 20 +++- .../DownstreamRouteFinderTests.cs | 108 +++++++++++++++--- 12 files changed, 197 insertions(+), 46 deletions(-) rename src/Ocelot/Values/{DownstreamPathTemplate.cs => PathTemplate.cs} (100%) create mode 100644 src/Ocelot/Values/UpstreamPathTemplate.cs diff --git a/docs/features/routing.rst b/docs/features/routing.rst index 3f9ddec8..0359d917 100644 --- a/docs/features/routing.rst +++ b/docs/features/routing.rst @@ -80,9 +80,7 @@ Ocelot's routing also supports a catch all style routing where the user can spec "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. - -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. +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. .. code-block:: json @@ -93,6 +91,4 @@ If you had this ReRoute after the catch all then it would never be matched. Howe "DownstreamHost" "10.0.10.1", "UpstreamPathTemplate": "/", "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. \ No newline at end of file + } \ No newline at end of file diff --git a/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs b/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs index 1a8877e7..cc5a61aa 100644 --- a/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs +++ b/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs @@ -2,6 +2,7 @@ using System.Net.Http; using Ocelot.Values; using System.Linq; +using Ocelot.Configuration.Creator; namespace Ocelot.Configuration.Builder { @@ -11,7 +12,7 @@ namespace Ocelot.Configuration.Builder private string _loadBalancerKey; private string _downstreamPathTemplate; private string _upstreamTemplate; - private string _upstreamTemplatePattern; + private UpstreamPathTemplate _upstreamTemplatePattern; private List _upstreamHttpMethod; private bool _isAuthenticated; private List _configHeaderExtractorProperties; @@ -65,7 +66,7 @@ namespace Ocelot.Configuration.Builder return this; } - public ReRouteBuilder WithUpstreamTemplatePattern(string input) + public ReRouteBuilder WithUpstreamTemplatePattern(UpstreamPathTemplate input) { _upstreamTemplatePattern = input; return this; diff --git a/src/Ocelot/Configuration/Creator/IUpstreamTemplatePatternCreator.cs b/src/Ocelot/Configuration/Creator/IUpstreamTemplatePatternCreator.cs index ae62c47a..14de619d 100644 --- a/src/Ocelot/Configuration/Creator/IUpstreamTemplatePatternCreator.cs +++ b/src/Ocelot/Configuration/Creator/IUpstreamTemplatePatternCreator.cs @@ -1,9 +1,10 @@ using Ocelot.Configuration.File; +using Ocelot.Values; namespace Ocelot.Configuration.Creator { public interface IUpstreamTemplatePatternCreator { - string Create(FileReRoute reRoute); + UpstreamPathTemplate Create(FileReRoute reRoute); } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/Creator/UpstreamTemplatePatternCreator.cs b/src/Ocelot/Configuration/Creator/UpstreamTemplatePatternCreator.cs index 9e7d9770..7816d118 100644 --- a/src/Ocelot/Configuration/Creator/UpstreamTemplatePatternCreator.cs +++ b/src/Ocelot/Configuration/Creator/UpstreamTemplatePatternCreator.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using Ocelot.Configuration.File; +using Ocelot.Values; namespace Ocelot.Configuration.Creator { @@ -11,7 +12,7 @@ namespace Ocelot.Configuration.Creator private const string RegExForwardSlashOnly = "^/$"; private const string RegExForwardSlashAndOnePlaceHolder = "^/.*"; - public string Create(FileReRoute reRoute) + public UpstreamPathTemplate Create(FileReRoute reRoute) { var upstreamTemplate = reRoute.UpstreamPathTemplate; @@ -29,7 +30,7 @@ namespace Ocelot.Configuration.Creator //hack to handle /{url} case if(ForwardSlashAndOnePlaceHolder(upstreamTemplate, placeholders, postitionOfPlaceHolderClosingBracket)) { - return RegExForwardSlashAndOnePlaceHolder; + return new UpstreamPathTemplate(RegExForwardSlashAndOnePlaceHolder, 0); } } } @@ -41,7 +42,7 @@ namespace Ocelot.Configuration.Creator if (upstreamTemplate == "/") { - return RegExForwardSlashOnly; + return new UpstreamPathTemplate(RegExForwardSlashOnly, 1); } if(upstreamTemplate.EndsWith("/")) @@ -53,7 +54,7 @@ namespace Ocelot.Configuration.Creator ? $"^{upstreamTemplate}{RegExMatchEndString}" : $"^{RegExIgnoreCase}{upstreamTemplate}{RegExMatchEndString}"; - return route; + return new UpstreamPathTemplate(route, 1); } private bool ForwardSlashAndOnePlaceHolder(string upstreamTemplate, List placeholders, int postitionOfPlaceHolderClosingBracket) diff --git a/src/Ocelot/Configuration/ReRoute.cs b/src/Ocelot/Configuration/ReRoute.cs index 0d373425..18e068aa 100644 --- a/src/Ocelot/Configuration/ReRoute.cs +++ b/src/Ocelot/Configuration/ReRoute.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Net.Http; +using Ocelot.Configuration.Creator; using Ocelot.Values; namespace Ocelot.Configuration @@ -9,7 +10,7 @@ namespace Ocelot.Configuration public ReRoute(PathTemplate downstreamPathTemplate, PathTemplate upstreamPathTemplate, List upstreamHttpMethod, - string upstreamTemplatePattern, + UpstreamPathTemplate upstreamTemplatePattern, bool isAuthenticated, AuthenticationOptions authenticationOptions, List claimsToHeaders, @@ -67,7 +68,7 @@ namespace Ocelot.Configuration public string ReRouteKey {get;private set;} public PathTemplate DownstreamPathTemplate { get; private set; } public PathTemplate UpstreamPathTemplate { get; private set; } - public string UpstreamTemplatePattern { get; private set; } + public UpstreamPathTemplate UpstreamTemplatePattern { get; private set; } public List UpstreamHttpMethod { get; private set; } public bool IsAuthenticated { get; private set; } public bool IsAuthorised { get; private set; } diff --git a/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs b/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs index b568f31b..643a4464 100644 --- a/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs +++ b/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs @@ -13,34 +13,30 @@ namespace Ocelot.DownstreamRouteFinder.Finder public class DownstreamRouteFinder : IDownstreamRouteFinder { private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; - private readonly IPlaceholderNameAndValueFinder _urlPathPlaceholderNameAndValueFinder; + private readonly IPlaceholderNameAndValueFinder __placeholderNameAndValueFinder; public DownstreamRouteFinder(IUrlPathToUrlTemplateMatcher urlMatcher, IPlaceholderNameAndValueFinder urlPathPlaceholderNameAndValueFinder) { _urlMatcher = urlMatcher; - _urlPathPlaceholderNameAndValueFinder = urlPathPlaceholderNameAndValueFinder; + __placeholderNameAndValueFinder = urlPathPlaceholderNameAndValueFinder; } - public Response FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod, IOcelotConfiguration configuration) + public Response 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) { - if (upstreamUrlPath == reRoute.UpstreamTemplatePattern) + if (path == reRoute.UpstreamTemplatePattern.Template) { - var templateVariableNameAndValues = _urlPathPlaceholderNameAndValueFinder.Find(upstreamUrlPath, reRoute.UpstreamPathTemplate.Value); - - return new OkResponse(new DownstreamRoute(templateVariableNameAndValues.Data, reRoute)); + return GetPlaceholderNamesAndValues(path, reRoute); } - var urlMatch = _urlMatcher.Match(upstreamUrlPath, reRoute.UpstreamTemplatePattern); + var urlMatch = _urlMatcher.Match(path, reRoute.UpstreamTemplatePattern.Template); if (urlMatch.Data.Match) { - var templateVariableNameAndValues = _urlPathPlaceholderNameAndValueFinder.Find(upstreamUrlPath, reRoute.UpstreamPathTemplate.Value); - - return new OkResponse(new DownstreamRoute(templateVariableNameAndValues.Data, reRoute)); + return GetPlaceholderNamesAndValues(path, reRoute); } } @@ -49,5 +45,12 @@ namespace Ocelot.DownstreamRouteFinder.Finder new UnableToFindDownstreamRouteError() }); } + + private OkResponse GetPlaceholderNamesAndValues(string path, ReRoute reRoute) + { + var templatePlaceholderNameAndValues = __placeholderNameAndValueFinder.Find(path, reRoute.UpstreamPathTemplate.Value); + + return new OkResponse(new DownstreamRoute(templatePlaceholderNameAndValues.Data, reRoute)); + } } } \ No newline at end of file diff --git a/src/Ocelot/Values/DownstreamPathTemplate.cs b/src/Ocelot/Values/PathTemplate.cs similarity index 100% rename from src/Ocelot/Values/DownstreamPathTemplate.cs rename to src/Ocelot/Values/PathTemplate.cs diff --git a/src/Ocelot/Values/UpstreamPathTemplate.cs b/src/Ocelot/Values/UpstreamPathTemplate.cs new file mode 100644 index 00000000..00b70b2f --- /dev/null +++ b/src/Ocelot/Values/UpstreamPathTemplate.cs @@ -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;} + } +} \ No newline at end of file diff --git a/test/Ocelot.AcceptanceTests/RoutingTests.cs b/test/Ocelot.AcceptanceTests/RoutingTests.cs index 44d0b8b6..21c21c06 100644 --- a/test/Ocelot.AcceptanceTests/RoutingTests.cs +++ b/test/Ocelot.AcceptanceTests/RoutingTests.cs @@ -98,6 +98,43 @@ namespace Ocelot.AcceptanceTests .BDDfy(); } + [Fact] + public void should_return_response_200_favouring_forward_slash() + { + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = "/{url}", + DownstreamScheme = "http", + DownstreamHost = "localhost", + DownstreamPort = 51880, + UpstreamPathTemplate = "/{url}", + UpstreamHttpMethod = new List { "Get" }, + }, + new FileReRoute + { + DownstreamPathTemplate = "/", + DownstreamScheme = "http", + DownstreamHost = "localhost", + DownstreamPort = 51879, + UpstreamPathTemplate = "/", + UpstreamHttpMethod = new List { "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] public void should_return_response_200_favouring_forward_slash_route_because_it_is_first() { diff --git a/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs index 1182a56f..d39fa394 100644 --- a/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs @@ -18,6 +18,7 @@ namespace Ocelot.UnitTests.Configuration using Ocelot.DependencyInjection; using Ocelot.Errors; using Ocelot.UnitTests.TestData; + using Ocelot.Values; public class FileConfigurationCreatorTests { @@ -367,7 +368,7 @@ namespace Ocelot.UnitTests.Configuration .WithDownstreamPathTemplate("/products/{productId}") .WithUpstreamPathTemplate("/api/products/{productId}") .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamTemplatePattern("(?i)/api/products/.*/$") + .WithUpstreamTemplatePattern(new UpstreamPathTemplate("(?i)/api/products/.*/$", 1)) .Build() })) .BDDfy(); @@ -580,7 +581,7 @@ namespace Ocelot.UnitTests.Configuration result.DownstreamPathTemplate.Value.ShouldBe(expected.DownstreamPathTemplate.Value); result.UpstreamHttpMethod.ShouldBe(expected.UpstreamHttpMethod); 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.ClaimsToHeaders.Count.ShouldBe(expected.ClaimsToHeaders.Count); result.ClaimsToQueries.Count.ShouldBe(expected.ClaimsToQueries.Count); @@ -623,7 +624,7 @@ namespace Ocelot.UnitTests.Configuration { _upstreamTemplatePatternCreator .Setup(x => x.Create(It.IsAny())) - .Returns(pattern); + .Returns(new UpstreamPathTemplate(pattern, 1)); } private void ThenTheRequestIdKeyCreatorIsCalledCorrectly() diff --git a/test/Ocelot.UnitTests/Configuration/UpstreamTemplatePatternCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/UpstreamTemplatePatternCreatorTests.cs index d5c9774b..87e2f2d6 100644 --- a/test/Ocelot.UnitTests/Configuration/UpstreamTemplatePatternCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/UpstreamTemplatePatternCreatorTests.cs @@ -1,5 +1,7 @@ +using System; using Ocelot.Configuration.Creator; using Ocelot.Configuration.File; +using Ocelot.Values; using Shouldly; using TestStack.BDDfy; using Xunit; @@ -10,7 +12,7 @@ namespace Ocelot.UnitTests.Configuration { private FileReRoute _fileReRoute; private UpstreamTemplatePatternCreator _creator; - private string _result; + private UpstreamPathTemplate _result; public UpstreamTemplatePatternCreatorTests() { @@ -29,6 +31,7 @@ namespace Ocelot.UnitTests.Configuration this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) .When(x => x.WhenICreateTheTemplatePattern()) .Then(x => x.ThenTheFollowingIsReturned("^(?i)/PRODUCTS/[0-9a-zA-Z].*$")) + .And(x => ThenThePriorityIs(1)) .BDDfy(); } @@ -45,6 +48,7 @@ namespace Ocelot.UnitTests.Configuration this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) .When(x => x.WhenICreateTheTemplatePattern()) .Then(x => x.ThenTheFollowingIsReturned("^(?i)/PRODUCTS(/|)$")) + .And(x => ThenThePriorityIs(1)) .BDDfy(); } @@ -59,6 +63,7 @@ namespace Ocelot.UnitTests.Configuration this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) .When(x => x.WhenICreateTheTemplatePattern()) .Then(x => x.ThenTheFollowingIsReturned("^/PRODUCTS/[0-9a-zA-Z].*$")) + .And(x => ThenThePriorityIs(1)) .BDDfy(); } @@ -74,6 +79,7 @@ namespace Ocelot.UnitTests.Configuration this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) .When(x => x.WhenICreateTheTemplatePattern()) .Then(x => x.ThenTheFollowingIsReturned("^/api/products/[0-9a-zA-Z].*$")) + .And(x => ThenThePriorityIs(1)) .BDDfy(); } @@ -89,6 +95,7 @@ namespace Ocelot.UnitTests.Configuration this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) .When(x => x.WhenICreateTheTemplatePattern()) .Then(x => x.ThenTheFollowingIsReturned("^/api/products/[0-9a-zA-Z].*/variants/[0-9a-zA-Z].*$")) + .And(x => ThenThePriorityIs(1)) .BDDfy(); } @@ -104,6 +111,7 @@ namespace Ocelot.UnitTests.Configuration this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) .When(x => x.WhenICreateTheTemplatePattern()) .Then(x => x.ThenTheFollowingIsReturned("^/api/products/[0-9a-zA-Z].*/variants/[0-9a-zA-Z].*(/|)$")) + .And(x => ThenThePriorityIs(1)) .BDDfy(); } @@ -118,6 +126,7 @@ namespace Ocelot.UnitTests.Configuration this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) .When(x => x.WhenICreateTheTemplatePattern()) .Then(x => x.ThenTheFollowingIsReturned("^/$")) + .And(x => ThenThePriorityIs(1)) .BDDfy(); } @@ -132,6 +141,7 @@ namespace Ocelot.UnitTests.Configuration this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) .When(x => x.WhenICreateTheTemplatePattern()) .Then(x => x.ThenTheFollowingIsReturned("^/.*")) + .And(x => ThenThePriorityIs(0)) .BDDfy(); } @@ -147,6 +157,7 @@ namespace Ocelot.UnitTests.Configuration this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute)) .When(x => x.WhenICreateTheTemplatePattern()) .Then(x => x.ThenTheFollowingIsReturned("^/[0-9a-zA-Z].*/products/variants/[0-9a-zA-Z].*(/|)$")) + .And(x => ThenThePriorityIs(1)) .BDDfy(); } @@ -162,7 +173,12 @@ namespace Ocelot.UnitTests.Configuration private void ThenTheFollowingIsReturned(string expected) { - _result.ShouldBe(expected); + _result.Template.ShouldBe(expected); + } + + private void ThenThePriorityIs(int v) + { + _result.Priority.ShouldBe(v); } } } \ No newline at end of file diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs index 3b935bb4..1593b3f3 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs @@ -2,11 +2,13 @@ using Moq; using Ocelot.Configuration; using Ocelot.Configuration.Builder; +using Ocelot.Configuration.Creator; using Ocelot.Configuration.Provider; using Ocelot.DownstreamRouteFinder; using Ocelot.DownstreamRouteFinder.Finder; using Ocelot.DownstreamRouteFinder.UrlMatcher; using Ocelot.Responses; +using Ocelot.Values; using Shouldly; using TestStack.BDDfy; using Xunit; @@ -32,6 +34,80 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder _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>(new List()))) + .And(x => x.GivenTheConfigurationIs(new List + { + new ReRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamPathTemplate("someUpstreamPath") + .WithUpstreamHttpMethod(new List { "Post" }) + .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1)) + .Build(), + new ReRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamPathTemplate("someUpstreamPath") + .WithUpstreamHttpMethod(new List { "Post" }) + .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 0)) + .Build() + }, string.Empty, serviceProviderConfig)) + .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) + .And(x => x.GivenTheUpstreamHttpMethodIs("Post")) + .When(x => x.WhenICallTheFinder()) + .Then(x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), + new ReRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1)) + .WithUpstreamHttpMethod(new List { "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>(new List()))) + .And(x => x.GivenTheConfigurationIs(new List + { + new ReRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamPathTemplate("someUpstreamPath") + .WithUpstreamHttpMethod(new List { "Post" }) + .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 0)) + .Build(), + new ReRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamPathTemplate("someUpstreamPath") + .WithUpstreamHttpMethod(new List { "Post" }) + .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1)) + .Build() + }, string.Empty, serviceProviderConfig)) + .And(x => x.GivenTheUrlMatcherReturns(new OkResponse(new UrlMatch(true)))) + .And(x => x.GivenTheUpstreamHttpMethodIs("Post")) + .When(x => x.WhenICallTheFinder()) + .Then(x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), + new ReRouteBuilder() + .WithDownstreamPathTemplate("someDownstreamPath") + .WithUpstreamTemplatePattern(new UpstreamPathTemplate("test", 1)) + .WithUpstreamHttpMethod(new List { "Post" }) + .Build() + ))) + .BDDfy(); + } + [Fact] public void should_return_route() { @@ -47,7 +123,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamTemplatePattern("someUpstreamPath") + .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .Build() }, string.Empty, serviceProviderConfig )) @@ -60,6 +136,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder new ReRouteBuilder() .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .Build() ))) .And(x => x.ThenTheUrlMatcherIsCalledCorrectly()) @@ -82,7 +159,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamTemplatePattern("someUpstreamPath") + .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .Build() }, string.Empty, serviceProviderConfig )) @@ -95,6 +172,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder new ReRouteBuilder() .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .Build() ))) .And(x => x.ThenTheUrlMatcherIsCalledCorrectly("matchInUrlMatcher")) @@ -117,7 +195,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamTemplatePattern("someUpstreamPath") + .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .Build() }, string.Empty, serviceProviderConfig )) @@ -129,6 +207,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder new ReRouteBuilder() .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamHttpMethod(new List { "Get" }) + .WithUpstreamTemplatePattern(new UpstreamPathTemplate("someUpstreamPath", 1)) .Build() ))) .And(x => x.ThenTheUrlMatcherIsNotCalled()) @@ -151,13 +230,13 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamTemplatePattern("") + .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1)) .Build(), new ReRouteBuilder() .WithDownstreamPathTemplate("someDownstreamPathForAPost") .WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamHttpMethod(new List { "Post" }) - .WithUpstreamTemplatePattern("") + .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1)) .Build() }, string.Empty, serviceProviderConfig )) @@ -169,6 +248,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder new ReRouteBuilder() .WithDownstreamPathTemplate("someDownstreamPathForAPost") .WithUpstreamHttpMethod(new List { "Post" }) + .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1)) .Build() ))) .BDDfy(); @@ -186,7 +266,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .WithDownstreamPathTemplate("somPath") .WithUpstreamPathTemplate("somePath") .WithUpstreamHttpMethod(new List { "Get" }) - .WithUpstreamTemplatePattern("somePath") + .WithUpstreamTemplatePattern(new UpstreamPathTemplate("somePath", 1)) .Build(), }, string.Empty, serviceProviderConfig )) @@ -215,7 +295,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamHttpMethod(new List { "Get", "Post" }) - .WithUpstreamTemplatePattern("") + .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1)) .Build() }, string.Empty, serviceProviderConfig )) @@ -227,6 +307,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder new ReRouteBuilder() .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamHttpMethod(new List { "Post" }) + .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1)) .Build() ))) .BDDfy(); @@ -248,7 +329,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamHttpMethod(new List()) - .WithUpstreamTemplatePattern("") + .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1)) .Build() }, string.Empty, serviceProviderConfig )) @@ -260,6 +341,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder new ReRouteBuilder() .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamHttpMethod(new List { "Post" }) + .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1)) .Build() ))) .BDDfy(); @@ -281,7 +363,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamPathTemplate("someUpstreamPath") .WithUpstreamHttpMethod(new List { "Get", "Patch", "Delete" }) - .WithUpstreamTemplatePattern("") + .WithUpstreamTemplatePattern(new UpstreamPathTemplate("", 1)) .Build() }, string.Empty, serviceProviderConfig )) @@ -356,14 +438,12 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder private void ThenTheFollowingIsReturned(DownstreamRoute expected) { _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++) { - _result.Data.TemplatePlaceholderNameAndValues[i].Name.ShouldBe( - expected.TemplatePlaceholderNameAndValues[i].Name); - - _result.Data.TemplatePlaceholderNameAndValues[i].Value.ShouldBe( - expected.TemplatePlaceholderNameAndValues[i].Value); + _result.Data.TemplatePlaceholderNameAndValues[i].Name.ShouldBe(expected.TemplatePlaceholderNameAndValues[i].Name); + _result.Data.TemplatePlaceholderNameAndValues[i].Value.ShouldBe(expected.TemplatePlaceholderNameAndValues[i].Value); } _result.IsError.ShouldBeFalse();