From c4e0bae4ce93ef126c09f6d03f9b37b1ca3d24cb Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Sat, 27 Aug 2016 14:13:45 +0100 Subject: [PATCH 1/5] simplifying stuff after i realised i added loads of crap i dont need --- .../HostUrlRepository/HostUrlMap.cs | 14 --- .../HostUrlMapKeyAlreadyExists.cs | 12 -- .../HostUrlMapKeyDoesNotExist.cs | 12 -- .../IHostUrlMapRepository.cs | 10 -- .../InMemoryHostUrlMapRepository.cs | 37 ------ .../UrlFinder/IUpstreamHostUrlFinder.cs | 9 -- .../UrlFinder/UnableToFindUpstreamHostUrl.cs | 12 -- .../UrlFinder/UpstreamHostUrlFinder.cs | 28 ----- .../IUrlPathToUrlTemplateMatcher.cs | 7 ++ .../TemplateVariableNameAndValue.cs | 2 +- .../Infrastructure/UrlMatcher/UrlMatch.cs | 17 +++ .../UrlPathToUrlTemplateMatcher.cs} | 22 ++-- .../IUrlPathToUrlPathTemplateMatcher.cs | 7 -- .../UrlPathMatcher/UrlPathMatch.cs | 17 --- ...UpstreamUrlPathTemplateVariableReplacer.cs | 10 -- ...UpstreamUrlPathTemplateVariableReplacer.cs | 22 ---- .../DownstreamUrlPathAlreadyExists.cs | 12 -- .../DownstreamUrlPathDoesNotExist.cs | 12 -- .../IUrlPathTemplateMapRepository.cs | 12 -- .../InMemoryUrlPathTemplateMapRepository.cs | 51 -------- .../UrlPathTemplateMap.cs | 14 --- .../DownstreamUrlTemplateVariableReplacer.cs | 22 ++++ ...wnstreamUrlPathTemplateVariableReplacer.cs | 9 ++ .../DownstreamUrlAlreadyExists.cs | 12 ++ .../DownstreamUrlDoesNotExist.cs | 12 ++ .../IUrlTemplateMapRepository.cs | 11 ++ .../InMemoryUrlTemplateMapRepository.cs | 39 ++++++ .../UrlTemplateRepository/UrlTemplateMap.cs | 14 +++ .../Middleware/ProxyMiddleware.cs | 51 ++++---- src/Ocelot/Startup.cs | 15 +-- .../{RouterTests.cs => OcelotTests.cs} | 18 ++- .../HostUrlMapRepositoryTests.cs | 117 ------------------ .../UpstreamBaseUrlFinderTests.cs | 68 ---------- ...eamUrlPathTemplateVariableReplacerTests.cs | 72 +++++------ .../UrlPathTemplateMapRepositoryTests.cs | 75 +++-------- ...cs => UrlPathToUrlTemplateMatcherTests.cs} | 96 +++++++------- 36 files changed, 302 insertions(+), 668 deletions(-) delete mode 100644 src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMap.cs delete mode 100644 src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMapKeyAlreadyExists.cs delete mode 100644 src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMapKeyDoesNotExist.cs delete mode 100644 src/Ocelot.Library/Infrastructure/HostUrlRepository/IHostUrlMapRepository.cs delete mode 100644 src/Ocelot.Library/Infrastructure/HostUrlRepository/InMemoryHostUrlMapRepository.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlFinder/IUpstreamHostUrlFinder.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlFinder/UnableToFindUpstreamHostUrl.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlFinder/UpstreamHostUrlFinder.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs rename src/Ocelot.Library/Infrastructure/{UrlPathMatcher => UrlMatcher}/TemplateVariableNameAndValue.cs (88%) create mode 100644 src/Ocelot.Library/Infrastructure/UrlMatcher/UrlMatch.cs rename src/Ocelot.Library/Infrastructure/{UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs => UrlMatcher/UrlPathToUrlTemplateMatcher.cs} (74%) delete mode 100644 src/Ocelot.Library/Infrastructure/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathMatch.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlPathReplacer/IUpstreamUrlPathTemplateVariableReplacer.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlPathReplacer/UpstreamUrlPathTemplateVariableReplacer.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/DownstreamUrlPathAlreadyExists.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/DownstreamUrlPathDoesNotExist.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/IUrlPathTemplateMapRepository.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/InMemoryUrlPathTemplateMapRepository.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/UrlPathTemplateMap.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlAlreadyExists.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlDoesNotExist.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlTemplateRepository/IUrlTemplateMapRepository.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlTemplateRepository/InMemoryUrlTemplateMapRepository.cs create mode 100644 src/Ocelot.Library/Infrastructure/UrlTemplateRepository/UrlTemplateMap.cs rename test/Ocelot.AcceptanceTests/{RouterTests.cs => OcelotTests.cs} (70%) delete mode 100644 test/Ocelot.UnitTests/HostUrlMapRepositoryTests.cs delete mode 100644 test/Ocelot.UnitTests/UpstreamBaseUrlFinderTests.cs rename test/Ocelot.UnitTests/{UrlPathToUrlPathTemplateMatcherTests.cs => UrlPathToUrlTemplateMatcherTests.cs} (63%) diff --git a/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMap.cs b/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMap.cs deleted file mode 100644 index a9b6ce61..00000000 --- a/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMap.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Ocelot.Library.Infrastructure.HostUrlRepository -{ - public class HostUrlMap - { - public HostUrlMap(string urlPathTemplate, string upstreamHostUrl) - { - UrlPathTemplate = urlPathTemplate; - UpstreamHostUrl = upstreamHostUrl; - } - - public string UrlPathTemplate {get;private set;} - public string UpstreamHostUrl {get;private set;} - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMapKeyAlreadyExists.cs b/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMapKeyAlreadyExists.cs deleted file mode 100644 index 236cac79..00000000 --- a/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMapKeyAlreadyExists.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.HostUrlRepository -{ - public class HostUrlMapKeyAlreadyExists : Error - { - public HostUrlMapKeyAlreadyExists() - : base("This key has already been used") - { - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMapKeyDoesNotExist.cs b/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMapKeyDoesNotExist.cs deleted file mode 100644 index 913f2b67..00000000 --- a/src/Ocelot.Library/Infrastructure/HostUrlRepository/HostUrlMapKeyDoesNotExist.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.HostUrlRepository -{ - public class HostUrlMapKeyDoesNotExist : Error - { - public HostUrlMapKeyDoesNotExist() - : base("This key does not exist") - { - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/HostUrlRepository/IHostUrlMapRepository.cs b/src/Ocelot.Library/Infrastructure/HostUrlRepository/IHostUrlMapRepository.cs deleted file mode 100644 index da78044c..00000000 --- a/src/Ocelot.Library/Infrastructure/HostUrlRepository/IHostUrlMapRepository.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.HostUrlRepository -{ - public interface IHostUrlMapRepository - { - Response AddBaseUrlMap(HostUrlMap baseUrlMap); - Response GetBaseUrlMap(string urlPathTemplate); - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/HostUrlRepository/InMemoryHostUrlMapRepository.cs b/src/Ocelot.Library/Infrastructure/HostUrlRepository/InMemoryHostUrlMapRepository.cs deleted file mode 100644 index 61b45ebf..00000000 --- a/src/Ocelot.Library/Infrastructure/HostUrlRepository/InMemoryHostUrlMapRepository.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Collections.Generic; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.HostUrlRepository -{ - public class InMemoryHostUrlMapRepository : IHostUrlMapRepository - { - private readonly Dictionary _routes; - public InMemoryHostUrlMapRepository() - { - _routes = new Dictionary(); - } - public Response AddBaseUrlMap(HostUrlMap baseUrlMap) - { - if(_routes.ContainsKey(baseUrlMap.UrlPathTemplate)) - { - return new ErrorResponse(new List(){new HostUrlMapKeyAlreadyExists()}); - } - - _routes.Add(baseUrlMap.UrlPathTemplate, baseUrlMap.UpstreamHostUrl); - - return new OkResponse(); - } - - public Response GetBaseUrlMap(string urlPathTemplate) - { - string upstreamUrl = null; - - if(_routes.TryGetValue(urlPathTemplate, out upstreamUrl)) - { - return new OkResponse(new HostUrlMap(urlPathTemplate, upstreamUrl)); - } - - return new ErrorResponse(new List(){new HostUrlMapKeyDoesNotExist()}); - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlFinder/IUpstreamHostUrlFinder.cs b/src/Ocelot.Library/Infrastructure/UrlFinder/IUpstreamHostUrlFinder.cs deleted file mode 100644 index 84a78493..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlFinder/IUpstreamHostUrlFinder.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlFinder -{ - public interface IUpstreamHostUrlFinder - { - Response FindUpstreamHostUrl(string downstreamHostUrl); - } -} diff --git a/src/Ocelot.Library/Infrastructure/UrlFinder/UnableToFindUpstreamHostUrl.cs b/src/Ocelot.Library/Infrastructure/UrlFinder/UnableToFindUpstreamHostUrl.cs deleted file mode 100644 index 10defcee..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlFinder/UnableToFindUpstreamHostUrl.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlFinder -{ - public class UnableToFindUpstreamHostUrl : Error - { - public UnableToFindUpstreamHostUrl() - : base("Unable to find upstream base url") - { - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlFinder/UpstreamHostUrlFinder.cs b/src/Ocelot.Library/Infrastructure/UrlFinder/UpstreamHostUrlFinder.cs deleted file mode 100644 index 555eb3d2..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlFinder/UpstreamHostUrlFinder.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Collections.Generic; -using Ocelot.Library.Infrastructure.HostUrlRepository; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlFinder -{ - public class UpstreamHostUrlFinder : IUpstreamHostUrlFinder - { - private readonly IHostUrlMapRepository _hostUrlMapRepository; - - public UpstreamHostUrlFinder(IHostUrlMapRepository hostUrlMapRepository) - { - _hostUrlMapRepository = hostUrlMapRepository; - } - public Response FindUpstreamHostUrl(string downstreamBaseUrl) - { - var baseUrl = _hostUrlMapRepository.GetBaseUrlMap(downstreamBaseUrl); - - if(baseUrl.IsError) - { - return new ErrorResponse(new List {new UnableToFindUpstreamHostUrl()}); - } - - return new OkResponse(baseUrl.Data.UpstreamHostUrl); - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs b/src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs new file mode 100644 index 00000000..6f96a28c --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs @@ -0,0 +1,7 @@ +namespace Ocelot.Library.Infrastructure.UrlMatcher +{ + public interface IUrlPathToUrlTemplateMatcher + { + UrlMatch Match(string downstreamUrlPath, string downstreamUrlTemplate); + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/TemplateVariableNameAndValue.cs b/src/Ocelot.Library/Infrastructure/UrlMatcher/TemplateVariableNameAndValue.cs similarity index 88% rename from src/Ocelot.Library/Infrastructure/UrlPathMatcher/TemplateVariableNameAndValue.cs rename to src/Ocelot.Library/Infrastructure/UrlMatcher/TemplateVariableNameAndValue.cs index f65ab514..07935d08 100644 --- a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/TemplateVariableNameAndValue.cs +++ b/src/Ocelot.Library/Infrastructure/UrlMatcher/TemplateVariableNameAndValue.cs @@ -1,4 +1,4 @@ -namespace Ocelot.Library.Infrastructure.UrlPathMatcher +namespace Ocelot.Library.Infrastructure.UrlMatcher { public class TemplateVariableNameAndValue { diff --git a/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlMatch.cs b/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlMatch.cs new file mode 100644 index 00000000..0eb4cb47 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlMatch.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; + +namespace Ocelot.Library.Infrastructure.UrlMatcher +{ + public class UrlMatch + { + public UrlMatch(bool match, List templateVariableNameAndValues, string downstreamUrlTemplate) + { + Match = match; + TemplateVariableNameAndValues = templateVariableNameAndValues; + DownstreamUrlTemplate = downstreamUrlTemplate; + } + public bool Match {get;private set;} + public List TemplateVariableNameAndValues {get;private set;} + public string DownstreamUrlTemplate {get;private set;} + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs b/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlPathToUrlTemplateMatcher.cs similarity index 74% rename from src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs rename to src/Ocelot.Library/Infrastructure/UrlMatcher/UrlPathToUrlTemplateMatcher.cs index 3b2152e8..fc34153e 100644 --- a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathToUrlPathTemplateMatcher.cs +++ b/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlPathToUrlTemplateMatcher.cs @@ -1,25 +1,25 @@ using System; using System.Collections.Generic; -namespace Ocelot.Library.Infrastructure.UrlPathMatcher +namespace Ocelot.Library.Infrastructure.UrlMatcher { - public class UrlPathToUrlPathTemplateMatcher : IUrlPathToUrlPathTemplateMatcher + public class UrlPathToUrlTemplateMatcher : IUrlPathToUrlTemplateMatcher { - public UrlPathMatch Match(string downstreamUrlPath, string downstreamUrlPathTemplate) + public UrlMatch Match(string downstreamUrlPath, string downstreamUrlTemplate) { - var urlPathTemplateCopy = downstreamUrlPathTemplate; + var urlPathTemplateCopy = downstreamUrlTemplate; var templateKeysAndValues = new List(); int counterForUrl = 0; - for (int counterForTemplate = 0; counterForTemplate < downstreamUrlPathTemplate.Length; counterForTemplate++) + for (int counterForTemplate = 0; counterForTemplate < downstreamUrlTemplate.Length; counterForTemplate++) { - if (CharactersDontMatch(downstreamUrlPathTemplate[counterForTemplate], downstreamUrlPath[counterForUrl]) && ContinueScanningUrl(counterForUrl,downstreamUrlPath.Length)) + if (CharactersDontMatch(downstreamUrlTemplate[counterForTemplate], downstreamUrlPath[counterForUrl]) && ContinueScanningUrl(counterForUrl,downstreamUrlPath.Length)) { - if (IsPlaceholder(downstreamUrlPathTemplate[counterForTemplate])) + if (IsPlaceholder(downstreamUrlTemplate[counterForTemplate])) { - var variableName = GetPlaceholderVariableName(downstreamUrlPathTemplate, counterForTemplate); + var variableName = GetPlaceholderVariableName(downstreamUrlTemplate, counterForTemplate); var variableValue = GetPlaceholderVariableValue(downstreamUrlPath, counterForUrl); @@ -27,7 +27,7 @@ namespace Ocelot.Library.Infrastructure.UrlPathMatcher templateKeysAndValues.Add(templateVariableNameAndValue); - counterForTemplate = GetNextCounterPosition(downstreamUrlPathTemplate, counterForTemplate, '}'); + counterForTemplate = GetNextCounterPosition(downstreamUrlTemplate, counterForTemplate, '}'); counterForUrl = GetNextCounterPosition(downstreamUrlPath, counterForUrl, '/'); @@ -35,12 +35,12 @@ namespace Ocelot.Library.Infrastructure.UrlPathMatcher } else { - return new UrlPathMatch(false, templateKeysAndValues, string.Empty); + return new UrlMatch(false, templateKeysAndValues, string.Empty); } } counterForUrl++; } - return new UrlPathMatch(true, templateKeysAndValues, urlPathTemplateCopy); + return new UrlMatch(true, templateKeysAndValues, urlPathTemplateCopy); } private string GetPlaceholderVariableValue(string urlPath, int counterForUrl) diff --git a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs b/src/Ocelot.Library/Infrastructure/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs deleted file mode 100644 index 5ed4d637..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/IUrlPathToUrlPathTemplateMatcher.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ocelot.Library.Infrastructure.UrlPathMatcher -{ - public interface IUrlPathToUrlPathTemplateMatcher - { - UrlPathMatch Match(string downstreamUrlPath, string downStreamUrlPathTemplate); - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathMatch.cs b/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathMatch.cs deleted file mode 100644 index 7f474e62..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlPathMatcher/UrlPathMatch.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Collections.Generic; - -namespace Ocelot.Library.Infrastructure.UrlPathMatcher -{ - public class UrlPathMatch - { - public UrlPathMatch(bool match, List templateVariableNameAndValues, string downstreamUrlPathTemplate) - { - Match = match; - TemplateVariableNameAndValues = templateVariableNameAndValues; - DownstreamUrlPathTemplate = downstreamUrlPathTemplate; - } - public bool Match {get;private set;} - public List TemplateVariableNameAndValues {get;private set;} - public string DownstreamUrlPathTemplate {get;private set;} - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathReplacer/IUpstreamUrlPathTemplateVariableReplacer.cs b/src/Ocelot.Library/Infrastructure/UrlPathReplacer/IUpstreamUrlPathTemplateVariableReplacer.cs deleted file mode 100644 index cb455185..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlPathReplacer/IUpstreamUrlPathTemplateVariableReplacer.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Ocelot.Library.Infrastructure.UrlPathMatcher; - -namespace Ocelot.Library.Infrastructure.UrlPathReplacer -{ - public interface IUpstreamUrlPathTemplateVariableReplacer - { - string ReplaceTemplateVariable(string upstreamPathTemplate, UrlPathMatch urlPathMatch); - - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathReplacer/UpstreamUrlPathTemplateVariableReplacer.cs b/src/Ocelot.Library/Infrastructure/UrlPathReplacer/UpstreamUrlPathTemplateVariableReplacer.cs deleted file mode 100644 index b52ea69e..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlPathReplacer/UpstreamUrlPathTemplateVariableReplacer.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Text; -using Ocelot.Library.Infrastructure.UrlPathMatcher; - -namespace Ocelot.Library.Infrastructure.UrlPathReplacer -{ - public class UpstreamUrlPathTemplateVariableReplacer : IUpstreamUrlPathTemplateVariableReplacer - { - public string ReplaceTemplateVariable(string upstreamPathTemplate, UrlPathMatch urlPathMatch) - { - var upstreamUrl = new StringBuilder(); - upstreamUrl.Append(upstreamPathTemplate); - - foreach (var templateVarAndValue in urlPathMatch.TemplateVariableNameAndValues) - { - upstreamUrl.Replace(templateVarAndValue.TemplateVariableName, templateVarAndValue.TemplateVariableValue); - } - - return upstreamUrl.ToString(); - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/DownstreamUrlPathAlreadyExists.cs b/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/DownstreamUrlPathAlreadyExists.cs deleted file mode 100644 index 05a552ac..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/DownstreamUrlPathAlreadyExists.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlPathTemplateRepository -{ - public class DownstreamUrlPathTemplateAlreadyExists : Error - { - public DownstreamUrlPathTemplateAlreadyExists() - : base("This key has already been used") - { - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/DownstreamUrlPathDoesNotExist.cs b/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/DownstreamUrlPathDoesNotExist.cs deleted file mode 100644 index 7d89beeb..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/DownstreamUrlPathDoesNotExist.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlPathTemplateRepository -{ - public class DownstreamUrlPathTemplateDoesNotExist : Error - { - public DownstreamUrlPathTemplateDoesNotExist() - : base("This key does not exist") - { - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/IUrlPathTemplateMapRepository.cs b/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/IUrlPathTemplateMapRepository.cs deleted file mode 100644 index b63ecfc6..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/IUrlPathTemplateMapRepository.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlPathTemplateRepository -{ - public interface IUrlPathTemplateMapRepository - { - Response AddUrlPathTemplateMap(UrlPathTemplateMap urlPathMap); - Response GetUrlPathTemplateMap(string downstreamUrlPathTemplate); - Response> All { get; } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/InMemoryUrlPathTemplateMapRepository.cs b/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/InMemoryUrlPathTemplateMapRepository.cs deleted file mode 100644 index b56c6b95..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/InMemoryUrlPathTemplateMapRepository.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlPathTemplateRepository -{ - public class InMemoryUrlPathTemplateMapRepository : IUrlPathTemplateMapRepository - { - private readonly Dictionary _routes; - public InMemoryUrlPathTemplateMapRepository() - { - _routes = new Dictionary(); - } - - public Response> All - { - get - { - var routes = _routes - .Select(r => new UrlPathTemplateMap(r.Key, r.Value)) - .ToList(); - return new OkResponse>(routes); - } - } - - public Response AddUrlPathTemplateMap(UrlPathTemplateMap urlPathMap) - { - if(_routes.ContainsKey(urlPathMap.DownstreamUrlPathTemplate)) - { - return new ErrorResponse(new List(){new DownstreamUrlPathTemplateAlreadyExists()}); - } - - _routes.Add(urlPathMap.DownstreamUrlPathTemplate, urlPathMap.UpstreamUrlPathTemplate); - - return new OkResponse(); - } - - public Response GetUrlPathTemplateMap(string downstreamUrlPathTemplate) - { - string upstreamUrlPathTemplate = null; - - if(_routes.TryGetValue(downstreamUrlPathTemplate, out upstreamUrlPathTemplate)) - { - return new OkResponse(new UrlPathTemplateMap(downstreamUrlPathTemplate, upstreamUrlPathTemplate)); - } - - return new ErrorResponse(new List(){new DownstreamUrlPathTemplateDoesNotExist()}); - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/UrlPathTemplateMap.cs b/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/UrlPathTemplateMap.cs deleted file mode 100644 index 1471813c..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlPathTemplateRepository/UrlPathTemplateMap.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Ocelot.Library.Infrastructure.UrlPathTemplateRepository -{ - public class UrlPathTemplateMap - { - public UrlPathTemplateMap(string downstreamUrlPathTemplate, string upstreamUrlPathTemplate) - { - DownstreamUrlPathTemplate = downstreamUrlPathTemplate; - UpstreamUrlPathTemplate = upstreamUrlPathTemplate; - } - - public string DownstreamUrlPathTemplate {get;private set;} - public string UpstreamUrlPathTemplate {get;private set;} - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs new file mode 100644 index 00000000..14e99be9 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs @@ -0,0 +1,22 @@ +using System.Text; +using Ocelot.Library.Infrastructure.UrlMatcher; + +namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer +{ + public class DownstreamUrlTemplateVariableReplacer : IDownstreamUrlTemplateVariableReplacer + { + public string ReplaceTemplateVariable(string downstreamPathTemplate, UrlMatch urlMatch) + { + var upstreamUrl = new StringBuilder(); + + upstreamUrl.Append(downstreamPathTemplate); + + foreach (var templateVarAndValue in urlMatch.TemplateVariableNameAndValues) + { + upstreamUrl.Replace(templateVarAndValue.TemplateVariableName, templateVarAndValue.TemplateVariableValue); + } + + return upstreamUrl.ToString(); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs new file mode 100644 index 00000000..53b532f4 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs @@ -0,0 +1,9 @@ +using Ocelot.Library.Infrastructure.UrlMatcher; + +namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer +{ + public interface IDownstreamUrlTemplateVariableReplacer + { + string ReplaceTemplateVariable(string downstreamPathTemplate, UrlMatch urlMatch); + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlAlreadyExists.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlAlreadyExists.cs new file mode 100644 index 00000000..cf471ba3 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlAlreadyExists.cs @@ -0,0 +1,12 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.UrlTemplateRepository +{ + public class DownstreamUrlTemplateAlreadyExists : Error + { + public DownstreamUrlTemplateAlreadyExists() + : base("This key has already been used") + { + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlDoesNotExist.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlDoesNotExist.cs new file mode 100644 index 00000000..ba960046 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlDoesNotExist.cs @@ -0,0 +1,12 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.UrlTemplateRepository +{ + public class DownstreamUrlTemplateDoesNotExist : Error + { + public DownstreamUrlTemplateDoesNotExist() + : base("This key does not exist") + { + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/IUrlTemplateMapRepository.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/IUrlTemplateMapRepository.cs new file mode 100644 index 00000000..d4be69ae --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/IUrlTemplateMapRepository.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.UrlTemplateRepository +{ + public interface IUrlTemplateMapRepository + { + Response AddUrlTemplateMap(UrlTemplateMap urlPathMap); + Response> All { get; } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/InMemoryUrlTemplateMapRepository.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/InMemoryUrlTemplateMapRepository.cs new file mode 100644 index 00000000..0129b4d6 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/InMemoryUrlTemplateMapRepository.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.UrlTemplateRepository +{ + public class InMemoryUrlTemplateMapRepository : IUrlTemplateMapRepository + { + private readonly Dictionary _urlTemplates; + public InMemoryUrlTemplateMapRepository() + { + _urlTemplates = new Dictionary(); + } + + public Response> All + { + get + { + var routes = _urlTemplates + .Select(r => new UrlTemplateMap(r.Key, r.Value)) + .ToList(); + return new OkResponse>(routes); + } + } + + public Response AddUrlTemplateMap(UrlTemplateMap urlMap) + { + if(_urlTemplates.ContainsKey(urlMap.DownstreamUrlTemplate)) + { + return new ErrorResponse(new List(){new DownstreamUrlTemplateAlreadyExists()}); + } + + _urlTemplates.Add(urlMap.DownstreamUrlTemplate, urlMap.UpstreamUrlPathTemplate); + + return new OkResponse(); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/UrlTemplateMap.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/UrlTemplateMap.cs new file mode 100644 index 00000000..198917a9 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/UrlTemplateMap.cs @@ -0,0 +1,14 @@ +namespace Ocelot.Library.Infrastructure.UrlTemplateRepository +{ + public class UrlTemplateMap + { + public UrlTemplateMap(string downstreamUrlTemplate, string upstreamUrlPathTemplate) + { + DownstreamUrlTemplate = downstreamUrlTemplate; + UpstreamUrlPathTemplate = upstreamUrlPathTemplate; + } + + public string DownstreamUrlTemplate {get;private set;} + public string UpstreamUrlPathTemplate {get;private set;} + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs index a56fbd17..077bfae9 100644 --- a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs +++ b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs @@ -1,10 +1,8 @@ -using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using Ocelot.Library.Infrastructure.HostUrlRepository; -using Ocelot.Library.Infrastructure.UrlPathMatcher; -using Ocelot.Library.Infrastructure.UrlPathReplacer; -using Ocelot.Library.Infrastructure.UrlPathTemplateRepository; +using Ocelot.Library.Infrastructure.UrlMatcher; +using Ocelot.Library.Infrastructure.UrlTemplateRepository; +using Ocelot.Library.Infrastructure.UrlTemplateReplacer; namespace Ocelot.Library.Middleware { @@ -13,53 +11,48 @@ namespace Ocelot.Library.Middleware public class ProxyMiddleware { private readonly RequestDelegate _next; - private readonly IUrlPathToUrlPathTemplateMatcher _urlMatcher; - private readonly IUrlPathTemplateMapRepository _urlPathRepository; - private readonly IHostUrlMapRepository _hostUrlRepository; - private readonly IUpstreamUrlPathTemplateVariableReplacer _urlReplacer; + private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; + private readonly IUrlTemplateMapRepository _urlTemplateMapRepository; + private readonly IDownstreamUrlTemplateVariableReplacer _urlReplacer; public ProxyMiddleware(RequestDelegate next, - IUrlPathToUrlPathTemplateMatcher urlMatcher, - IUrlPathTemplateMapRepository urlPathRepository, - IHostUrlMapRepository hostUrlRepository, - IUpstreamUrlPathTemplateVariableReplacer urlReplacer) + IUrlPathToUrlTemplateMatcher urlMatcher, + IUrlTemplateMapRepository urlPathRepository, + IDownstreamUrlTemplateVariableReplacer urlReplacer) { _next = next; _urlMatcher = urlMatcher; - _urlPathRepository = urlPathRepository; - _hostUrlRepository = hostUrlRepository; + _urlTemplateMapRepository = urlPathRepository; _urlReplacer = urlReplacer; } public async Task Invoke(HttpContext context) - { - - var path = context.Request.Path.ToString(); + { + var downstreamUrlPath = context.Request.Path.ToString(); - var urlPathTemplateMaps = _urlPathRepository.All; + var upstreamUrlTemplates = _urlTemplateMapRepository.All; - UrlPathMatch urlPathMatch = null; - string upstreamPathUrlTemplate = string.Empty; + UrlMatch urlMatch = null; - foreach (var template in urlPathTemplateMaps.Data) + string downstreamUrlTemplate = string.Empty; + + foreach (var template in upstreamUrlTemplates.Data) { - urlPathMatch = _urlMatcher.Match(path, template.DownstreamUrlPathTemplate); + urlMatch = _urlMatcher.Match(downstreamUrlPath, template.DownstreamUrlTemplate); - if (urlPathMatch.Match) + if (urlMatch.Match) { - upstreamPathUrlTemplate = template.UpstreamUrlPathTemplate; + downstreamUrlTemplate = template.DownstreamUrlTemplate; break; } } - if (urlPathMatch == null || !urlPathMatch.Match) + if (urlMatch == null || !urlMatch.Match) { context.Response.StatusCode = (int)HttpStatusCode.NotFound; return; } - var upstreamHostUrl = _hostUrlRepository.GetBaseUrlMap(urlPathMatch.DownstreamUrlPathTemplate); - - var pathUrl = _urlReplacer.ReplaceTemplateVariable(upstreamPathUrlTemplate, urlPathMatch); + var downstreamUrl = _urlReplacer.ReplaceTemplateVariable(downstreamUrlTemplate, urlMatch); //make a http request to this endpoint...maybe bring in a library diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index d95b6f65..c585c1a5 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -8,10 +8,9 @@ using Ocelot.Library.Middleware; namespace Ocelot { - using Library.Infrastructure.HostUrlRepository; - using Library.Infrastructure.UrlPathMatcher; - using Library.Infrastructure.UrlPathReplacer; - using Library.Infrastructure.UrlPathTemplateRepository; + using Library.Infrastructure.UrlMatcher; + using Library.Infrastructure.UrlTemplateReplacer; + using Library.Infrastructure.UrlTemplateRepository; public class Startup { @@ -31,11 +30,9 @@ namespace Ocelot public void ConfigureServices(IServiceCollection services) { // Add framework services. - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/test/Ocelot.AcceptanceTests/RouterTests.cs b/test/Ocelot.AcceptanceTests/OcelotTests.cs similarity index 70% rename from test/Ocelot.AcceptanceTests/RouterTests.cs rename to test/Ocelot.AcceptanceTests/OcelotTests.cs index 2d4d2c4e..6f767a64 100644 --- a/test/Ocelot.AcceptanceTests/RouterTests.cs +++ b/test/Ocelot.AcceptanceTests/OcelotTests.cs @@ -11,14 +11,14 @@ namespace Ocelot.AcceptanceTests using System.Net; using TestStack.BDDfy; - public class RouterTests : IDisposable + public class OcelotTests : IDisposable { private readonly FakeService _fakeService; private readonly TestServer _server; private readonly HttpClient _client; private HttpResponseMessage _response; - public RouterTests() + public OcelotTests() { _server = new TestServer(new WebHostBuilder() .UseStartup()); @@ -36,6 +36,15 @@ namespace Ocelot.AcceptanceTests .BDDfy(); } + [Fact] + public void should_return_response_200() + { + this.When(x => x.WhenIRequestTheUrl("/")) + .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .And(x => x.ThenTheResponseBodyShouldBe("Hello from Laura")) + .BDDfy(); + } + private void WhenIRequestTheUrl(string url) { _response = _client.GetAsync("/").Result; @@ -46,6 +55,11 @@ namespace Ocelot.AcceptanceTests _response.StatusCode.ShouldBe(expectedHttpStatusCode); } + private void ThenTheResponseBodyShouldBe(string expectedBody) + { + _response.Content.ReadAsStringAsync().Result.ShouldBe(expectedBody); + } + public void Dispose() { _fakeService.Stop(); diff --git a/test/Ocelot.UnitTests/HostUrlMapRepositoryTests.cs b/test/Ocelot.UnitTests/HostUrlMapRepositoryTests.cs deleted file mode 100644 index 045dfab1..00000000 --- a/test/Ocelot.UnitTests/HostUrlMapRepositoryTests.cs +++ /dev/null @@ -1,117 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; -using Ocelot.Library.Infrastructure.HostUrlRepository; -using Shouldly; -using Xunit; - -namespace Ocelot.UnitTests -{ - using TestStack.BDDfy; - - public class HostUrlMapRepositoryTests - { - private string _upstreamBaseUrl; - private string _downstreamBaseUrl; - private readonly IHostUrlMapRepository _repository; - private Response _response; - private Response _getRouteResponse; - - public HostUrlMapRepositoryTests() - { - _repository = new InMemoryHostUrlMapRepository(); - } - - [Fact] - public void can_add_route() - { - this.Given(x => x.GivenIHaveAnUpstreamBaseUrl("www.someapi.com")) - .And(x => x.GivenIWantToRouteRequestsFromMyDownstreamBaseUrl("api")) - .When(x => x.WhenIAddTheConfiguration()) - .Then(x => x.ThenTheResponseIsSuccesful()) - .BDDfy(); - } - - [Fact] - public void can_get_route_by_key() - { - this.Given(x => x.GivenIHaveSetUpAnApiKeyAndUpstreamUrl("api2", "www.someapi.com")) - .When(x => x.WhenIRetrieveTheRouteByKey()) - .Then(x => x.ThenTheRouteIsReturned()) - .BDDfy(); - } - - [Fact] - public void should_return_error_response_when_key_already_used() - { - this.Given(x => x.GivenIHaveSetUpAnApiKeyAndUpstreamUrl("api2", "www.someapi.com")) - .When(x => x.WhenITryToUseTheSameKey()) - .Then(x => x.ThenTheKeyHasAlreadyBeenUsed()) - .BDDfy(); - } - - [Fact] - public void should_return_error_response_if_key_doesnt_exist() - { - this.Given(x => x.GivenIWantToRouteRequestsFromMyDownstreamBaseUrl("api")) - .When(x => x.WhenIRetrieveTheRouteByKey()) - .Then(x => x.ThenTheKeyDoesNotExist()) - .BDDfy(); - } - - private void WhenITryToUseTheSameKey() - { - WhenIAddTheConfiguration(); - } - - private void ThenTheKeyHasAlreadyBeenUsed() - { - _response.ShouldNotBeNull(); - _response.ShouldBeOfType(); - _response.Errors[0].Message.ShouldBe("This key has already been used"); - } - - private void ThenTheKeyDoesNotExist() - { - _getRouteResponse.ShouldNotBeNull(); - _getRouteResponse.ShouldBeOfType>(); - _getRouteResponse.Errors[0].Message.ShouldBe("This key does not exist"); - } - - private void WhenIRetrieveTheRouteByKey() - { - _getRouteResponse = _repository.GetBaseUrlMap(_downstreamBaseUrl); - } - - private void ThenTheRouteIsReturned() - { - _getRouteResponse.Data.UrlPathTemplate.ShouldBe(_downstreamBaseUrl); - _getRouteResponse.Data.UpstreamHostUrl.ShouldBe(_upstreamBaseUrl); - } - - private void GivenIHaveSetUpAnApiKeyAndUpstreamUrl(string apiKey, string upstreamUrl) - { - GivenIHaveAnUpstreamBaseUrl(upstreamUrl); - GivenIWantToRouteRequestsFromMyDownstreamBaseUrl(apiKey); - WhenIAddTheConfiguration(); - } - - private void GivenIHaveAnUpstreamBaseUrl(string upstreamApiUrl) - { - _upstreamBaseUrl = upstreamApiUrl; - } - - private void GivenIWantToRouteRequestsFromMyDownstreamBaseUrl(string downstreamBaseUrl) - { - _downstreamBaseUrl = downstreamBaseUrl; - } - - private void WhenIAddTheConfiguration() - { - _response = _repository.AddBaseUrlMap(new HostUrlMap(_downstreamBaseUrl, _upstreamBaseUrl)); - } - - private void ThenTheResponseIsSuccesful() - { - _response.ShouldBeOfType(); - } - } -} \ No newline at end of file diff --git a/test/Ocelot.UnitTests/UpstreamBaseUrlFinderTests.cs b/test/Ocelot.UnitTests/UpstreamBaseUrlFinderTests.cs deleted file mode 100644 index 6a36b312..00000000 --- a/test/Ocelot.UnitTests/UpstreamBaseUrlFinderTests.cs +++ /dev/null @@ -1,68 +0,0 @@ -using Ocelot.Library.Infrastructure.HostUrlRepository; -using Ocelot.Library.Infrastructure.UrlFinder; -using Ocelot.Library.Infrastructure.Responses; -using Xunit; -using Shouldly; -using TestStack.BDDfy; - -namespace Ocelot.UnitTests -{ - public class UpstreamBaseUrlFinderTests - { - private readonly IUpstreamHostUrlFinder _upstreamBaseUrlFinder; - private readonly IHostUrlMapRepository _hostUrlMapRepository; - private string _downstreamBaseUrl; - private Response _result; - public UpstreamBaseUrlFinderTests() - { - _hostUrlMapRepository = new InMemoryHostUrlMapRepository(); - _upstreamBaseUrlFinder = new UpstreamHostUrlFinder(_hostUrlMapRepository); - } - - [Fact] - public void can_find_base_url() - { - this.Given(x => x.GivenTheBaseUrlMapExists(new HostUrlMap("api.tom.com", "api.laura.com"))) - .And(x => x.GivenTheDownstreamBaseUrlIs("api.tom.com")) - .When(x => x.WhenIFindTheMatchingUpstreamBaseUrl()) - .Then(x => x.ThenTheFollowingIsReturned("api.laura.com")) - .BDDfy(); - } - - [Fact] - public void cant_find_base_url() - { - this.Given(x => x.GivenTheDownstreamBaseUrlIs("api.tom.com")) - .When(x => x.WhenIFindTheMatchingUpstreamBaseUrl()) - .Then(x => x.ThenAnErrorIsReturned()) - .BDDfy(); - } - - private void ThenAnErrorIsReturned() - { - _result.Errors.Count.ShouldBe(1); - } - - private void GivenTheBaseUrlMapExists(HostUrlMap baseUrlMap) - { - _hostUrlMapRepository.AddBaseUrlMap(baseUrlMap); - - } - - private void GivenTheDownstreamBaseUrlIs(string downstreamBaseUrl) - { - _downstreamBaseUrl = downstreamBaseUrl; - } - - private void WhenIFindTheMatchingUpstreamBaseUrl() - { - _result = _upstreamBaseUrlFinder.FindUpstreamHostUrl(_downstreamBaseUrl); - - } - - private void ThenTheFollowingIsReturned(string expectedBaseUrl) - { - _result.Data.ShouldBe(expectedBaseUrl); - } - } -} \ No newline at end of file diff --git a/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs b/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs index fd4deacf..aef6e6c6 100644 --- a/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs +++ b/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -using Ocelot.Library.Infrastructure.UrlPathMatcher; -using Ocelot.Library.Infrastructure.UrlPathReplacer; +using Ocelot.Library.Infrastructure.UrlMatcher; +using Ocelot.Library.Infrastructure.UrlTemplateReplacer; using Shouldly; using Xunit; @@ -10,53 +10,53 @@ namespace Ocelot.UnitTests public class UpstreamUrlPathTemplateVariableReplacerTests { - private string _upstreamUrlPath; - private UrlPathMatch _urlPathMatch; + private string _downstreamUrlTemplate; + private UrlMatch _urlMatch; private string _result; - private readonly IUpstreamUrlPathTemplateVariableReplacer _upstreamUrlPathReplacer; + private readonly IDownstreamUrlTemplateVariableReplacer _downstreamUrlPathReplacer; public UpstreamUrlPathTemplateVariableReplacerTests() { - _upstreamUrlPathReplacer = new UpstreamUrlPathTemplateVariableReplacer(); + _downstreamUrlPathReplacer = new DownstreamUrlTemplateVariableReplacer(); } [Fact] public void can_replace_no_template_variables() { - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("")) - .And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, new List(), ""))) + this.Given(x => x.GivenThereIsADownstreamUrl("")) + .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), ""))) .When(x => x.WhenIReplaceTheTemplateVariables()) - .Then(x => x.ThenTheUpstreamUrlPathIsReturned("")) + .Then(x => x.ThenTheDownstreamUrlPathIsReturned("")) .BDDfy(); } [Fact] public void can_replace_url_no_slash() { - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("api")) - .And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, new List(), "api"))) + this.Given(x => x.GivenThereIsADownstreamUrl("api")) + .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "api"))) .When(x => x.WhenIReplaceTheTemplateVariables()) - .Then(x => x.ThenTheUpstreamUrlPathIsReturned("api")) + .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api")) .BDDfy(); } [Fact] public void can_replace_url_one_slash() { - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("api/")) - .And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, new List(), "api/"))) + this.Given(x => x.GivenThereIsADownstreamUrl("api/")) + .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "api/"))) .When(x => x.WhenIReplaceTheTemplateVariables()) - .Then(x => x.ThenTheUpstreamUrlPathIsReturned("api/")) + .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/")) .BDDfy(); } [Fact] public void can_replace_url_multiple_slash() { - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("api/product/products/")) - .And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, new List(), "api/product/products/"))) + this.Given(x => x.GivenThereIsADownstreamUrl("api/product/products/")) + .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "api/product/products/"))) .When(x => x.WhenIReplaceTheTemplateVariables()) - .Then(x => x.ThenTheUpstreamUrlPathIsReturned("api/product/products/")) + .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/product/products/")) .BDDfy(); } @@ -68,10 +68,10 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{productId}", "1") }; - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("productservice/products/{productId}/")) - .And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, templateVariables, "api/products/{productId}/"))) + this.Given(x => x.GivenThereIsADownstreamUrl("productservice/products/{productId}/")) + .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "api/products/{productId}/"))) .When(x => x.WhenIReplaceTheTemplateVariables()) - .Then(x => x.ThenTheUpstreamUrlPathIsReturned("productservice/products/1/")) + .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/")) .BDDfy(); } @@ -83,10 +83,10 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{productId}", "1") }; - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("productservice/products/{productId}/variants")) - .And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, templateVariables, "api/products/{productId}/"))) + this.Given(x => x.GivenThereIsADownstreamUrl("productservice/products/{productId}/variants")) + .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "api/products/{productId}/"))) .When(x => x.WhenIReplaceTheTemplateVariables()) - .Then(x => x.ThenTheUpstreamUrlPathIsReturned("productservice/products/1/variants")) + .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants")) .BDDfy(); } @@ -99,10 +99,10 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{variantId}", "12") }; - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("productservice/products/{productId}/variants/{variantId}")) - .And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, templateVariables, "api/products/{productId}/{variantId}"))) + this.Given(x => x.GivenThereIsADownstreamUrl("productservice/products/{productId}/variants/{variantId}")) + .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "api/products/{productId}/{variantId}"))) .When(x => x.WhenIReplaceTheTemplateVariables()) - .Then(x => x.ThenTheUpstreamUrlPathIsReturned("productservice/products/1/variants/12")) + .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants/12")) .BDDfy(); } @@ -116,29 +116,29 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{categoryId}", "34") }; - this.Given(x => x.GivenThereIsAnUpstreamUrlPath("productservice/category/{categoryId}/products/{productId}/variants/{variantId}")) - .And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, templateVariables, "api/products/{categoryId}/{productId}/{variantId}"))) + this.Given(x => x.GivenThereIsADownstreamUrl("productservice/category/{categoryId}/products/{productId}/variants/{variantId}")) + .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "api/products/{categoryId}/{productId}/{variantId}"))) .When(x => x.WhenIReplaceTheTemplateVariables()) - .Then(x => x.ThenTheUpstreamUrlPathIsReturned("productservice/category/34/products/1/variants/12")) + .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/category/34/products/1/variants/12")) .BDDfy(); } - private void GivenThereIsAnUpstreamUrlPath(string upstreamUrlPath) + private void GivenThereIsADownstreamUrl(string downstreamUrlTemplate) { - _upstreamUrlPath = upstreamUrlPath; + _downstreamUrlTemplate = downstreamUrlTemplate; } - private void GivenThereIsAUrlPathMatch(UrlPathMatch urlPathMatch) + private void GivenThereIsAUrlMatch(UrlMatch urlMatch) { - _urlPathMatch = urlPathMatch; + _urlMatch = urlMatch; } private void WhenIReplaceTheTemplateVariables() { - _result = _upstreamUrlPathReplacer.ReplaceTemplateVariable(_upstreamUrlPath, _urlPathMatch); + _result = _downstreamUrlPathReplacer.ReplaceTemplateVariable(_downstreamUrlTemplate, _urlMatch); } - private void ThenTheUpstreamUrlPathIsReturned(string expected) + private void ThenTheDownstreamUrlPathIsReturned(string expected) { _result.ShouldBe(expected); } diff --git a/test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs b/test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs index 98de6ba9..19811718 100644 --- a/test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs +++ b/test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using Ocelot.Library.Infrastructure.Responses; -using Ocelot.Library.Infrastructure.UrlPathTemplateRepository; +using Ocelot.Library.Infrastructure.UrlTemplateRepository; using Shouldly; using Xunit; @@ -10,41 +10,31 @@ namespace Ocelot.UnitTests public class UrlPathTemplateMapRepositoryTests { - private string _upstreamUrlPath; - private string _downstreamUrlPath; - private IUrlPathTemplateMapRepository _repository; + private string _upstreamUrlPathTemplate; + private string _downstreamUrlTemplate; + private IUrlTemplateMapRepository _repository; private Response _response; - private Response _getResponse; - private Response> _listResponse; + private Response> _listResponse; public UrlPathTemplateMapRepositoryTests() { - _repository = new InMemoryUrlPathTemplateMapRepository(); + _repository = new InMemoryUrlTemplateMapRepository(); } [Fact] public void can_add_url_path() { - this.Given(x => x.GivenIHaveAnUpstreamUrlPath("/api/products/products/{productId}")) - .And(x => x.GivenIWantToRouteRequestsToMyUpstreamUrlPath("/api/products/{productId}")) + this.Given(x => x.GivenIHaveAnUpstreamUrlPathTemplate("/api/products/products/{productId}")) + .And(x => x.GivenADownstreamUrlTemplate("/api/products/{productId}")) .When(x => x.WhenIAddTheConfiguration()) .Then(x => x.ThenTheResponseIsSuccesful()) .BDDfy(); } - [Fact] - public void can_get_url_path() - { - this.Given(x => x.GivenIHaveSetUpADownstreamUrlPathAndAnUpstreamUrlPath("/api2", "http://www.someapi.com/api2")) - .When(x => x.WhenIRetrieveTheUrlPathByDownstreamUrl()) - .Then(x => x.ThenTheUrlPathIsReturned()) - .BDDfy(); - } - [Fact] public void can_get_all_urls() { - this.Given(x => x.GivenIHaveSetUpADownstreamUrlPathAndAnUpstreamUrlPath("/api2", "http://www.someapi.com/api2")) + this.Given(x => x.GivenIHaveSetUpADownstreamUrlTemplateAndAnUpstreamUrlPathTemplate("/api2", "http://www.someapi.com/api2")) .When(x => x.WhenIRetrieveTheUrls()) .Then(x => x.ThenTheUrlsAreReturned()) .BDDfy(); @@ -53,21 +43,12 @@ namespace Ocelot.UnitTests [Fact] public void should_return_error_response_when_url_path_already_used() { - this.Given(x => x.GivenIHaveSetUpADownstreamUrlPathAndAnUpstreamUrlPath("/api2", "http://www.someapi.com/api2")) + this.Given(x => x.GivenIHaveSetUpADownstreamUrlTemplateAndAnUpstreamUrlPathTemplate("/api2", "http://www.someapi.com/api2")) .When(x => x.WhenITryToUseTheSameDownstreamUrl()) .Then(x => x.ThenTheDownstreamUrlAlreadyBeenUsed()) .BDDfy(); } - [Fact] - public void should_return_error_response_if_key_doesnt_exist() - { - this.Given(x => x.GivenIWantToRouteRequestsToMyUpstreamUrlPath("/api")) - .When(x => x.WhenIRetrieveTheUrlPathByDownstreamUrl()) - .Then(x => x.ThenTheKeyDoesNotExist()) - .BDDfy(); - } - private void WhenITryToUseTheSameDownstreamUrl() { WhenIAddTheConfiguration(); @@ -80,54 +61,36 @@ namespace Ocelot.UnitTests _response.Errors[0].Message.ShouldBe("This key has already been used"); } - private void ThenTheKeyDoesNotExist() - { - _getResponse.ShouldNotBeNull(); - _getResponse.ShouldBeOfType>(); - _getResponse.Errors[0].Message.ShouldBe("This key does not exist"); - } - - private void WhenIRetrieveTheUrlPathByDownstreamUrl() - { - _getResponse = _repository.GetUrlPathTemplateMap(_downstreamUrlPath); - } - - private void WhenIRetrieveTheUrls() + private void WhenIRetrieveTheUrls() { _listResponse = _repository.All; } - private void ThenTheUrlPathIsReturned() - { - _getResponse.Data.DownstreamUrlPathTemplate.ShouldBe(_downstreamUrlPath); - _getResponse.Data.UpstreamUrlPathTemplate.ShouldBe(_upstreamUrlPath); - } - private void ThenTheUrlsAreReturned() { _listResponse.Data.Count.ShouldBeGreaterThan(0); } - private void GivenIHaveSetUpADownstreamUrlPathAndAnUpstreamUrlPath(string downstream, string upstreamApiUrl) + private void GivenIHaveSetUpADownstreamUrlTemplateAndAnUpstreamUrlPathTemplate(string downstreamUrlTemplate, string upstreamUrlPathTemplate) { - GivenIHaveAnUpstreamUrlPath(upstreamApiUrl); - GivenIWantToRouteRequestsToMyUpstreamUrlPath(downstream); + GivenIHaveAnUpstreamUrlPathTemplate(upstreamUrlPathTemplate); + GivenADownstreamUrlTemplate(downstreamUrlTemplate); WhenIAddTheConfiguration(); } - private void GivenIHaveAnUpstreamUrlPath(string upstreamApiUrl) + private void GivenIHaveAnUpstreamUrlPathTemplate(string upstreamUrlPathTemplate) { - _upstreamUrlPath = upstreamApiUrl; + _upstreamUrlPathTemplate = upstreamUrlPathTemplate; } - private void GivenIWantToRouteRequestsToMyUpstreamUrlPath(string apiKey) + private void GivenADownstreamUrlTemplate(string downstreamUrlTemplate) { - _downstreamUrlPath = apiKey; + _downstreamUrlTemplate = downstreamUrlTemplate; } private void WhenIAddTheConfiguration() { - _response = _repository.AddUrlPathTemplateMap(new UrlPathTemplateMap(_downstreamUrlPath, _upstreamUrlPath)); + _response = _repository.AddUrlTemplateMap(new UrlTemplateMap(_downstreamUrlTemplate, _upstreamUrlPathTemplate)); } private void ThenTheResponseIsSuccesful() diff --git a/test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs b/test/Ocelot.UnitTests/UrlPathToUrlTemplateMatcherTests.cs similarity index 63% rename from test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs rename to test/Ocelot.UnitTests/UrlPathToUrlTemplateMatcherTests.cs index 0a3b105d..eb3ff139 100644 --- a/test/Ocelot.UnitTests/UrlPathToUrlPathTemplateMatcherTests.cs +++ b/test/Ocelot.UnitTests/UrlPathToUrlTemplateMatcherTests.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Linq; -using Ocelot.Library.Infrastructure.UrlPathMatcher; +using Ocelot.Library.Infrastructure.UrlMatcher; using Shouldly; using Xunit; @@ -8,26 +8,26 @@ namespace Ocelot.UnitTests { using TestStack.BDDfy; - public class UrlPathToUrlPathTemplateMatcherTests + public class UrlPathToUrlTemplateMatcherTests { - private readonly IUrlPathToUrlPathTemplateMatcher _urlMapper; - private string _downstreamPath; + private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; + private string _downstreamUrlPath; private string _downstreamPathTemplate; - private UrlPathMatch _result; - public UrlPathToUrlPathTemplateMatcherTests() + private UrlMatch _result; + public UrlPathToUrlTemplateMatcherTests() { - _urlMapper = new UrlPathToUrlPathTemplateMatcher(); + _urlMatcher = new UrlPathToUrlTemplateMatcher(); } [Fact] public void can_match_down_stream_url() { this.Given(x => x.GivenIHaveADownstreamPath("")) - .And(x => x.GivenIHaveAnDownstreamPathTemplate("")) + .And(x => x.GivenIHaveAnDownstreamUrlTemplate("")) .When(x => x.WhenIMatchThePaths()) .And(x => x.ThenTheResultIsTrue()) - .And(x => x.ThenTheTemplatesDictionaryIs(new List())) - .And(x => x.ThenTheUrlPathTemplateIs("")) + .And(x => x.ThenTheTemplatesVariablesAre(new List())) + .And(x => x.ThenTheDownstreamUrlTemplateIs("")) .BDDfy(); } @@ -35,23 +35,23 @@ namespace Ocelot.UnitTests public void can_match_down_stream_url_with_no_slash() { this.Given(x => x.GivenIHaveADownstreamPath("api")) - .Given(x => x.GivenIHaveAnDownstreamPathTemplate("api")) + .Given(x => x.GivenIHaveAnDownstreamUrlTemplate("api")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) - .And(x => x.ThenTheTemplatesDictionaryIs(new List())) - .And(x => x.ThenTheUrlPathTemplateIs("api")) + .And(x => x.ThenTheTemplatesVariablesAre(new List())) + .And(x => x.ThenTheDownstreamUrlTemplateIs("api")) .BDDfy(); } - [Fact] + [Fact] public void can_match_down_stream_url_with_one_slash() { this.Given(x => x.GivenIHaveADownstreamPath("api/")) - .Given(x => x.GivenIHaveAnDownstreamPathTemplate("api/")) + .Given(x => x.GivenIHaveAnDownstreamUrlTemplate("api/")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) - .And(x => x.ThenTheTemplatesDictionaryIs(new List())) - .And(x => x.ThenTheUrlPathTemplateIs("api/")) + .And(x => x.ThenTheTemplatesVariablesAre(new List())) + .And(x => x.ThenTheDownstreamUrlTemplateIs("api/")) .BDDfy(); } @@ -59,11 +59,11 @@ namespace Ocelot.UnitTests public void can_match_down_stream_url_with_downstream_template() { this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/")) - .Given(x => x.GivenIHaveAnDownstreamPathTemplate("api/product/products/")) + .Given(x => x.GivenIHaveAnDownstreamUrlTemplate("api/product/products/")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) - .And(x => x.ThenTheTemplatesDictionaryIs(new List())) - .And(x => x.ThenTheUrlPathTemplateIs("api/product/products/")) + .And(x => x.ThenTheTemplatesVariablesAre(new List())) + .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/")) .BDDfy(); } @@ -71,11 +71,11 @@ namespace Ocelot.UnitTests public void can_match_down_stream_url_with_downstream_template_with_one_query_string_parameter() { this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/?soldout=false")) - .Given(x => x.GivenIHaveAnDownstreamPathTemplate("api/product/products/")) + .Given(x => x.GivenIHaveAnDownstreamUrlTemplate("api/product/products/")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) - .And(x => x.ThenTheTemplatesDictionaryIs(new List())) - .And(x => x.ThenTheUrlPathTemplateIs("api/product/products/")) + .And(x => x.ThenTheTemplatesVariablesAre(new List())) + .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/")) .BDDfy(); } @@ -88,11 +88,11 @@ namespace Ocelot.UnitTests }; this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1/variants/?soldout=false")) - .Given(x => x.GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}/variants/")) + .Given(x => x.GivenIHaveAnDownstreamUrlTemplate("api/product/products/{productId}/variants/")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) - .And(x => x.ThenTheTemplatesDictionaryIs(expectedTemplates)) - .And(x => x.ThenTheUrlPathTemplateIs("api/product/products/{productId}/variants/")) + .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) + .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}/variants/")) .BDDfy(); } @@ -105,11 +105,11 @@ namespace Ocelot.UnitTests }; this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1")) - .Given(x => x.GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}")) + .Given(x => x.GivenIHaveAnDownstreamUrlTemplate("api/product/products/{productId}")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) - .And(x => x.ThenTheTemplatesDictionaryIs(expectedTemplates)) - .And(x => x.ThenTheUrlPathTemplateIs("api/product/products/{productId}")) + .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) + .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}")) .BDDfy(); } @@ -123,11 +123,11 @@ namespace Ocelot.UnitTests }; this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1/2")) - .Given(x => x.GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}/{categoryId}")) + .Given(x => x.GivenIHaveAnDownstreamUrlTemplate("api/product/products/{productId}/{categoryId}")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) - .And(x => x.ThenTheTemplatesDictionaryIs(expectedTemplates)) - .And(x => x.ThenTheUrlPathTemplateIs("api/product/products/{productId}/{categoryId}")) + .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) + .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}/{categoryId}")) .BDDfy(); } @@ -141,11 +141,11 @@ namespace Ocelot.UnitTests }; this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1/categories/2")) - .And(x => x.GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}/categories/{categoryId}")) + .And(x => x.GivenIHaveAnDownstreamUrlTemplate("api/product/products/{productId}/categories/{categoryId}")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) - .And(x => x.ThenTheTemplatesDictionaryIs(expectedTemplates)) - .And(x => x.ThenTheUrlPathTemplateIs("api/product/products/{productId}/categories/{categoryId}")) + .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) + .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}/categories/{categoryId}")) .BDDfy(); } @@ -160,11 +160,11 @@ namespace Ocelot.UnitTests }; this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1/categories/2/variant/123")) - .And(x => x.GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}/categories/{categoryId}/variant/{variantId}")) + .And(x => x.GivenIHaveAnDownstreamUrlTemplate("api/product/products/{productId}/categories/{categoryId}/variant/{variantId}")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) - .And(x => x.ThenTheTemplatesDictionaryIs(expectedTemplates)) - .And(x => x.ThenTheUrlPathTemplateIs("api/product/products/{productId}/categories/{categoryId}/variant/{variantId}")) + .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) + .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}/categories/{categoryId}/variant/{variantId}")) .BDDfy(); } @@ -178,15 +178,15 @@ namespace Ocelot.UnitTests }; this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1/categories/2/variant/")) - .And(x => x.GivenIHaveAnDownstreamPathTemplate("api/product/products/{productId}/categories/{categoryId}/variant/")) + .And(x => x.GivenIHaveAnDownstreamUrlTemplate("api/product/products/{productId}/categories/{categoryId}/variant/")) .When(x => x.WhenIMatchThePaths()) .Then(x => x.ThenTheResultIsTrue()) - .And(x => x.ThenTheTemplatesDictionaryIs(expectedTemplates)) - .And(x => x.ThenTheUrlPathTemplateIs("api/product/products/{productId}/categories/{categoryId}/variant/")) + .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) + .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}/categories/{categoryId}/variant/")) .BDDfy(); } - private void ThenTheTemplatesDictionaryIs(List expectedResults) + private void ThenTheTemplatesVariablesAre(List expectedResults) { foreach (var expectedResult in expectedResults) { @@ -196,23 +196,23 @@ namespace Ocelot.UnitTests } } - private void ThenTheUrlPathTemplateIs(string expectedUrlPathTemplate) + private void ThenTheDownstreamUrlTemplateIs(string expectedDownstreamUrlTemplate) { - _result.DownstreamUrlPathTemplate.ShouldBe(expectedUrlPathTemplate); + _result.DownstreamUrlTemplate.ShouldBe(expectedDownstreamUrlTemplate); } private void GivenIHaveADownstreamPath(string downstreamPath) { - _downstreamPath = downstreamPath; + _downstreamUrlPath = downstreamPath; } - private void GivenIHaveAnDownstreamPathTemplate(string downstreamTemplate) + private void GivenIHaveAnDownstreamUrlTemplate(string downstreamUrlTemplate) { - _downstreamPathTemplate = downstreamTemplate; + _downstreamPathTemplate = downstreamUrlTemplate; } private void WhenIMatchThePaths() { - _result = _urlMapper.Match(_downstreamPath, _downstreamPathTemplate); + _result = _urlMatcher.Match(_downstreamUrlPath, _downstreamPathTemplate); } private void ThenTheResultIsTrue() From e7a41fbc4d7daf70aff2f22f1f2d81ea6d7e31b6 Mon Sep 17 00:00:00 2001 From: Tom Pallister Date: Wed, 31 Aug 2016 20:46:46 +0100 Subject: [PATCH 2/5] hacking yaml config --- .../Configuration/Configuration.cs | 18 +++ .../Configuration/ConfigurationReader.cs | 22 ++++ .../Configuration/IConfigurationReader.cs | 7 + .../Infrastructure/Configuration/Route.cs | 18 +++ .../YamlConfigurationExtensions.cs | 42 ++++++ .../YamlConfigurationFileParser.cs | 121 ++++++++++++++++++ .../YamlConfigurationProvider.cs | 22 ++++ .../Configuration/YamlConfigurationSource.cs | 13 ++ .../Middleware/ProxyMiddleware.cs | 8 +- src/Ocelot.Library/project.json | 33 ++--- src/Ocelot/Startup.cs | 6 + .../ConfigurationReaderTests.cs | 54 ++++++++ test/Ocelot.AcceptanceTests/OcelotTests.cs | 2 +- .../Ocelot.AcceptanceTests/configuration.yaml | 3 + test/Ocelot.AcceptanceTests/project.json | 79 +++++++----- test/Ocelot.UnitTests/project.json | 43 ++++--- 16 files changed, 417 insertions(+), 74 deletions(-) create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/ConfigurationReader.cs create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/IConfigurationReader.cs create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/Route.cs create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationExtensions.cs create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationFileParser.cs create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationProvider.cs create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationSource.cs create mode 100644 test/Ocelot.AcceptanceTests/ConfigurationReaderTests.cs create mode 100644 test/Ocelot.AcceptanceTests/configuration.yaml diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs b/src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs new file mode 100644 index 00000000..f70712ed --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; + +namespace Ocelot.Library.Infrastructure.Configuration +{ + public class Configuration + { + public Configuration() + { + Routes = new List(); + } + public Configuration(List routes) + { + Routes = routes; + } + + public List Routes { get; private set; } + } +} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationReader.cs b/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationReader.cs new file mode 100644 index 00000000..139cff46 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationReader.cs @@ -0,0 +1,22 @@ +namespace Ocelot.Library.Infrastructure.Configuration +{ + using System.IO; + using YamlDotNet.Serialization; + using YamlDotNet.Serialization.NamingConventions; + + public class ConfigurationReader : IConfigurationReader + { + public Configuration Read(string configurationFilePath) + { + var contents = File.ReadAllText(configurationFilePath); + + var input = new StringReader(contents); + + var deserializer = new Deserializer(namingConvention: new CamelCaseNamingConvention()); + + var configuration = deserializer.Deserialize(input); + + return configuration;; + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Configuration/IConfigurationReader.cs b/src/Ocelot.Library/Infrastructure/Configuration/IConfigurationReader.cs new file mode 100644 index 00000000..d53b0526 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/IConfigurationReader.cs @@ -0,0 +1,7 @@ +namespace Ocelot.Library.Infrastructure.Configuration +{ + public interface IConfigurationReader + { + Configuration Read(string configurationFilePath); + } +} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Route.cs b/src/Ocelot.Library/Infrastructure/Configuration/Route.cs new file mode 100644 index 00000000..aa551658 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/Route.cs @@ -0,0 +1,18 @@ +namespace Ocelot.Library.Infrastructure.Configuration +{ + public class Route + { + public Route() + { + + } + public Route(string downstream, string upstream) + { + Downstream = downstream; + Upstream = upstream; + } + + public string Downstream { get; private set; } + public string Upstream { get; private set; } + } +} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationExtensions.cs b/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationExtensions.cs new file mode 100644 index 00000000..802016c8 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationExtensions.cs @@ -0,0 +1,42 @@ +using System.IO; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.FileProviders; + +namespace Ocelot.Library.Infrastructure.Configuration +{ + public static class YamlConfigurationExtensions + { + public static IConfigurationBuilder AddYamlFile(this IConfigurationBuilder builder, string path) + { + return AddYamlFile(builder, provider: null, path: path, optional: false, reloadOnChange: false); + } + + public static IConfigurationBuilder AddYamlFile(this IConfigurationBuilder builder, string path, bool optional) + { + return AddYamlFile(builder, provider: null, path: path, optional: optional, reloadOnChange: false); + } + + public static IConfigurationBuilder AddYamlFile(this IConfigurationBuilder builder, string path, bool optional, bool reloadOnChange) + { + return AddYamlFile(builder, provider: null, path: path, optional: optional, reloadOnChange: reloadOnChange); + } + + public static IConfigurationBuilder AddYamlFile(this IConfigurationBuilder builder, IFileProvider provider, string path, bool optional, bool reloadOnChange) + { + if (provider == null && Path.IsPathRooted(path)) + { + provider = new PhysicalFileProvider(Path.GetDirectoryName(path)); + path = Path.GetFileName(path); + } + var source = new YamlConfigurationSource + { + FileProvider = provider, + Path = path, + Optional = optional, + ReloadOnChange = reloadOnChange + }; + builder.Add(source); + return builder; + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationFileParser.cs b/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationFileParser.cs new file mode 100644 index 00000000..5e6d7c34 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationFileParser.cs @@ -0,0 +1,121 @@ +namespace Ocelot.Library.Infrastructure.Configuration +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using Microsoft.Extensions.Configuration; + using YamlDotNet.RepresentationModel; + + internal class YamlConfigurationFileParser + { + private readonly IDictionary _data = new SortedDictionary(StringComparer.OrdinalIgnoreCase); + private readonly Stack _context = new Stack(); + private string _currentPath; + + public IDictionary Parse(Stream input) + { + _data.Clear(); + _context.Clear(); + + // https://dotnetfiddle.net/rrR2Bb + var yaml = new YamlStream(); + yaml.Load(new StreamReader(input)); + + if (yaml.Documents.Any()) + { + var mapping = (YamlMappingNode)yaml.Documents[0].RootNode; + + // The document node is a mapping node + VisitYamlMappingNode(mapping); + } + + return _data; + } + + private void VisitYamlNodePair(KeyValuePair yamlNodePair) + { + var context = ((YamlScalarNode)yamlNodePair.Key).Value; + VisitYamlNode(context, yamlNodePair.Value); + } + + private void VisitYamlNode(string context, YamlNode node) + { + if (node is YamlScalarNode) + { + VisitYamlScalarNode(context, (YamlScalarNode)node); + } + if (node is YamlMappingNode) + { + VisitYamlMappingNode(context, (YamlMappingNode)node); + } + if (node is YamlSequenceNode) + { + VisitYamlSequenceNode(context, (YamlSequenceNode)node); + } + } + + private void VisitYamlScalarNode(string context, YamlScalarNode yamlValue) + { + //a node with a single 1-1 mapping + EnterContext(context); + var currentKey = _currentPath; + + if (_data.ContainsKey(currentKey)) + { + throw new FormatException("Key is duplicate ${currentKey}"); + } + + _data[currentKey] = yamlValue.Value; + ExitContext(); + } + + private void VisitYamlMappingNode(YamlMappingNode node) + { + foreach (var yamlNodePair in node.Children) + { + VisitYamlNodePair(yamlNodePair); + } + } + + private void VisitYamlMappingNode(string context, YamlMappingNode yamlValue) + { + //a node with an associated sub-document + EnterContext(context); + + VisitYamlMappingNode(yamlValue); + + ExitContext(); + } + + private void VisitYamlSequenceNode(string context, YamlSequenceNode yamlValue) + { + //a node with an associated list + EnterContext(context); + + VisitYamlSequenceNode(yamlValue); + + ExitContext(); + } + + private void VisitYamlSequenceNode(YamlSequenceNode node) + { + for (int i = 0; i < node.Children.Count; i++) + { + VisitYamlNode(i.ToString(), node.Children[i]); + } + } + + private void EnterContext(string context) + { + _context.Push(context); + _currentPath = ConfigurationPath.Combine(_context.Reverse()); + } + + private void ExitContext() + { + _context.Pop(); + _currentPath = ConfigurationPath.Combine(_context.Reverse()); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationProvider.cs b/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationProvider.cs new file mode 100644 index 00000000..fc81e102 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationProvider.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Ocelot.Library.Infrastructure.Configuration +{ + using System.IO; + using Microsoft.Extensions.Configuration; + + public class YamlConfigurationProvider : FileConfigurationProvider + { + public YamlConfigurationProvider(YamlConfigurationSource source) : base(source) { } + + public override void Load(Stream stream) + { + var parser = new YamlConfigurationFileParser(); + + Data = parser.Parse(stream); + } + } +} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationSource.cs b/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationSource.cs new file mode 100644 index 00000000..d1684517 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationSource.cs @@ -0,0 +1,13 @@ +namespace Ocelot.Library.Infrastructure.Configuration +{ + using Microsoft.Extensions.Configuration; + + public class YamlConfigurationSource : FileConfigurationSource + { + public override IConfigurationProvider Build(IConfigurationBuilder builder) + { + FileProvider = FileProvider ?? builder.GetFileProvider(); + return new YamlConfigurationProvider(this); + } + } +} diff --git a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs index 077bfae9..0acf6c25 100644 --- a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs +++ b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs @@ -7,6 +7,8 @@ using Ocelot.Library.Infrastructure.UrlTemplateReplacer; namespace Ocelot.Library.Middleware { using System.Net; + using Infrastructure.Configuration; + using Microsoft.Extensions.Options; public class ProxyMiddleware { @@ -14,19 +16,23 @@ namespace Ocelot.Library.Middleware private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; private readonly IUrlTemplateMapRepository _urlTemplateMapRepository; private readonly IDownstreamUrlTemplateVariableReplacer _urlReplacer; + private readonly IOptions _optionsAccessor; + public ProxyMiddleware(RequestDelegate next, IUrlPathToUrlTemplateMatcher urlMatcher, IUrlTemplateMapRepository urlPathRepository, - IDownstreamUrlTemplateVariableReplacer urlReplacer) + IDownstreamUrlTemplateVariableReplacer urlReplacer, IOptions optionsAccessor) { _next = next; _urlMatcher = urlMatcher; _urlTemplateMapRepository = urlPathRepository; _urlReplacer = urlReplacer; + _optionsAccessor = optionsAccessor; } public async Task Invoke(HttpContext context) { + var downstreamUrlPath = context.Request.Path.ToString(); var upstreamUrlTemplates = _urlTemplateMapRepository.All; diff --git a/src/Ocelot.Library/project.json b/src/Ocelot.Library/project.json index ca884c95..7037f0a7 100644 --- a/src/Ocelot.Library/project.json +++ b/src/Ocelot.Library/project.json @@ -1,23 +1,24 @@ { "version": "1.0.0-*", - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.0.0", - "type": "platform" - }, - "Microsoft.AspNetCore.Mvc": "1.0.0", - "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", - "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", - "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", - "Microsoft.Extensions.Configuration.Json": "1.0.0", - "Microsoft.Extensions.Logging": "1.0.0", - "Microsoft.Extensions.Logging.Console": "1.0.0", - "Microsoft.Extensions.Logging.Debug": "1.0.0", - "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", - "Microsoft.AspNetCore.Http": "1.0.0" + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0", + "type": "platform" }, + "Microsoft.AspNetCore.Mvc": "1.0.0", + "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", + "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", + "Microsoft.Extensions.Configuration.Json": "1.0.0", + "Microsoft.Extensions.Logging": "1.0.0", + "Microsoft.Extensions.Logging.Console": "1.0.0", + "Microsoft.Extensions.Logging.Debug": "1.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", + "Microsoft.AspNetCore.Http": "1.0.0", + "YamlDotNet": "3.9.0" + }, "frameworks": { "netcoreapp1.0": { diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index c585c1a5..779a0e74 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -8,6 +8,7 @@ using Ocelot.Library.Middleware; namespace Ocelot { + using Library.Infrastructure.Configuration; using Library.Infrastructure.UrlMatcher; using Library.Infrastructure.UrlTemplateReplacer; using Library.Infrastructure.UrlTemplateRepository; @@ -20,6 +21,7 @@ namespace Ocelot .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) + .AddYamlFile("configuration.yaml") .AddEnvironmentVariables(); Configuration = builder.Build(); } @@ -29,6 +31,10 @@ namespace Ocelot // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { + services.AddOptions(); + + services.Configure(Configuration); + // Add framework services. services.AddSingleton(); services.AddSingleton(); diff --git a/test/Ocelot.AcceptanceTests/ConfigurationReaderTests.cs b/test/Ocelot.AcceptanceTests/ConfigurationReaderTests.cs new file mode 100644 index 00000000..14878829 --- /dev/null +++ b/test/Ocelot.AcceptanceTests/ConfigurationReaderTests.cs @@ -0,0 +1,54 @@ +namespace Ocelot.AcceptanceTests +{ + using System.Collections.Generic; + using Library.Infrastructure.Configuration; + using Shouldly; + using TestStack.BDDfy; + using Xunit; + + public class ConfigurationReaderTests + { + private readonly IConfigurationReader _configurationReader; + private string _configPath; + private Configuration _result; + + public ConfigurationReaderTests() + { + _configurationReader = new ConfigurationReader(); + } + + [Fact] + public void can_read_configuration() + { + const string path = "./ConfigurationReaderTests.can_read_configuration.yaml"; + + var expected = + new Configuration(new List + { + new Route("productservice/category/{categoryId}/products/{productId}/variants/{variantId}", + "https://www.moonpig.com/api/products/{categoryId}/{productId}/{variantId}") + }); + + this.Given(x => x.GivenAConfigPathOf(path)) + .When(x => x.WhenICallTheConfigurationReader()) + .Then(x => x.ThenTheFollowingConfigurationIsReturned(expected)) + .BDDfy(); + } + + private void GivenAConfigPathOf(string configPath) + { + _configPath = configPath; + } + + private void WhenICallTheConfigurationReader() + { + _result = _configurationReader.Read(_configPath); + } + + private void ThenTheFollowingConfigurationIsReturned(Configuration expected) + { + _result.Routes[0].Downstream.ShouldBe(expected.Routes[0].Downstream); + _result.Routes[0].Upstream.ShouldBe(expected.Routes[0].Upstream); + } + } +} diff --git a/test/Ocelot.AcceptanceTests/OcelotTests.cs b/test/Ocelot.AcceptanceTests/OcelotTests.cs index 6f767a64..08a2734c 100644 --- a/test/Ocelot.AcceptanceTests/OcelotTests.cs +++ b/test/Ocelot.AcceptanceTests/OcelotTests.cs @@ -36,7 +36,7 @@ namespace Ocelot.AcceptanceTests .BDDfy(); } - [Fact] + [Fact] public void should_return_response_200() { this.When(x => x.WhenIRequestTheUrl("/")) diff --git a/test/Ocelot.AcceptanceTests/configuration.yaml b/test/Ocelot.AcceptanceTests/configuration.yaml new file mode 100644 index 00000000..98c05a41 --- /dev/null +++ b/test/Ocelot.AcceptanceTests/configuration.yaml @@ -0,0 +1,3 @@ +routes: + - downstream: "productservice/category/{categoryId}/products/{productId}/variants/{variantId}" + upstream: "https://www.moonpig.com/api/products/{categoryId}/{productId}/{variantId}" diff --git a/test/Ocelot.AcceptanceTests/project.json b/test/Ocelot.AcceptanceTests/project.json index c350a62b..c672997c 100644 --- a/test/Ocelot.AcceptanceTests/project.json +++ b/test/Ocelot.AcceptanceTests/project.json @@ -1,39 +1,48 @@ { - "version": "1.0.0-*", + "version": "1.0.0-*", - "testRunner": "xunit", - - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.0.0", - "type": "platform" - }, - "Microsoft.AspNetCore.Mvc": "1.0.0", - "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", - "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", - "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", - "Microsoft.Extensions.Configuration.Json": "1.0.0", - "Microsoft.Extensions.Logging": "1.0.0", - "Microsoft.Extensions.Logging.Console": "1.0.0", - "Microsoft.Extensions.Logging.Debug": "1.0.0", - "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", - "Microsoft.AspNetCore.Http": "1.0.0", - "Ocelot.Library": "1.0.0-*", - "xunit": "2.1.0", - "dotnet-test-xunit": "2.2.0-preview2-build1029", - "Shouldly": "2.8.0", - "Ocelot": "1.0.0-*", - "Microsoft.AspNetCore.TestHost": "1.0.0", - "TestStack.BDDfy": "4.3.1" - }, - - "frameworks": { - "netcoreapp1.0": { - "imports": [ - "dotnet5.6", - "portable-net45+win8" - ] - } + "buildOptions": { + "copyToOutput": { + "include": [ + "configuration.yaml" + ] } + }, + + "testRunner": "xunit", + + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0", + "type": "platform" + }, + "Microsoft.AspNetCore.Mvc": "1.0.0", + "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", + "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", + "Microsoft.Extensions.Configuration.Json": "1.0.0", + "Microsoft.Extensions.Logging": "1.0.0", + "Microsoft.Extensions.Logging.Console": "1.0.0", + "Microsoft.Extensions.Logging.Debug": "1.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", + "Microsoft.AspNetCore.Http": "1.0.0", + "Ocelot.Library": "1.0.0-*", + "xunit": "2.1.0", + "dotnet-test-xunit": "2.2.0-preview2-build1029", + "Shouldly": "2.8.0", + "Ocelot": "1.0.0-*", + "Microsoft.AspNetCore.TestHost": "1.0.0", + "TestStack.BDDfy": "4.3.1", + "YamlDotNet": "3.9.0" + }, + + "frameworks": { + "netcoreapp1.0": { + "imports": [ + "dotnet5.6", + "portable-net45+win8" + ] + } + } } diff --git a/test/Ocelot.UnitTests/project.json b/test/Ocelot.UnitTests/project.json index f415f589..f8c0cf9d 100644 --- a/test/Ocelot.UnitTests/project.json +++ b/test/Ocelot.UnitTests/project.json @@ -3,28 +3,29 @@ "testRunner": "xunit", - "dependencies": { - "Microsoft.NETCore.App": { - "version": "1.0.0", - "type": "platform" - }, - "Microsoft.AspNetCore.Mvc": "1.0.0", - "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", - "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", - "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", - "Microsoft.Extensions.Configuration.Json": "1.0.0", - "Microsoft.Extensions.Logging": "1.0.0", - "Microsoft.Extensions.Logging.Console": "1.0.0", - "Microsoft.Extensions.Logging.Debug": "1.0.0", - "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", - "Microsoft.AspNetCore.Http": "1.0.0", - "Ocelot.Library": "1.0.0-*", - "xunit": "2.1.0", - "dotnet-test-xunit": "2.2.0-preview2-build1029", - "Shouldly": "2.8.0", - "TestStack.BDDfy": "4.3.1" + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0", + "type": "platform" }, + "Microsoft.AspNetCore.Mvc": "1.0.0", + "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", + "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", + "Microsoft.Extensions.Configuration.Json": "1.0.0", + "Microsoft.Extensions.Logging": "1.0.0", + "Microsoft.Extensions.Logging.Console": "1.0.0", + "Microsoft.Extensions.Logging.Debug": "1.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", + "Microsoft.AspNetCore.Http": "1.0.0", + "Ocelot.Library": "1.0.0-*", + "xunit": "2.1.0", + "dotnet-test-xunit": "2.2.0-preview2-build1029", + "Shouldly": "2.8.0", + "TestStack.BDDfy": "4.3.1", + "YamlDotNet": "3.9.0" + }, "frameworks": { "netcoreapp1.0": { From 15d7cafa1c820cf7c394997e93d3caf0f7a68d7a Mon Sep 17 00:00:00 2001 From: Tom Pallister Date: Thu, 1 Sep 2016 09:05:04 +0100 Subject: [PATCH 3/5] Brought in YAML lib for configuration and added failing acceptance test --- .../Configuration/Configuration.cs | 6 +- .../Configuration/ConfigurationReader.cs | 22 ---- .../Configuration/IConfigurationReader.cs | 7 - .../Infrastructure/Configuration/Route.cs | 14 +- .../YamlConfigurationExtensions.cs | 42 ------ .../YamlConfigurationFileParser.cs | 121 ------------------ .../YamlConfigurationProvider.cs | 22 ---- .../Configuration/YamlConfigurationSource.cs | 13 -- src/Ocelot/Startup.cs | 1 - src/Ocelot/project.json | 3 +- .../ConfigurationReaderTests.cs | 54 -------- test/Ocelot.AcceptanceTests/OcelotTests.cs | 79 +++++++++--- .../Ocelot.AcceptanceTests/configuration.yaml | 6 +- 13 files changed, 69 insertions(+), 321 deletions(-) delete mode 100644 src/Ocelot.Library/Infrastructure/Configuration/ConfigurationReader.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Configuration/IConfigurationReader.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationExtensions.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationFileParser.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationProvider.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationSource.cs delete mode 100644 test/Ocelot.AcceptanceTests/ConfigurationReaderTests.cs diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs b/src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs index f70712ed..1a118086 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs @@ -8,11 +8,7 @@ namespace Ocelot.Library.Infrastructure.Configuration { Routes = new List(); } - public Configuration(List routes) - { - Routes = routes; - } - public List Routes { get; private set; } + public List Routes { get; set; } } } diff --git a/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationReader.cs b/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationReader.cs deleted file mode 100644 index 139cff46..00000000 --- a/src/Ocelot.Library/Infrastructure/Configuration/ConfigurationReader.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Ocelot.Library.Infrastructure.Configuration -{ - using System.IO; - using YamlDotNet.Serialization; - using YamlDotNet.Serialization.NamingConventions; - - public class ConfigurationReader : IConfigurationReader - { - public Configuration Read(string configurationFilePath) - { - var contents = File.ReadAllText(configurationFilePath); - - var input = new StringReader(contents); - - var deserializer = new Deserializer(namingConvention: new CamelCaseNamingConvention()); - - var configuration = deserializer.Deserialize(input); - - return configuration;; - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Configuration/IConfigurationReader.cs b/src/Ocelot.Library/Infrastructure/Configuration/IConfigurationReader.cs deleted file mode 100644 index d53b0526..00000000 --- a/src/Ocelot.Library/Infrastructure/Configuration/IConfigurationReader.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ocelot.Library.Infrastructure.Configuration -{ - public interface IConfigurationReader - { - Configuration Read(string configurationFilePath); - } -} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Route.cs b/src/Ocelot.Library/Infrastructure/Configuration/Route.cs index aa551658..a30d3bbf 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/Route.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/Route.cs @@ -2,17 +2,7 @@ { public class Route { - public Route() - { - - } - public Route(string downstream, string upstream) - { - Downstream = downstream; - Upstream = upstream; - } - - public string Downstream { get; private set; } - public string Upstream { get; private set; } + public string Downstream { get; set; } + public string Upstream { get; set; } } } diff --git a/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationExtensions.cs b/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationExtensions.cs deleted file mode 100644 index 802016c8..00000000 --- a/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationExtensions.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.IO; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.FileProviders; - -namespace Ocelot.Library.Infrastructure.Configuration -{ - public static class YamlConfigurationExtensions - { - public static IConfigurationBuilder AddYamlFile(this IConfigurationBuilder builder, string path) - { - return AddYamlFile(builder, provider: null, path: path, optional: false, reloadOnChange: false); - } - - public static IConfigurationBuilder AddYamlFile(this IConfigurationBuilder builder, string path, bool optional) - { - return AddYamlFile(builder, provider: null, path: path, optional: optional, reloadOnChange: false); - } - - public static IConfigurationBuilder AddYamlFile(this IConfigurationBuilder builder, string path, bool optional, bool reloadOnChange) - { - return AddYamlFile(builder, provider: null, path: path, optional: optional, reloadOnChange: reloadOnChange); - } - - public static IConfigurationBuilder AddYamlFile(this IConfigurationBuilder builder, IFileProvider provider, string path, bool optional, bool reloadOnChange) - { - if (provider == null && Path.IsPathRooted(path)) - { - provider = new PhysicalFileProvider(Path.GetDirectoryName(path)); - path = Path.GetFileName(path); - } - var source = new YamlConfigurationSource - { - FileProvider = provider, - Path = path, - Optional = optional, - ReloadOnChange = reloadOnChange - }; - builder.Add(source); - return builder; - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationFileParser.cs b/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationFileParser.cs deleted file mode 100644 index 5e6d7c34..00000000 --- a/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationFileParser.cs +++ /dev/null @@ -1,121 +0,0 @@ -namespace Ocelot.Library.Infrastructure.Configuration -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using Microsoft.Extensions.Configuration; - using YamlDotNet.RepresentationModel; - - internal class YamlConfigurationFileParser - { - private readonly IDictionary _data = new SortedDictionary(StringComparer.OrdinalIgnoreCase); - private readonly Stack _context = new Stack(); - private string _currentPath; - - public IDictionary Parse(Stream input) - { - _data.Clear(); - _context.Clear(); - - // https://dotnetfiddle.net/rrR2Bb - var yaml = new YamlStream(); - yaml.Load(new StreamReader(input)); - - if (yaml.Documents.Any()) - { - var mapping = (YamlMappingNode)yaml.Documents[0].RootNode; - - // The document node is a mapping node - VisitYamlMappingNode(mapping); - } - - return _data; - } - - private void VisitYamlNodePair(KeyValuePair yamlNodePair) - { - var context = ((YamlScalarNode)yamlNodePair.Key).Value; - VisitYamlNode(context, yamlNodePair.Value); - } - - private void VisitYamlNode(string context, YamlNode node) - { - if (node is YamlScalarNode) - { - VisitYamlScalarNode(context, (YamlScalarNode)node); - } - if (node is YamlMappingNode) - { - VisitYamlMappingNode(context, (YamlMappingNode)node); - } - if (node is YamlSequenceNode) - { - VisitYamlSequenceNode(context, (YamlSequenceNode)node); - } - } - - private void VisitYamlScalarNode(string context, YamlScalarNode yamlValue) - { - //a node with a single 1-1 mapping - EnterContext(context); - var currentKey = _currentPath; - - if (_data.ContainsKey(currentKey)) - { - throw new FormatException("Key is duplicate ${currentKey}"); - } - - _data[currentKey] = yamlValue.Value; - ExitContext(); - } - - private void VisitYamlMappingNode(YamlMappingNode node) - { - foreach (var yamlNodePair in node.Children) - { - VisitYamlNodePair(yamlNodePair); - } - } - - private void VisitYamlMappingNode(string context, YamlMappingNode yamlValue) - { - //a node with an associated sub-document - EnterContext(context); - - VisitYamlMappingNode(yamlValue); - - ExitContext(); - } - - private void VisitYamlSequenceNode(string context, YamlSequenceNode yamlValue) - { - //a node with an associated list - EnterContext(context); - - VisitYamlSequenceNode(yamlValue); - - ExitContext(); - } - - private void VisitYamlSequenceNode(YamlSequenceNode node) - { - for (int i = 0; i < node.Children.Count; i++) - { - VisitYamlNode(i.ToString(), node.Children[i]); - } - } - - private void EnterContext(string context) - { - _context.Push(context); - _currentPath = ConfigurationPath.Combine(_context.Reverse()); - } - - private void ExitContext() - { - _context.Pop(); - _currentPath = ConfigurationPath.Combine(_context.Reverse()); - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationProvider.cs b/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationProvider.cs deleted file mode 100644 index fc81e102..00000000 --- a/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationProvider.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Ocelot.Library.Infrastructure.Configuration -{ - using System.IO; - using Microsoft.Extensions.Configuration; - - public class YamlConfigurationProvider : FileConfigurationProvider - { - public YamlConfigurationProvider(YamlConfigurationSource source) : base(source) { } - - public override void Load(Stream stream) - { - var parser = new YamlConfigurationFileParser(); - - Data = parser.Parse(stream); - } - } -} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationSource.cs b/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationSource.cs deleted file mode 100644 index d1684517..00000000 --- a/src/Ocelot.Library/Infrastructure/Configuration/YamlConfigurationSource.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Ocelot.Library.Infrastructure.Configuration -{ - using Microsoft.Extensions.Configuration; - - public class YamlConfigurationSource : FileConfigurationSource - { - public override IConfigurationProvider Build(IConfigurationBuilder builder) - { - FileProvider = FileProvider ?? builder.GetFileProvider(); - return new YamlConfigurationProvider(this); - } - } -} diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index 779a0e74..93346a40 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -1,6 +1,5 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; diff --git a/src/Ocelot/project.json b/src/Ocelot/project.json index ba309f23..d77d3493 100644 --- a/src/Ocelot/project.json +++ b/src/Ocelot/project.json @@ -15,7 +15,8 @@ "Microsoft.Extensions.Logging.Console": "1.0.0", "Microsoft.Extensions.Logging.Debug": "1.0.0", "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", - "Ocelot.Library": "1.0.0-*" + "Ocelot.Library": "1.0.0-*", + "NetEscapades.Configuration.Yaml": "1.1.0" }, "tools": { diff --git a/test/Ocelot.AcceptanceTests/ConfigurationReaderTests.cs b/test/Ocelot.AcceptanceTests/ConfigurationReaderTests.cs deleted file mode 100644 index 14878829..00000000 --- a/test/Ocelot.AcceptanceTests/ConfigurationReaderTests.cs +++ /dev/null @@ -1,54 +0,0 @@ -namespace Ocelot.AcceptanceTests -{ - using System.Collections.Generic; - using Library.Infrastructure.Configuration; - using Shouldly; - using TestStack.BDDfy; - using Xunit; - - public class ConfigurationReaderTests - { - private readonly IConfigurationReader _configurationReader; - private string _configPath; - private Configuration _result; - - public ConfigurationReaderTests() - { - _configurationReader = new ConfigurationReader(); - } - - [Fact] - public void can_read_configuration() - { - const string path = "./ConfigurationReaderTests.can_read_configuration.yaml"; - - var expected = - new Configuration(new List - { - new Route("productservice/category/{categoryId}/products/{productId}/variants/{variantId}", - "https://www.moonpig.com/api/products/{categoryId}/{productId}/{variantId}") - }); - - this.Given(x => x.GivenAConfigPathOf(path)) - .When(x => x.WhenICallTheConfigurationReader()) - .Then(x => x.ThenTheFollowingConfigurationIsReturned(expected)) - .BDDfy(); - } - - private void GivenAConfigPathOf(string configPath) - { - _configPath = configPath; - } - - private void WhenICallTheConfigurationReader() - { - _result = _configurationReader.Read(_configPath); - } - - private void ThenTheFollowingConfigurationIsReturned(Configuration expected) - { - _result.Routes[0].Downstream.ShouldBe(expected.Routes[0].Downstream); - _result.Routes[0].Upstream.ShouldBe(expected.Routes[0].Upstream); - } - } -} diff --git a/test/Ocelot.AcceptanceTests/OcelotTests.cs b/test/Ocelot.AcceptanceTests/OcelotTests.cs index 08a2734c..6989ce99 100644 --- a/test/Ocelot.AcceptanceTests/OcelotTests.cs +++ b/test/Ocelot.AcceptanceTests/OcelotTests.cs @@ -1,37 +1,36 @@ -using System; -using System.Net.Http; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.TestHost; -using Xunit; -using Ocelot.AcceptanceTests.Fake; -using Shouldly; - namespace Ocelot.AcceptanceTests { + using System; + using System.Net.Http; + using Microsoft.AspNetCore.Hosting; + using Microsoft.AspNetCore.TestHost; + using Xunit; + using Ocelot.AcceptanceTests.Fake; + using Shouldly; + using System.Collections.Generic; + using System.IO; using System.Net; + using Library.Infrastructure.Configuration; using TestStack.BDDfy; + using YamlDotNet.Serialization; public class OcelotTests : IDisposable { private readonly FakeService _fakeService; - private readonly TestServer _server; - private readonly HttpClient _client; + private TestServer _server; + private HttpClient _client; private HttpResponseMessage _response; public OcelotTests() { - _server = new TestServer(new WebHostBuilder() - .UseStartup()); - - _client = _server.CreateClient(); - _fakeService = new FakeService(); } [Fact] public void should_return_response_404() { - this.When(x => x.WhenIRequestTheUrl("/")) + this.Given(x => x.GivenTheApiGatewayIsRunning()) + .When(x => x.WhenIRequestTheUrlOnTheApiGateway("/")) .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound)) .BDDfy(); } @@ -39,13 +38,57 @@ namespace Ocelot.AcceptanceTests [Fact] public void should_return_response_200() { - this.When(x => x.WhenIRequestTheUrl("/")) + this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879")) + .And(x => x.GivenThereIsAConfiguration(new Configuration + { + Routes = new List + { + new Route + { + Downstream = "http://localhost:51879/", + Upstream = "/heee" + } + } + })) + .And(x => x.GivenTheApiGatewayIsRunning()) + .When(x => x.WhenIRequestTheUrlOnTheApiGateway("/")) .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .And(x => x.ThenTheResponseBodyShouldBe("Hello from Laura")) .BDDfy(); } - private void WhenIRequestTheUrl(string url) + /// + /// This is annoying cos it should be in the constructor but we need to set up the yaml file before calling startup so its a step. + /// + private void GivenTheApiGatewayIsRunning() + { + _server = new TestServer(new WebHostBuilder() + .UseStartup()); + + _client = _server.CreateClient(); + } + + private void GivenThereIsAConfiguration(Configuration configuration) + { + var serializer = new Serializer(); + + if (File.Exists("./configuration.yaml")) + { + File.Delete("./configuration.yaml"); + } + + using (TextWriter writer = File.CreateText("./configuration.yaml")) + { + serializer.Serialize(writer, configuration); + } + } + + private void GivenThereIsAServiceRunningOn(string url) + { + _fakeService.Start(url); + } + + private void WhenIRequestTheUrlOnTheApiGateway(string url) { _response = _client.GetAsync("/").Result; } diff --git a/test/Ocelot.AcceptanceTests/configuration.yaml b/test/Ocelot.AcceptanceTests/configuration.yaml index 98c05a41..2e47e77d 100644 --- a/test/Ocelot.AcceptanceTests/configuration.yaml +++ b/test/Ocelot.AcceptanceTests/configuration.yaml @@ -1,3 +1,3 @@ -routes: - - downstream: "productservice/category/{categoryId}/products/{productId}/variants/{variantId}" - upstream: "https://www.moonpig.com/api/products/{categoryId}/{productId}/{variantId}" +Routes: +- Downstream: http://localhost:51879/ + Upstream: /heee From 71b7e7743e749d60ad831d075fe2ec7c4efcb871 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 7 Sep 2016 20:40:56 +0100 Subject: [PATCH 4/5] more simplification is that a word --- .../Configuration/Configuration.cs | 4 +- .../Infrastructure/Configuration/ReRoute.cs | 8 ++ .../Infrastructure/Configuration/Route.cs | 8 -- .../IUrlPathToUrlTemplateMatcher.cs | 2 +- .../UrlMatcher/UrlPathToUrlTemplateMatcher.cs | 18 ++-- .../DownstreamUrlTemplateVariableReplacer.cs | 4 +- ...wnstreamUrlPathTemplateVariableReplacer.cs | 2 +- .../DownstreamUrlAlreadyExists.cs | 12 --- .../DownstreamUrlDoesNotExist.cs | 12 --- .../IUrlTemplateMapRepository.cs | 11 -- .../InMemoryUrlTemplateMapRepository.cs | 39 ------- .../UrlTemplateRepository/UrlTemplateMap.cs | 14 --- .../Middleware/ProxyMiddleware.cs | 26 ++--- src/Ocelot/Startup.cs | 2 - test/Ocelot.AcceptanceTests/OcelotTests.cs | 8 +- .../Ocelot.AcceptanceTests/configuration.yaml | 6 +- ...eamUrlPathTemplateVariableReplacerTests.cs | 41 ++++--- .../UrlPathTemplateMapRepositoryTests.cs | 101 ------------------ 18 files changed, 56 insertions(+), 262 deletions(-) create mode 100644 src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs delete mode 100644 src/Ocelot.Library/Infrastructure/Configuration/Route.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlAlreadyExists.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlDoesNotExist.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlTemplateRepository/IUrlTemplateMapRepository.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlTemplateRepository/InMemoryUrlTemplateMapRepository.cs delete mode 100644 src/Ocelot.Library/Infrastructure/UrlTemplateRepository/UrlTemplateMap.cs delete mode 100644 test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs b/src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs index 1a118086..f1cc9b90 100644 --- a/src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs +++ b/src/Ocelot.Library/Infrastructure/Configuration/Configuration.cs @@ -6,9 +6,9 @@ namespace Ocelot.Library.Infrastructure.Configuration { public Configuration() { - Routes = new List(); + ReRoutes = new List(); } - public List Routes { get; set; } + public List ReRoutes { get; set; } } } diff --git a/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs b/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs new file mode 100644 index 00000000..4c27ec37 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/Configuration/ReRoute.cs @@ -0,0 +1,8 @@ +namespace Ocelot.Library.Infrastructure.Configuration +{ + public class ReRoute + { + public string DownstreamTemplate { get; set; } + public string UpstreamTemplate { get; set; } + } +} diff --git a/src/Ocelot.Library/Infrastructure/Configuration/Route.cs b/src/Ocelot.Library/Infrastructure/Configuration/Route.cs deleted file mode 100644 index a30d3bbf..00000000 --- a/src/Ocelot.Library/Infrastructure/Configuration/Route.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ocelot.Library.Infrastructure.Configuration -{ - public class Route - { - public string Downstream { get; set; } - public string Upstream { get; set; } - } -} diff --git a/src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs b/src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs index 6f96a28c..954e3fee 100644 --- a/src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs +++ b/src/Ocelot.Library/Infrastructure/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs @@ -2,6 +2,6 @@ namespace Ocelot.Library.Infrastructure.UrlMatcher { public interface IUrlPathToUrlTemplateMatcher { - UrlMatch Match(string downstreamUrlPath, string downstreamUrlTemplate); + UrlMatch Match(string upstreamUrlPath, string upstreamUrlTemplate); } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlPathToUrlTemplateMatcher.cs b/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlPathToUrlTemplateMatcher.cs index fc34153e..0c396e32 100644 --- a/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlPathToUrlTemplateMatcher.cs +++ b/src/Ocelot.Library/Infrastructure/UrlMatcher/UrlPathToUrlTemplateMatcher.cs @@ -5,31 +5,31 @@ namespace Ocelot.Library.Infrastructure.UrlMatcher { public class UrlPathToUrlTemplateMatcher : IUrlPathToUrlTemplateMatcher { - public UrlMatch Match(string downstreamUrlPath, string downstreamUrlTemplate) + public UrlMatch Match(string upstreamUrlPath, string upstreamUrlTemplate) { - var urlPathTemplateCopy = downstreamUrlTemplate; + var urlPathTemplateCopy = upstreamUrlTemplate; var templateKeysAndValues = new List(); int counterForUrl = 0; - for (int counterForTemplate = 0; counterForTemplate < downstreamUrlTemplate.Length; counterForTemplate++) + for (int counterForTemplate = 0; counterForTemplate < upstreamUrlTemplate.Length; counterForTemplate++) { - if (CharactersDontMatch(downstreamUrlTemplate[counterForTemplate], downstreamUrlPath[counterForUrl]) && ContinueScanningUrl(counterForUrl,downstreamUrlPath.Length)) + if (CharactersDontMatch(upstreamUrlTemplate[counterForTemplate], upstreamUrlPath[counterForUrl]) && ContinueScanningUrl(counterForUrl,upstreamUrlPath.Length)) { - if (IsPlaceholder(downstreamUrlTemplate[counterForTemplate])) + if (IsPlaceholder(upstreamUrlTemplate[counterForTemplate])) { - var variableName = GetPlaceholderVariableName(downstreamUrlTemplate, counterForTemplate); + var variableName = GetPlaceholderVariableName(upstreamUrlTemplate, counterForTemplate); - var variableValue = GetPlaceholderVariableValue(downstreamUrlPath, counterForUrl); + var variableValue = GetPlaceholderVariableValue(upstreamUrlPath, counterForUrl); var templateVariableNameAndValue = new TemplateVariableNameAndValue(variableName, variableValue); templateKeysAndValues.Add(templateVariableNameAndValue); - counterForTemplate = GetNextCounterPosition(downstreamUrlTemplate, counterForTemplate, '}'); + counterForTemplate = GetNextCounterPosition(upstreamUrlTemplate, counterForTemplate, '}'); - counterForUrl = GetNextCounterPosition(downstreamUrlPath, counterForUrl, '/'); + counterForUrl = GetNextCounterPosition(upstreamUrlPath, counterForUrl, '/'); continue; } diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs index 14e99be9..35dc563c 100644 --- a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs @@ -5,11 +5,11 @@ namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer { public class DownstreamUrlTemplateVariableReplacer : IDownstreamUrlTemplateVariableReplacer { - public string ReplaceTemplateVariable(string downstreamPathTemplate, UrlMatch urlMatch) + public string ReplaceTemplateVariable(UrlMatch urlMatch) { var upstreamUrl = new StringBuilder(); - upstreamUrl.Append(downstreamPathTemplate); + upstreamUrl.Append(urlMatch.DownstreamUrlTemplate); foreach (var templateVarAndValue in urlMatch.TemplateVariableNameAndValues) { diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs index 53b532f4..62eac8bc 100644 --- a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs @@ -4,6 +4,6 @@ namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer { public interface IDownstreamUrlTemplateVariableReplacer { - string ReplaceTemplateVariable(string downstreamPathTemplate, UrlMatch urlMatch); + string ReplaceTemplateVariable(UrlMatch urlMatch); } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlAlreadyExists.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlAlreadyExists.cs deleted file mode 100644 index cf471ba3..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlAlreadyExists.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlTemplateRepository -{ - public class DownstreamUrlTemplateAlreadyExists : Error - { - public DownstreamUrlTemplateAlreadyExists() - : base("This key has already been used") - { - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlDoesNotExist.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlDoesNotExist.cs deleted file mode 100644 index ba960046..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/DownstreamUrlDoesNotExist.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlTemplateRepository -{ - public class DownstreamUrlTemplateDoesNotExist : Error - { - public DownstreamUrlTemplateDoesNotExist() - : base("This key does not exist") - { - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/IUrlTemplateMapRepository.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/IUrlTemplateMapRepository.cs deleted file mode 100644 index d4be69ae..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/IUrlTemplateMapRepository.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlTemplateRepository -{ - public interface IUrlTemplateMapRepository - { - Response AddUrlTemplateMap(UrlTemplateMap urlPathMap); - Response> All { get; } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/InMemoryUrlTemplateMapRepository.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/InMemoryUrlTemplateMapRepository.cs deleted file mode 100644 index 0129b4d6..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/InMemoryUrlTemplateMapRepository.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Ocelot.Library.Infrastructure.Responses; - -namespace Ocelot.Library.Infrastructure.UrlTemplateRepository -{ - public class InMemoryUrlTemplateMapRepository : IUrlTemplateMapRepository - { - private readonly Dictionary _urlTemplates; - public InMemoryUrlTemplateMapRepository() - { - _urlTemplates = new Dictionary(); - } - - public Response> All - { - get - { - var routes = _urlTemplates - .Select(r => new UrlTemplateMap(r.Key, r.Value)) - .ToList(); - return new OkResponse>(routes); - } - } - - public Response AddUrlTemplateMap(UrlTemplateMap urlMap) - { - if(_urlTemplates.ContainsKey(urlMap.DownstreamUrlTemplate)) - { - return new ErrorResponse(new List(){new DownstreamUrlTemplateAlreadyExists()}); - } - - _urlTemplates.Add(urlMap.DownstreamUrlTemplate, urlMap.UpstreamUrlPathTemplate); - - return new OkResponse(); - } - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/UrlTemplateMap.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/UrlTemplateMap.cs deleted file mode 100644 index 198917a9..00000000 --- a/src/Ocelot.Library/Infrastructure/UrlTemplateRepository/UrlTemplateMap.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Ocelot.Library.Infrastructure.UrlTemplateRepository -{ - public class UrlTemplateMap - { - public UrlTemplateMap(string downstreamUrlTemplate, string upstreamUrlPathTemplate) - { - DownstreamUrlTemplate = downstreamUrlTemplate; - UpstreamUrlPathTemplate = upstreamUrlPathTemplate; - } - - public string DownstreamUrlTemplate {get;private set;} - public string UpstreamUrlPathTemplate {get;private set;} - } -} \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs index 0acf6c25..e723392e 100644 --- a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs +++ b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs @@ -1,7 +1,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Ocelot.Library.Infrastructure.UrlMatcher; -using Ocelot.Library.Infrastructure.UrlTemplateRepository; using Ocelot.Library.Infrastructure.UrlTemplateReplacer; namespace Ocelot.Library.Middleware @@ -14,40 +13,31 @@ namespace Ocelot.Library.Middleware { private readonly RequestDelegate _next; private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; - private readonly IUrlTemplateMapRepository _urlTemplateMapRepository; private readonly IDownstreamUrlTemplateVariableReplacer _urlReplacer; - private readonly IOptions _optionsAccessor; + private readonly IOptions _configuration; public ProxyMiddleware(RequestDelegate next, IUrlPathToUrlTemplateMatcher urlMatcher, - IUrlTemplateMapRepository urlPathRepository, - IDownstreamUrlTemplateVariableReplacer urlReplacer, IOptions optionsAccessor) + IDownstreamUrlTemplateVariableReplacer urlReplacer, IOptions configuration) { _next = next; _urlMatcher = urlMatcher; - _urlTemplateMapRepository = urlPathRepository; _urlReplacer = urlReplacer; - _optionsAccessor = optionsAccessor; + _configuration = configuration; } public async Task Invoke(HttpContext context) - { - - var downstreamUrlPath = context.Request.Path.ToString(); - - var upstreamUrlTemplates = _urlTemplateMapRepository.All; + { + var upstreamUrlPath = context.Request.Path.ToString(); UrlMatch urlMatch = null; - string downstreamUrlTemplate = string.Empty; - - foreach (var template in upstreamUrlTemplates.Data) + foreach (var template in _configuration.Value.ReRoutes) { - urlMatch = _urlMatcher.Match(downstreamUrlPath, template.DownstreamUrlTemplate); + urlMatch = _urlMatcher.Match(upstreamUrlPath, template.UpstreamTemplate); if (urlMatch.Match) { - downstreamUrlTemplate = template.DownstreamUrlTemplate; break; } } @@ -58,7 +48,7 @@ namespace Ocelot.Library.Middleware return; } - var downstreamUrl = _urlReplacer.ReplaceTemplateVariable(downstreamUrlTemplate, urlMatch); + var downstreamUrl = _urlReplacer.ReplaceTemplateVariable(urlMatch); //make a http request to this endpoint...maybe bring in a library diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index 93346a40..d9400980 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -10,7 +10,6 @@ namespace Ocelot using Library.Infrastructure.Configuration; using Library.Infrastructure.UrlMatcher; using Library.Infrastructure.UrlTemplateReplacer; - using Library.Infrastructure.UrlTemplateRepository; public class Startup { @@ -37,7 +36,6 @@ namespace Ocelot // Add framework services. services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/test/Ocelot.AcceptanceTests/OcelotTests.cs b/test/Ocelot.AcceptanceTests/OcelotTests.cs index 6989ce99..6f270e2c 100644 --- a/test/Ocelot.AcceptanceTests/OcelotTests.cs +++ b/test/Ocelot.AcceptanceTests/OcelotTests.cs @@ -41,12 +41,12 @@ namespace Ocelot.AcceptanceTests this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879")) .And(x => x.GivenThereIsAConfiguration(new Configuration { - Routes = new List + ReRoutes = new List { - new Route + new ReRoute { - Downstream = "http://localhost:51879/", - Upstream = "/heee" + DownstreamTemplate = "http://localhost:51879/", + UpstreamTemplate = "/" } } })) diff --git a/test/Ocelot.AcceptanceTests/configuration.yaml b/test/Ocelot.AcceptanceTests/configuration.yaml index 2e47e77d..97b35e41 100644 --- a/test/Ocelot.AcceptanceTests/configuration.yaml +++ b/test/Ocelot.AcceptanceTests/configuration.yaml @@ -1,3 +1,3 @@ -Routes: -- Downstream: http://localhost:51879/ - Upstream: /heee +ReRoutes: +- DownstreamTemplate: http://localhost:51879/ + UpstreamTemplate: / diff --git a/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs b/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs index aef6e6c6..6b55c013 100644 --- a/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs +++ b/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs @@ -10,7 +10,6 @@ namespace Ocelot.UnitTests public class UpstreamUrlPathTemplateVariableReplacerTests { - private string _downstreamUrlTemplate; private UrlMatch _urlMatch; private string _result; private readonly IDownstreamUrlTemplateVariableReplacer _downstreamUrlPathReplacer; @@ -23,18 +22,25 @@ namespace Ocelot.UnitTests [Fact] public void can_replace_no_template_variables() { - this.Given(x => x.GivenThereIsADownstreamUrl("")) - .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), ""))) + this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), ""))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("")) .BDDfy(); } + [Fact] + public void can_replace_no_template_variables_with_slash() + { + this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "/"))) + .When(x => x.WhenIReplaceTheTemplateVariables()) + .Then(x => x.ThenTheDownstreamUrlPathIsReturned("/")) + .BDDfy(); + } + [Fact] public void can_replace_url_no_slash() { - this.Given(x => x.GivenThereIsADownstreamUrl("api")) - .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "api"))) + this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "api"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api")) .BDDfy(); @@ -43,8 +49,7 @@ namespace Ocelot.UnitTests [Fact] public void can_replace_url_one_slash() { - this.Given(x => x.GivenThereIsADownstreamUrl("api/")) - .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "api/"))) + this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "api/"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/")) .BDDfy(); @@ -53,8 +58,7 @@ namespace Ocelot.UnitTests [Fact] public void can_replace_url_multiple_slash() { - this.Given(x => x.GivenThereIsADownstreamUrl("api/product/products/")) - .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "api/product/products/"))) + this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "api/product/products/"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/product/products/")) .BDDfy(); @@ -68,8 +72,7 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{productId}", "1") }; - this.Given(x => x.GivenThereIsADownstreamUrl("productservice/products/{productId}/")) - .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "api/products/{productId}/"))) + this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "productservice/products/{productId}/"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/")) .BDDfy(); @@ -83,8 +86,7 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{productId}", "1") }; - this.Given(x => x.GivenThereIsADownstreamUrl("productservice/products/{productId}/variants")) - .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "api/products/{productId}/"))) + this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "productservice/products/{productId}/variants"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants")) .BDDfy(); @@ -99,8 +101,7 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{variantId}", "12") }; - this.Given(x => x.GivenThereIsADownstreamUrl("productservice/products/{productId}/variants/{variantId}")) - .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "api/products/{productId}/{variantId}"))) + this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "productservice/products/{productId}/variants/{variantId}"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants/12")) .BDDfy(); @@ -116,18 +117,12 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{categoryId}", "34") }; - this.Given(x => x.GivenThereIsADownstreamUrl("productservice/category/{categoryId}/products/{productId}/variants/{variantId}")) - .And(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "api/products/{categoryId}/{productId}/{variantId}"))) + this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "productservice/category/{categoryId}/products/{productId}/variants/{variantId}"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/category/34/products/1/variants/12")) .BDDfy(); } - private void GivenThereIsADownstreamUrl(string downstreamUrlTemplate) - { - _downstreamUrlTemplate = downstreamUrlTemplate; - } - private void GivenThereIsAUrlMatch(UrlMatch urlMatch) { _urlMatch = urlMatch; @@ -135,7 +130,7 @@ namespace Ocelot.UnitTests private void WhenIReplaceTheTemplateVariables() { - _result = _downstreamUrlPathReplacer.ReplaceTemplateVariable(_downstreamUrlTemplate, _urlMatch); + _result = _downstreamUrlPathReplacer.ReplaceTemplateVariable(_urlMatch); } private void ThenTheDownstreamUrlPathIsReturned(string expected) diff --git a/test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs b/test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs deleted file mode 100644 index 19811718..00000000 --- a/test/Ocelot.UnitTests/UrlPathTemplateMapRepositoryTests.cs +++ /dev/null @@ -1,101 +0,0 @@ -using System.Collections.Generic; -using Ocelot.Library.Infrastructure.Responses; -using Ocelot.Library.Infrastructure.UrlTemplateRepository; -using Shouldly; -using Xunit; - -namespace Ocelot.UnitTests -{ - using TestStack.BDDfy; - - public class UrlPathTemplateMapRepositoryTests - { - private string _upstreamUrlPathTemplate; - private string _downstreamUrlTemplate; - private IUrlTemplateMapRepository _repository; - private Response _response; - private Response> _listResponse; - - public UrlPathTemplateMapRepositoryTests() - { - _repository = new InMemoryUrlTemplateMapRepository(); - } - - [Fact] - public void can_add_url_path() - { - this.Given(x => x.GivenIHaveAnUpstreamUrlPathTemplate("/api/products/products/{productId}")) - .And(x => x.GivenADownstreamUrlTemplate("/api/products/{productId}")) - .When(x => x.WhenIAddTheConfiguration()) - .Then(x => x.ThenTheResponseIsSuccesful()) - .BDDfy(); - } - - [Fact] - public void can_get_all_urls() - { - this.Given(x => x.GivenIHaveSetUpADownstreamUrlTemplateAndAnUpstreamUrlPathTemplate("/api2", "http://www.someapi.com/api2")) - .When(x => x.WhenIRetrieveTheUrls()) - .Then(x => x.ThenTheUrlsAreReturned()) - .BDDfy(); - } - - [Fact] - public void should_return_error_response_when_url_path_already_used() - { - this.Given(x => x.GivenIHaveSetUpADownstreamUrlTemplateAndAnUpstreamUrlPathTemplate("/api2", "http://www.someapi.com/api2")) - .When(x => x.WhenITryToUseTheSameDownstreamUrl()) - .Then(x => x.ThenTheDownstreamUrlAlreadyBeenUsed()) - .BDDfy(); - } - - private void WhenITryToUseTheSameDownstreamUrl() - { - WhenIAddTheConfiguration(); - } - - private void ThenTheDownstreamUrlAlreadyBeenUsed() - { - _response.ShouldNotBeNull(); - _response.ShouldBeOfType(); - _response.Errors[0].Message.ShouldBe("This key has already been used"); - } - - private void WhenIRetrieveTheUrls() - { - _listResponse = _repository.All; - } - - private void ThenTheUrlsAreReturned() - { - _listResponse.Data.Count.ShouldBeGreaterThan(0); - } - - private void GivenIHaveSetUpADownstreamUrlTemplateAndAnUpstreamUrlPathTemplate(string downstreamUrlTemplate, string upstreamUrlPathTemplate) - { - GivenIHaveAnUpstreamUrlPathTemplate(upstreamUrlPathTemplate); - GivenADownstreamUrlTemplate(downstreamUrlTemplate); - WhenIAddTheConfiguration(); - } - - private void GivenIHaveAnUpstreamUrlPathTemplate(string upstreamUrlPathTemplate) - { - _upstreamUrlPathTemplate = upstreamUrlPathTemplate; - } - - private void GivenADownstreamUrlTemplate(string downstreamUrlTemplate) - { - _downstreamUrlTemplate = downstreamUrlTemplate; - } - - private void WhenIAddTheConfiguration() - { - _response = _repository.AddUrlTemplateMap(new UrlTemplateMap(_downstreamUrlTemplate, _upstreamUrlPathTemplate)); - } - - private void ThenTheResponseIsSuccesful() - { - _response.ShouldBeOfType(); - } - } -} \ No newline at end of file From 03ef47038adb44c615a74ab5c4f24a190d553546 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 7 Sep 2016 21:47:39 +0100 Subject: [PATCH 5/5] first passing proxy acceptnace test yeyyy! --- .../DownstreamRouteFinder/DownstreamRoute.cs | 16 +++ .../DownstreamRouteFinder.cs | 38 +++++ .../IDownstreamRouteFinder.cs | 9 ++ .../UnableToFindDownstreamRouteError.cs | 15 ++ .../DownstreamUrlTemplateVariableReplacer.cs | 8 +- ...wnstreamUrlPathTemplateVariableReplacer.cs | 3 +- .../Middleware/ProxyMiddleware.cs | 52 ++++--- src/Ocelot/Startup.cs | 2 + test/Ocelot.AcceptanceTests/OcelotTests.cs | 2 +- .../DownstreamRouteFinderTests.cs | 132 ++++++++++++++++++ ...eamUrlPathTemplateVariableReplacerTests.cs | 27 ++-- test/Ocelot.UnitTests/project.json | 3 +- 12 files changed, 264 insertions(+), 43 deletions(-) create mode 100644 src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRoute.cs create mode 100644 src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs create mode 100644 src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/IDownstreamRouteFinder.cs create mode 100644 src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs create mode 100644 test/Ocelot.UnitTests/DownstreamRouteFinderTests.cs diff --git a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRoute.cs b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRoute.cs new file mode 100644 index 00000000..b88f0063 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRoute.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Ocelot.Library.Infrastructure.UrlMatcher; + +namespace Ocelot.Library.Infrastructure.DownstreamRouteFinder +{ + public class DownstreamRoute + { + public DownstreamRoute(List templateVariableNameAndValues, string downstreamUrlTemplate) + { + TemplateVariableNameAndValues = templateVariableNameAndValues; + DownstreamUrlTemplate = downstreamUrlTemplate; + } + public List TemplateVariableNameAndValues { get; private set; } + public string DownstreamUrlTemplate { get; private set; } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs new file mode 100644 index 00000000..63ddfacd --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/DownstreamRouteFinder.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using Microsoft.Extensions.Options; +using Ocelot.Library.Infrastructure.Responses; +using Ocelot.Library.Infrastructure.UrlMatcher; + +namespace Ocelot.Library.Infrastructure.DownstreamRouteFinder +{ + public class DownstreamRouteFinder : IDownstreamRouteFinder + { + private readonly IOptions _configuration; + private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; + + public DownstreamRouteFinder(IOptions configuration, IUrlPathToUrlTemplateMatcher urlMatcher) + { + _configuration = configuration; + _urlMatcher = urlMatcher; + } + + public Response FindDownstreamRoute(string upstreamUrlPath) + { + + foreach (var template in _configuration.Value.ReRoutes) + { + var urlMatch = _urlMatcher.Match(upstreamUrlPath, template.UpstreamTemplate); + + if (urlMatch.Match) + { + return new OkResponse(new DownstreamRoute(urlMatch.TemplateVariableNameAndValues, template.DownstreamTemplate)); + } + } + + return new ErrorResponse(new List + { + new UnableToFindDownstreamRouteError() + }); + } + } +} \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/IDownstreamRouteFinder.cs b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/IDownstreamRouteFinder.cs new file mode 100644 index 00000000..1394b3af --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/IDownstreamRouteFinder.cs @@ -0,0 +1,9 @@ +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.DownstreamRouteFinder +{ + public interface IDownstreamRouteFinder + { + Response FindDownstreamRoute(string upstreamUrlPath); + } +} diff --git a/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs new file mode 100644 index 00000000..62618951 --- /dev/null +++ b/src/Ocelot.Library/Infrastructure/DownstreamRouteFinder/UnableToFindDownstreamRouteError.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Ocelot.Library.Infrastructure.Responses; + +namespace Ocelot.Library.Infrastructure.DownstreamRouteFinder +{ + public class UnableToFindDownstreamRouteError : Error + { + public UnableToFindDownstreamRouteError() : base("UnableToFindDownstreamRouteError") + { + } + } +} diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs index 35dc563c..204eb212 100644 --- a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs @@ -1,17 +1,17 @@ using System.Text; -using Ocelot.Library.Infrastructure.UrlMatcher; +using Ocelot.Library.Infrastructure.DownstreamRouteFinder; namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer { public class DownstreamUrlTemplateVariableReplacer : IDownstreamUrlTemplateVariableReplacer { - public string ReplaceTemplateVariable(UrlMatch urlMatch) + public string ReplaceTemplateVariable(DownstreamRoute downstreamRoute) { var upstreamUrl = new StringBuilder(); - upstreamUrl.Append(urlMatch.DownstreamUrlTemplate); + upstreamUrl.Append(downstreamRoute.DownstreamUrlTemplate); - foreach (var templateVarAndValue in urlMatch.TemplateVariableNameAndValues) + foreach (var templateVarAndValue in downstreamRoute.TemplateVariableNameAndValues) { upstreamUrl.Replace(templateVarAndValue.TemplateVariableName, templateVarAndValue.TemplateVariableValue); } diff --git a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs index 62eac8bc..bc50a8fa 100644 --- a/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs +++ b/src/Ocelot.Library/Infrastructure/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs @@ -1,9 +1,10 @@ +using Ocelot.Library.Infrastructure.DownstreamRouteFinder; using Ocelot.Library.Infrastructure.UrlMatcher; namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer { public interface IDownstreamUrlTemplateVariableReplacer { - string ReplaceTemplateVariable(UrlMatch urlMatch); + string ReplaceTemplateVariable(DownstreamRoute downstreamRoute); } } \ No newline at end of file diff --git a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs index e723392e..1dd90dc6 100644 --- a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs +++ b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs @@ -1,56 +1,62 @@ +using System.Net; +using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using Ocelot.Library.Infrastructure.UrlMatcher; +using Microsoft.Extensions.Options; +using Ocelot.Library.Infrastructure.Configuration; +using Ocelot.Library.Infrastructure.DownstreamRouteFinder; using Ocelot.Library.Infrastructure.UrlTemplateReplacer; namespace Ocelot.Library.Middleware { - using System.Net; - using Infrastructure.Configuration; - using Microsoft.Extensions.Options; - public class ProxyMiddleware { private readonly RequestDelegate _next; - private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; private readonly IDownstreamUrlTemplateVariableReplacer _urlReplacer; private readonly IOptions _configuration; + private readonly IDownstreamRouteFinder _downstreamRouteFinder; public ProxyMiddleware(RequestDelegate next, - IUrlPathToUrlTemplateMatcher urlMatcher, - IDownstreamUrlTemplateVariableReplacer urlReplacer, IOptions configuration) + IDownstreamUrlTemplateVariableReplacer urlReplacer, + IOptions configuration, + IDownstreamRouteFinder downstreamRouteFinder) { _next = next; - _urlMatcher = urlMatcher; _urlReplacer = urlReplacer; _configuration = configuration; + _downstreamRouteFinder = downstreamRouteFinder; } public async Task Invoke(HttpContext context) { var upstreamUrlPath = context.Request.Path.ToString(); - UrlMatch urlMatch = null; + var downstreamRoute = _downstreamRouteFinder.FindDownstreamRoute(upstreamUrlPath); - foreach (var template in _configuration.Value.ReRoutes) - { - urlMatch = _urlMatcher.Match(upstreamUrlPath, template.UpstreamTemplate); - - if (urlMatch.Match) - { - break; - } - } - - if (urlMatch == null || !urlMatch.Match) + if (downstreamRoute.IsError) { context.Response.StatusCode = (int)HttpStatusCode.NotFound; return; } - - var downstreamUrl = _urlReplacer.ReplaceTemplateVariable(urlMatch); + + var downstreamUrl = _urlReplacer.ReplaceTemplateVariable(downstreamRoute.Data); //make a http request to this endpoint...maybe bring in a library + using (var httpClient = new HttpClient()) + { + var httpMethod = new HttpMethod(context.Request.Method); + + var httpRequestMessage = new HttpRequestMessage(httpMethod, downstreamUrl); + + var response = await httpClient.SendAsync(httpRequestMessage); + + if (!response.IsSuccessStatusCode) + { + context.Response.StatusCode = (int)response.StatusCode; + return; + } + await context.Response.WriteAsync(await response.Content.ReadAsStringAsync()); + } await _next.Invoke(context); } diff --git a/src/Ocelot/Startup.cs b/src/Ocelot/Startup.cs index d9400980..18d5ba6b 100644 --- a/src/Ocelot/Startup.cs +++ b/src/Ocelot/Startup.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Ocelot.Library.Infrastructure.DownstreamRouteFinder; using Ocelot.Library.Middleware; namespace Ocelot @@ -36,6 +37,7 @@ namespace Ocelot // Add framework services. services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/test/Ocelot.AcceptanceTests/OcelotTests.cs b/test/Ocelot.AcceptanceTests/OcelotTests.cs index 6f270e2c..6eea27ab 100644 --- a/test/Ocelot.AcceptanceTests/OcelotTests.cs +++ b/test/Ocelot.AcceptanceTests/OcelotTests.cs @@ -90,7 +90,7 @@ namespace Ocelot.AcceptanceTests private void WhenIRequestTheUrlOnTheApiGateway(string url) { - _response = _client.GetAsync("/").Result; + _response = _client.GetAsync(url).Result; } private void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode) diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinderTests.cs new file mode 100644 index 00000000..212e2029 --- /dev/null +++ b/test/Ocelot.UnitTests/DownstreamRouteFinderTests.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Moq; +using Ocelot.Library.Infrastructure.Configuration; +using Ocelot.Library.Infrastructure.DownstreamRouteFinder; +using Ocelot.Library.Infrastructure.Responses; +using Ocelot.Library.Infrastructure.UrlMatcher; +using Shouldly; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests +{ + public class DownstreamRouteFinderTests + { + private readonly IDownstreamRouteFinder _downstreamRouteFinder; + private readonly Mock> _mockConfig; + private readonly Mock _mockMatcher; + private string _upstreamUrlPath; + private Response _result; + private Response _response; + private Configuration _configuration; + private UrlMatch _match; + + public DownstreamRouteFinderTests() + { + _mockConfig = new Mock>(); + _mockMatcher = new Mock(); + _downstreamRouteFinder = new DownstreamRouteFinder(_mockConfig.Object, _mockMatcher.Object); + } + + [Fact] + public void should_return_route() + { + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("somePath")) + .And(x => x.GivenTheConfigurationIs(new Configuration { + ReRoutes = new List + { + new ReRoute() + { + UpstreamTemplate = "somePath", + DownstreamTemplate = "somPath" + } + } + })) + .And(x => x.GivenTheUrlMatcherReturns(new UrlMatch(true, new List(), "somePath"))) + .When(x => x.WhenICallTheFinder()) + .Then( + x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), "somePath"))) + .And(x => x.ThenTheUrlMatcherIsCalledCorrectly()) + .BDDfy(); + } + + [Fact] + public void should_not_return_route() + { + this.Given(x => x.GivenThereIsAnUpstreamUrlPath("somePath")) + .And(x => x.GivenTheConfigurationIs(new Configuration + { + ReRoutes = new List + { + new ReRoute() + { + UpstreamTemplate = "somePath", + DownstreamTemplate = "somPath" + } + } + })) + .And(x => x.GivenTheUrlMatcherReturns(new UrlMatch(false, new List(), null))) + .When(x => x.WhenICallTheFinder()) + .Then( + x => x.ThenAnErrorResponseIsReturned()) + .And(x => x.ThenTheUrlMatcherIsCalledCorrectly()) + .BDDfy(); + } + + private void ThenAnErrorResponseIsReturned() + { + _result.IsError.ShouldBeTrue(); + } + + private void ThenTheUrlMatcherIsCalledCorrectly() + { + _mockMatcher + .Verify(x => x.Match(_upstreamUrlPath, _configuration.ReRoutes[0].UpstreamTemplate), Times.Once); + } + + private void GivenTheUrlMatcherReturns(UrlMatch match) + { + _match = match; + _mockMatcher + .Setup(x => x.Match(It.IsAny(), It.IsAny())) + .Returns(_match); + } + + private void GivenTheConfigurationIs(Configuration configuration) + { + _configuration = configuration; + _mockConfig + .Setup(x => x.Value) + .Returns(_configuration); + } + + private void GivenThereIsAnUpstreamUrlPath(string upstreamUrlPath) + { + _upstreamUrlPath = upstreamUrlPath; + } + + private void WhenICallTheFinder() + { + _result = _downstreamRouteFinder.FindDownstreamRoute(_upstreamUrlPath); + } + + private void ThenTheFollowingIsReturned(DownstreamRoute expected) + { + _result.Data.DownstreamUrlTemplate.ShouldBe(expected.DownstreamUrlTemplate); + for (int i = 0; i < _result.Data.TemplateVariableNameAndValues.Count; i++) + { + _result.Data.TemplateVariableNameAndValues[i].TemplateVariableName.ShouldBe( + expected.TemplateVariableNameAndValues[i].TemplateVariableName); + + _result.Data.TemplateVariableNameAndValues[i].TemplateVariableValue.ShouldBe( + expected.TemplateVariableNameAndValues[i].TemplateVariableValue); + } + + _result.IsError.ShouldBeFalse(); + } + } +} diff --git a/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs b/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs index 6b55c013..b280e04f 100644 --- a/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs +++ b/test/Ocelot.UnitTests/UpstreamUrlPathTemplateVariableReplacerTests.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Ocelot.Library.Infrastructure.DownstreamRouteFinder; using Ocelot.Library.Infrastructure.UrlMatcher; using Ocelot.Library.Infrastructure.UrlTemplateReplacer; using Shouldly; @@ -10,7 +11,7 @@ namespace Ocelot.UnitTests public class UpstreamUrlPathTemplateVariableReplacerTests { - private UrlMatch _urlMatch; + private DownstreamRoute _downstreamRoute; private string _result; private readonly IDownstreamUrlTemplateVariableReplacer _downstreamUrlPathReplacer; @@ -22,7 +23,7 @@ namespace Ocelot.UnitTests [Fact] public void can_replace_no_template_variables() { - this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), ""))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), ""))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("")) .BDDfy(); @@ -31,7 +32,7 @@ namespace Ocelot.UnitTests [Fact] public void can_replace_no_template_variables_with_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "/"))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), "/"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("/")) .BDDfy(); @@ -40,7 +41,7 @@ namespace Ocelot.UnitTests [Fact] public void can_replace_url_no_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "api"))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), "api"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api")) .BDDfy(); @@ -49,7 +50,7 @@ namespace Ocelot.UnitTests [Fact] public void can_replace_url_one_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "api/"))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), "api/"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/")) .BDDfy(); @@ -58,7 +59,7 @@ namespace Ocelot.UnitTests [Fact] public void can_replace_url_multiple_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, new List(), "api/product/products/"))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), "api/product/products/"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/product/products/")) .BDDfy(); @@ -72,7 +73,7 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{productId}", "1") }; - this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "productservice/products/{productId}/"))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, "productservice/products/{productId}/"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/")) .BDDfy(); @@ -86,7 +87,7 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{productId}", "1") }; - this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "productservice/products/{productId}/variants"))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, "productservice/products/{productId}/variants"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants")) .BDDfy(); @@ -101,7 +102,7 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{variantId}", "12") }; - this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "productservice/products/{productId}/variants/{variantId}"))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, "productservice/products/{productId}/variants/{variantId}"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants/12")) .BDDfy(); @@ -117,20 +118,20 @@ namespace Ocelot.UnitTests new TemplateVariableNameAndValue("{categoryId}", "34") }; - this.Given(x => x.GivenThereIsAUrlMatch(new UrlMatch(true, templateVariables, "productservice/category/{categoryId}/products/{productId}/variants/{variantId}"))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, "productservice/category/{categoryId}/products/{productId}/variants/{variantId}"))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/category/34/products/1/variants/12")) .BDDfy(); } - private void GivenThereIsAUrlMatch(UrlMatch urlMatch) + private void GivenThereIsAUrlMatch(DownstreamRoute downstreamRoute) { - _urlMatch = urlMatch; + _downstreamRoute = downstreamRoute; } private void WhenIReplaceTheTemplateVariables() { - _result = _downstreamUrlPathReplacer.ReplaceTemplateVariable(_urlMatch); + _result = _downstreamUrlPathReplacer.ReplaceTemplateVariable(_downstreamRoute); } private void ThenTheDownstreamUrlPathIsReturned(string expected) diff --git a/test/Ocelot.UnitTests/project.json b/test/Ocelot.UnitTests/project.json index f8c0cf9d..7b0acc6e 100644 --- a/test/Ocelot.UnitTests/project.json +++ b/test/Ocelot.UnitTests/project.json @@ -24,7 +24,8 @@ "dotnet-test-xunit": "2.2.0-preview2-build1029", "Shouldly": "2.8.0", "TestStack.BDDfy": "4.3.1", - "YamlDotNet": "3.9.0" + "YamlDotNet": "3.9.0", + "Moq": "4.6.38-alpha" }, "frameworks": {