mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-10-31 23:15:28 +08:00 
			
		
		
		
	regex for url match, means annoying constructor ocelot configuration object but cant work out a better way to do this at the moment
This commit is contained in:
		| @@ -1,14 +0,0 @@ | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| namespace Ocelot.Library.Infrastructure.Configuration | ||||
| { | ||||
|     public class Configuration | ||||
|     { | ||||
|         public Configuration() | ||||
|         { | ||||
|             ReRoutes = new List<ReRoute>(); | ||||
|         } | ||||
|  | ||||
|         public List<ReRoute> ReRoutes { get; set; } | ||||
|     } | ||||
| } | ||||
| @@ -1,15 +0,0 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Threading.Tasks; | ||||
| using Ocelot.Library.Infrastructure.Responses; | ||||
|  | ||||
| namespace Ocelot.Library.Infrastructure.Configuration | ||||
| { | ||||
|     public class DownstreamTemplateAlreadyUsedError : Error | ||||
|     { | ||||
|         public DownstreamTemplateAlreadyUsedError(string message) : base(message) | ||||
|         { | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,13 +0,0 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Threading.Tasks; | ||||
| using Ocelot.Library.Infrastructure.Responses; | ||||
|  | ||||
| namespace Ocelot.Library.Infrastructure.Configuration | ||||
| { | ||||
|     public interface IConfigurationValidator | ||||
|     { | ||||
|         Response<ConfigurationValidationResult> IsValid(Configuration configuration); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,9 @@ | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| namespace Ocelot.Library.Infrastructure.Configuration | ||||
| { | ||||
|     public interface IOcelotConfiguration | ||||
|     { | ||||
|         List<ReRoute> ReRoutes { get; } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,57 @@ | ||||
| using System.Collections.Generic; | ||||
| using Microsoft.Extensions.Options; | ||||
| using Ocelot.Library.Infrastructure.Configuration.Yaml; | ||||
|  | ||||
| namespace Ocelot.Library.Infrastructure.Configuration | ||||
| { | ||||
|     public class OcelotConfiguration : IOcelotConfiguration | ||||
|     { | ||||
|         private readonly IOptions<YamlConfiguration> _options; | ||||
|         private readonly List<ReRoute> _reRoutes; | ||||
|         private const string RegExMatchEverything = ".*"; | ||||
|         private const string RegExMatchEndString = "$"; | ||||
|  | ||||
|         public OcelotConfiguration(IOptions<YamlConfiguration> options) | ||||
|         { | ||||
|             _options = options; | ||||
|             _reRoutes = new List<ReRoute>(); | ||||
|             SetReRoutes(); | ||||
|         } | ||||
|  | ||||
|         private void SetReRoutes() | ||||
|         { | ||||
|             foreach(var reRoute in _options.Value.ReRoutes) | ||||
|             { | ||||
|                 var upstreamTemplate = reRoute.UpstreamTemplate; | ||||
|                 var placeholders = new List<string>(); | ||||
|  | ||||
|                 for (int i = 0; i < upstreamTemplate.Length; i++) | ||||
|                 { | ||||
|                     if (IsPlaceHolder(upstreamTemplate, i)) | ||||
|                     { | ||||
|                         var postitionOfPlaceHolderClosingBracket = upstreamTemplate.IndexOf('}', i); | ||||
|                         var difference = postitionOfPlaceHolderClosingBracket - i + 1; | ||||
|                         var variableName = upstreamTemplate.Substring(i, difference); | ||||
|                         placeholders.Add(variableName); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 foreach (var placeholder in placeholders) | ||||
|                 { | ||||
|                     upstreamTemplate = upstreamTemplate.Replace(placeholder, RegExMatchEverything); | ||||
|                 } | ||||
|  | ||||
|                 upstreamTemplate = $"{upstreamTemplate}{RegExMatchEndString}"; | ||||
|  | ||||
|                 _reRoutes.Add(new ReRoute(reRoute.DownstreamTemplate, reRoute.UpstreamTemplate, reRoute.UpstreamHttpMethod, upstreamTemplate)); | ||||
|             }    | ||||
|         } | ||||
|  | ||||
|         private static bool IsPlaceHolder(string upstreamTemplate, int i) | ||||
|         { | ||||
|             return upstreamTemplate[i] == '{'; | ||||
|         } | ||||
|  | ||||
|         public List<ReRoute> ReRoutes => _reRoutes; | ||||
|     } | ||||
| } | ||||
| @@ -2,8 +2,17 @@ | ||||
| { | ||||
|     public class ReRoute | ||||
|     { | ||||
|         public string DownstreamTemplate { get; set; } | ||||
|         public string UpstreamTemplate { get; set; } | ||||
|         public string UpstreamHttpMethod { get; set; } | ||||
|         public ReRoute(string downstreamTemplate, string upstreamTemplate, string upstreamHttpMethod, string upstreamTemplatePattern) | ||||
|         { | ||||
|             DownstreamTemplate = downstreamTemplate; | ||||
|             UpstreamTemplate = upstreamTemplate; | ||||
|             UpstreamHttpMethod = upstreamHttpMethod; | ||||
|             UpstreamTemplatePattern = upstreamTemplatePattern; | ||||
|         } | ||||
|  | ||||
|         public string DownstreamTemplate { get; private set; } | ||||
|         public string UpstreamTemplate { get; private set; } | ||||
|         public string UpstreamTemplatePattern { get; private set; } | ||||
|         public string UpstreamHttpMethod { get; private set; } | ||||
|     } | ||||
| } | ||||
| @@ -1,7 +1,7 @@ | ||||
| using System.Collections.Generic; | ||||
| using Ocelot.Library.Infrastructure.Responses; | ||||
| 
 | ||||
| namespace Ocelot.Library.Infrastructure.Configuration | ||||
| namespace Ocelot.Library.Infrastructure.Configuration.Yaml | ||||
| { | ||||
|     public class ConfigurationValidationResult | ||||
|     { | ||||
| @@ -2,11 +2,11 @@ | ||||
| using System.Linq; | ||||
| using Ocelot.Library.Infrastructure.Responses; | ||||
| 
 | ||||
| namespace Ocelot.Library.Infrastructure.Configuration | ||||
| namespace Ocelot.Library.Infrastructure.Configuration.Yaml | ||||
| { | ||||
|     public class ConfigurationValidator : IConfigurationValidator | ||||
|     { | ||||
|         public Response<ConfigurationValidationResult> IsValid(Configuration configuration) | ||||
|         public Response<ConfigurationValidationResult> IsValid(YamlConfiguration configuration) | ||||
|         { | ||||
|             var duplicateUpstreamTemplates = configuration.ReRoutes | ||||
|                 .Select(r => r.DownstreamTemplate) | ||||
| @@ -0,0 +1,11 @@ | ||||
| using Ocelot.Library.Infrastructure.Responses; | ||||
|  | ||||
| namespace Ocelot.Library.Infrastructure.Configuration.Yaml | ||||
| { | ||||
|     public class DownstreamTemplateAlreadyUsedError : Error | ||||
|     { | ||||
|         public DownstreamTemplateAlreadyUsedError(string message) : base(message) | ||||
|         { | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,9 @@ | ||||
| using Ocelot.Library.Infrastructure.Responses; | ||||
|  | ||||
| namespace Ocelot.Library.Infrastructure.Configuration.Yaml | ||||
| { | ||||
|     public interface IConfigurationValidator | ||||
|     { | ||||
|         Response<ConfigurationValidationResult> IsValid(YamlConfiguration configuration); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,14 @@ | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| namespace Ocelot.Library.Infrastructure.Configuration.Yaml | ||||
| { | ||||
|     public class YamlConfiguration | ||||
|     { | ||||
|         public YamlConfiguration() | ||||
|         { | ||||
|             ReRoutes = new List<YamlReRoute>(); | ||||
|         } | ||||
|  | ||||
|         public List<YamlReRoute> ReRoutes { get; set; } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,9 @@ | ||||
| namespace Ocelot.Library.Infrastructure.Configuration.Yaml | ||||
| { | ||||
|     public class YamlReRoute | ||||
|     { | ||||
|         public string DownstreamTemplate { get; set; } | ||||
|         public string UpstreamTemplate { get; set; } | ||||
|         public string UpstreamHttpMethod { get; set; } | ||||
|     } | ||||
| } | ||||
| @@ -2,6 +2,7 @@ | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using Microsoft.Extensions.Options; | ||||
| using Ocelot.Library.Infrastructure.Configuration; | ||||
| using Ocelot.Library.Infrastructure.Responses; | ||||
| using Ocelot.Library.Infrastructure.UrlMatcher; | ||||
|  | ||||
| @@ -9,24 +10,29 @@ namespace Ocelot.Library.Infrastructure.DownstreamRouteFinder | ||||
| { | ||||
|     public class DownstreamRouteFinder : IDownstreamRouteFinder | ||||
|     { | ||||
|         private readonly IOptions<Configuration.Configuration> _configuration; | ||||
|         private readonly IOcelotConfiguration _configuration; | ||||
|         private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; | ||||
|         private readonly ITemplateVariableNameAndValueFinder _templateVariableNameAndValueFinder; | ||||
|  | ||||
|         public DownstreamRouteFinder(IOptions<Configuration.Configuration> configuration, IUrlPathToUrlTemplateMatcher urlMatcher) | ||||
|         public DownstreamRouteFinder(IOcelotConfiguration configuration, IUrlPathToUrlTemplateMatcher urlMatcher, ITemplateVariableNameAndValueFinder templateVariableNameAndValueFinder) | ||||
|         { | ||||
|             _configuration = configuration; | ||||
|             _urlMatcher = urlMatcher; | ||||
|             _templateVariableNameAndValueFinder = templateVariableNameAndValueFinder; | ||||
|         } | ||||
|  | ||||
|         public Response<DownstreamRoute> FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod) | ||||
|         { | ||||
|             foreach (var template in _configuration.Value.ReRoutes.Where(r => string.Equals(r.UpstreamHttpMethod, upstreamHttpMethod, StringComparison.CurrentCultureIgnoreCase))) | ||||
|             foreach (var template in _configuration.ReRoutes.Where(r => string.Equals(r.UpstreamHttpMethod, upstreamHttpMethod, StringComparison.CurrentCultureIgnoreCase))) | ||||
|             { | ||||
|                 var urlMatch = _urlMatcher.Match(upstreamUrlPath, template.UpstreamTemplate); | ||||
|                 var urlMatch = _urlMatcher.Match(upstreamUrlPath, template.UpstreamTemplatePattern); | ||||
|  | ||||
|                 if (urlMatch.Match) | ||||
|                 if (urlMatch.Data.Match) | ||||
|                 { | ||||
|                     return new OkResponse<DownstreamRoute>(new DownstreamRoute(urlMatch.TemplateVariableNameAndValues, template.DownstreamTemplate)); | ||||
|                     var templateVariableNameAndValues = _templateVariableNameAndValueFinder.Find(upstreamUrlPath, | ||||
|                         template.UpstreamTemplate); | ||||
|  | ||||
|                     return new OkResponse<DownstreamRoute>(new DownstreamRoute(templateVariableNameAndValues.Data, template.DownstreamTemplate)); | ||||
|                 } | ||||
|             } | ||||
|          | ||||
|   | ||||
| @@ -5,12 +5,13 @@ using System.Net.Http; | ||||
| using System.Net.Http.Headers; | ||||
| using System.Threading.Tasks; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Ocelot.Library.Infrastructure.Responses; | ||||
|  | ||||
| namespace Ocelot.Library.Infrastructure.RequestBuilder | ||||
| { | ||||
|     public class HttpRequestBuilder : IRequestBuilder | ||||
|     { | ||||
|         public async Task<Request> Build(string httpMethod, string downstreamUrl, Stream content, IHeaderDictionary headers, | ||||
|         public async Task<Response<Request>> Build(string httpMethod, string downstreamUrl, Stream content, IHeaderDictionary headers, | ||||
|             IRequestCookieCollection cookies, string queryString, string contentType) | ||||
|         { | ||||
|             var method = new HttpMethod(httpMethod); | ||||
| @@ -65,8 +66,7 @@ namespace Ocelot.Library.Infrastructure.RequestBuilder | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|  | ||||
|             return new Request(httpRequestMessage, cookieContainer); | ||||
|             return new OkResponse<Request>(new Request(httpRequestMessage, cookieContainer)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,12 +1,13 @@ | ||||
| using System.IO; | ||||
| using System.Threading.Tasks; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Ocelot.Library.Infrastructure.Responses; | ||||
|  | ||||
| namespace Ocelot.Library.Infrastructure.RequestBuilder | ||||
| { | ||||
|     public interface IRequestBuilder | ||||
|     { | ||||
|         Task<Request> Build(string httpMethod, | ||||
|         Task<Response<Request>> Build(string httpMethod, | ||||
|             string downstreamUrl, | ||||
|             Stream content, | ||||
|             IHeaderDictionary headers, | ||||
|   | ||||
| @@ -0,0 +1,10 @@ | ||||
| using System.Collections.Generic; | ||||
| using Ocelot.Library.Infrastructure.Responses; | ||||
|  | ||||
| namespace Ocelot.Library.Infrastructure.UrlMatcher | ||||
| { | ||||
|     public interface ITemplateVariableNameAndValueFinder | ||||
|     { | ||||
|         Response<List<TemplateVariableNameAndValue>> Find(string upstreamUrlPath, string upstreamUrlPathTemplate); | ||||
|     } | ||||
| } | ||||
| @@ -1,7 +1,9 @@ | ||||
| using Ocelot.Library.Infrastructure.Responses; | ||||
|  | ||||
| namespace Ocelot.Library.Infrastructure.UrlMatcher | ||||
| { | ||||
|      public interface IUrlPathToUrlTemplateMatcher | ||||
|      { | ||||
|         UrlMatch Match(string upstreamUrlPath, string upstreamUrlPathTemplate); | ||||
|         Response<UrlMatch> Match(string upstreamUrlPath, string upstreamUrlPathTemplate); | ||||
|      } | ||||
| }  | ||||
| @@ -0,0 +1,17 @@ | ||||
| using System.Text.RegularExpressions; | ||||
| using Ocelot.Library.Infrastructure.Responses; | ||||
|  | ||||
| namespace Ocelot.Library.Infrastructure.UrlMatcher | ||||
| { | ||||
|     public class RegExUrlMatcher : IUrlPathToUrlTemplateMatcher | ||||
|     { | ||||
|         public Response<UrlMatch> Match(string upstreamUrlPath, string upstreamUrlPathTemplate) | ||||
|         { | ||||
|             var regex = new Regex(upstreamUrlPathTemplate); | ||||
|  | ||||
|             return regex.IsMatch(upstreamUrlPath)  | ||||
|                 ? new OkResponse<UrlMatch>(new UrlMatch(true))  | ||||
|                 : new OkResponse<UrlMatch>(new UrlMatch(false)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,19 +1,12 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using Ocelot.Library.Infrastructure.Responses; | ||||
| 
 | ||||
| namespace Ocelot.Library.Infrastructure.UrlMatcher | ||||
| { | ||||
|      public class UrlPathToUrlTemplateMatcher : IUrlPathToUrlTemplateMatcher | ||||
|      public class TemplateVariableNameAndValueFinder : ITemplateVariableNameAndValueFinder | ||||
|     { | ||||
|         public UrlMatch Match(string upstreamUrlPath, string upstreamUrlPathTemplate) | ||||
|         public Response<List<TemplateVariableNameAndValue>> Find(string upstreamUrlPath, string upstreamUrlPathTemplate) | ||||
|         { | ||||
|             if (upstreamUrlPath.Length > upstreamUrlPathTemplate.Length) | ||||
|             { | ||||
|                 return new UrlMatch(false, new List<TemplateVariableNameAndValue>(), string.Empty); | ||||
|             } | ||||
| 
 | ||||
|             var urlPathTemplateCopy = upstreamUrlPathTemplate; | ||||
| 
 | ||||
|             var templateKeysAndValues = new List<TemplateVariableNameAndValue>(); | ||||
| 
 | ||||
|             int counterForUrl = 0; | ||||
| @@ -38,14 +31,13 @@ namespace Ocelot.Library.Infrastructure.UrlMatcher | ||||
| 
 | ||||
|                         continue; | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         return new UrlMatch(false, templateKeysAndValues, string.Empty); | ||||
|                     }  | ||||
| 
 | ||||
|                     return new OkResponse<List<TemplateVariableNameAndValue>>(templateKeysAndValues); | ||||
|                 } | ||||
|                 counterForUrl++; | ||||
|             } | ||||
|             return new UrlMatch(true, templateKeysAndValues, urlPathTemplateCopy); | ||||
| 
 | ||||
|             return new OkResponse<List<TemplateVariableNameAndValue>>(templateKeysAndValues); | ||||
|         } | ||||
| 
 | ||||
|         private string GetPlaceholderVariableValue(string urlPath, int counterForUrl) | ||||
| @@ -1,17 +1,11 @@ | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| namespace Ocelot.Library.Infrastructure.UrlMatcher | ||||
| { | ||||
|     public class UrlMatch | ||||
|     { | ||||
|         public UrlMatch(bool match, List<TemplateVariableNameAndValue> templateVariableNameAndValues, string downstreamUrlTemplate) | ||||
|         public UrlMatch(bool match) | ||||
|         { | ||||
|             Match = match;  | ||||
|             TemplateVariableNameAndValues = templateVariableNameAndValues; | ||||
|             DownstreamUrlTemplate = downstreamUrlTemplate; | ||||
|         } | ||||
|         public bool Match {get;private set;} | ||||
|         public List<TemplateVariableNameAndValue> TemplateVariableNameAndValues {get;private set;} | ||||
|         public string DownstreamUrlTemplate {get;private set;} | ||||
|     } | ||||
| } | ||||
| @@ -1,11 +1,12 @@ | ||||
| using System.Text; | ||||
| using Ocelot.Library.Infrastructure.DownstreamRouteFinder; | ||||
| using Ocelot.Library.Infrastructure.Responses; | ||||
|  | ||||
| namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer | ||||
| { | ||||
|     public class DownstreamUrlTemplateVariableReplacer : IDownstreamUrlTemplateVariableReplacer | ||||
|     { | ||||
|         public string ReplaceTemplateVariables(DownstreamRoute downstreamRoute) | ||||
|         public Response<string> ReplaceTemplateVariables(DownstreamRoute downstreamRoute) | ||||
|         { | ||||
|             var upstreamUrl = new StringBuilder(); | ||||
|  | ||||
| @@ -16,7 +17,7 @@ namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer | ||||
|                 upstreamUrl.Replace(templateVarAndValue.TemplateVariableName, templateVarAndValue.TemplateVariableValue); | ||||
|             } | ||||
|  | ||||
|             return upstreamUrl.ToString(); | ||||
|             return new OkResponse<string>(upstreamUrl.ToString()); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,10 +1,10 @@ | ||||
| using Ocelot.Library.Infrastructure.DownstreamRouteFinder; | ||||
| using Ocelot.Library.Infrastructure.UrlMatcher; | ||||
| using Ocelot.Library.Infrastructure.Responses; | ||||
|  | ||||
| namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer | ||||
| { | ||||
|     public interface IDownstreamUrlTemplateVariableReplacer | ||||
|     { | ||||
|         string ReplaceTemplateVariables(DownstreamRoute downstreamRoute);    | ||||
|         Response<string> ReplaceTemplateVariables(DownstreamRoute downstreamRoute);    | ||||
|     } | ||||
| } | ||||
| @@ -2,25 +2,22 @@ using System.Threading.Tasks; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Ocelot.Library.Infrastructure.DownstreamRouteFinder; | ||||
| using Ocelot.Library.Infrastructure.Repository; | ||||
| using Ocelot.Library.Infrastructure.Responder; | ||||
|  | ||||
| namespace Ocelot.Library.Middleware | ||||
| { | ||||
|     public class DownstreamRouteFinderMiddleware | ||||
|     public class DownstreamRouteFinderMiddleware : OcelotMiddleware | ||||
|     { | ||||
|         private readonly RequestDelegate _next; | ||||
|         private readonly IDownstreamRouteFinder _downstreamRouteFinder; | ||||
|         private readonly IHttpResponder _responder; | ||||
|         private readonly IScopedRequestDataRepository _scopedRequestDataRepository; | ||||
|  | ||||
|         public DownstreamRouteFinderMiddleware(RequestDelegate next,  | ||||
|             IDownstreamRouteFinder downstreamRouteFinder,  | ||||
|             IHttpResponder responder, | ||||
|             IScopedRequestDataRepository scopedRequestDataRepository) | ||||
|             :base(scopedRequestDataRepository) | ||||
|         { | ||||
|             _next = next; | ||||
|             _downstreamRouteFinder = downstreamRouteFinder; | ||||
|             _responder = responder; | ||||
|             _scopedRequestDataRepository = scopedRequestDataRepository; | ||||
|         } | ||||
|  | ||||
| @@ -32,7 +29,7 @@ namespace Ocelot.Library.Middleware | ||||
|  | ||||
|             if (downstreamRoute.IsError) | ||||
|             { | ||||
|                 await _responder.CreateNotFoundResponse(context); | ||||
|                 SetPipelineError(downstreamRoute.Errors); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|   | ||||
| @@ -7,22 +7,20 @@ using Ocelot.Library.Infrastructure.UrlTemplateReplacer; | ||||
|  | ||||
| namespace Ocelot.Library.Middleware | ||||
| { | ||||
|     public class DownstreamUrlCreatorMiddleware | ||||
|     public class DownstreamUrlCreatorMiddleware : OcelotMiddleware | ||||
|     { | ||||
|         private readonly RequestDelegate _next; | ||||
|         private readonly IDownstreamUrlTemplateVariableReplacer _urlReplacer; | ||||
|         private readonly IScopedRequestDataRepository _scopedRequestDataRepository; | ||||
|         private readonly IHttpResponder _responder; | ||||
|  | ||||
|         public DownstreamUrlCreatorMiddleware(RequestDelegate next,  | ||||
|             IDownstreamUrlTemplateVariableReplacer urlReplacer, | ||||
|             IScopedRequestDataRepository scopedRequestDataRepository,  | ||||
|             IHttpResponder responder) | ||||
|             IScopedRequestDataRepository scopedRequestDataRepository) | ||||
|             :base(scopedRequestDataRepository) | ||||
|         { | ||||
|             _next = next; | ||||
|             _urlReplacer = urlReplacer; | ||||
|             _scopedRequestDataRepository = scopedRequestDataRepository; | ||||
|             _responder = responder; | ||||
|         } | ||||
|  | ||||
|         public async Task Invoke(HttpContext context) | ||||
| @@ -31,13 +29,19 @@ namespace Ocelot.Library.Middleware | ||||
|  | ||||
|             if (downstreamRoute.IsError) | ||||
|             { | ||||
|                 await _responder.CreateNotFoundResponse(context); | ||||
|                 SetPipelineError(downstreamRoute.Errors); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             var downstreamUrl = _urlReplacer.ReplaceTemplateVariables(downstreamRoute.Data); | ||||
|  | ||||
|             _scopedRequestDataRepository.Add("DownstreamUrl", downstreamUrl); | ||||
|             if (downstreamUrl.IsError) | ||||
|             { | ||||
|                 SetPipelineError(downstreamUrl.Errors); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             _scopedRequestDataRepository.Add("DownstreamUrl", downstreamUrl.Data); | ||||
|                  | ||||
|             await _next.Invoke(context); | ||||
|         } | ||||
|   | ||||
| @@ -1,27 +1,22 @@ | ||||
| using System.Threading.Tasks; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Ocelot.Library.Infrastructure.Repository; | ||||
| using Ocelot.Library.Infrastructure.Requester; | ||||
| using Ocelot.Library.Infrastructure.Responder; | ||||
| using Ocelot.Library.Infrastructure.RequestBuilder; | ||||
|  | ||||
| namespace Ocelot.Library.Middleware | ||||
| { | ||||
|     using Infrastructure.RequestBuilder; | ||||
|  | ||||
|     public class HttpRequestBuilderMiddleware | ||||
|     public class HttpRequestBuilderMiddleware : OcelotMiddleware | ||||
|     { | ||||
|         private readonly RequestDelegate _next; | ||||
|         private readonly IHttpResponder _responder; | ||||
|         private readonly IScopedRequestDataRepository _scopedRequestDataRepository; | ||||
|         private readonly IRequestBuilder _requestBuilder; | ||||
|  | ||||
|         public HttpRequestBuilderMiddleware(RequestDelegate next,  | ||||
|             IHttpResponder responder, | ||||
|             IScopedRequestDataRepository scopedRequestDataRepository,  | ||||
|             IRequestBuilder requestBuilder) | ||||
|             :base(scopedRequestDataRepository) | ||||
|         { | ||||
|             _next = next; | ||||
|             _responder = responder; | ||||
|             _scopedRequestDataRepository = scopedRequestDataRepository; | ||||
|             _requestBuilder = requestBuilder; | ||||
|         } | ||||
| @@ -32,7 +27,7 @@ namespace Ocelot.Library.Middleware | ||||
|  | ||||
|             if (downstreamUrl.IsError) | ||||
|             { | ||||
|                 await _responder.CreateNotFoundResponse(context); | ||||
|                 SetPipelineError(downstreamUrl.Errors); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
| @@ -40,7 +35,13 @@ namespace Ocelot.Library.Middleware | ||||
|               .Build(context.Request.Method, downstreamUrl.Data, context.Request.Body, | ||||
|               context.Request.Headers, context.Request.Cookies, context.Request.QueryString.Value, context.Request.ContentType); | ||||
|  | ||||
|             _scopedRequestDataRepository.Add("Request", request); | ||||
|             if (request.IsError) | ||||
|             { | ||||
|                 SetPipelineError(request.Errors); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             _scopedRequestDataRepository.Add("Request", request.Data); | ||||
|  | ||||
|             await _next.Invoke(context); | ||||
|         } | ||||
|   | ||||
| @@ -1,29 +1,24 @@ | ||||
| using System.Net.Http; | ||||
| using System.Threading.Tasks; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Ocelot.Library.Infrastructure.Repository; | ||||
| using Ocelot.Library.Infrastructure.RequestBuilder; | ||||
| using Ocelot.Library.Infrastructure.Requester; | ||||
| using Ocelot.Library.Infrastructure.Responder; | ||||
|  | ||||
| namespace Ocelot.Library.Middleware | ||||
| { | ||||
|     using Infrastructure.RequestBuilder; | ||||
|  | ||||
|     public class HttpRequesterMiddleware | ||||
|     public class HttpRequesterMiddleware : OcelotMiddleware | ||||
|     { | ||||
|         private readonly RequestDelegate _next; | ||||
|         private readonly IHttpRequester _requester; | ||||
|         private readonly IHttpResponder _responder; | ||||
|         private readonly IScopedRequestDataRepository _scopedRequestDataRepository; | ||||
|  | ||||
|         public HttpRequesterMiddleware(RequestDelegate next,  | ||||
|             IHttpRequester requester,  | ||||
|             IHttpResponder responder, | ||||
|             IScopedRequestDataRepository scopedRequestDataRepository) | ||||
|             :base(scopedRequestDataRepository) | ||||
|         { | ||||
|             _next = next; | ||||
|             _requester = requester; | ||||
|             _responder = responder; | ||||
|             _scopedRequestDataRepository = scopedRequestDataRepository; | ||||
|         } | ||||
|  | ||||
| @@ -33,16 +28,19 @@ namespace Ocelot.Library.Middleware | ||||
|  | ||||
|             if (request.IsError) | ||||
|             { | ||||
|                 await _responder.CreateNotFoundResponse(context); | ||||
|                 SetPipelineError(request.Errors); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             var response = await _requester | ||||
|                 .GetResponse(request.Data); | ||||
|             var response = await _requester.GetResponse(request.Data); | ||||
|  | ||||
|             if (response.IsError) | ||||
|             { | ||||
|                 SetPipelineError(response.Errors); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             _scopedRequestDataRepository.Add("Response", response.Data);             | ||||
|              | ||||
|             await _next.Invoke(context); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -6,10 +6,7 @@ using Ocelot.Library.Infrastructure.Responder; | ||||
|  | ||||
| namespace Ocelot.Library.Middleware | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Terminating middleware that is responsible for returning a http response to the client | ||||
|     /// </summary> | ||||
|     public class HttpResponderMiddleware | ||||
|     public class HttpResponderMiddleware : OcelotMiddleware | ||||
|     { | ||||
|         private readonly RequestDelegate _next; | ||||
|         private readonly IHttpResponder _responder; | ||||
| @@ -18,6 +15,7 @@ namespace Ocelot.Library.Middleware | ||||
|         public HttpResponderMiddleware(RequestDelegate next,  | ||||
|             IHttpResponder responder, | ||||
|             IScopedRequestDataRepository scopedRequestDataRepository) | ||||
|             :base(scopedRequestDataRepository) | ||||
|         { | ||||
|             _next = next; | ||||
|             _responder = responder; | ||||
| @@ -26,9 +24,22 @@ namespace Ocelot.Library.Middleware | ||||
|  | ||||
|         public async Task Invoke(HttpContext context) | ||||
|         { | ||||
|             var response = _scopedRequestDataRepository.Get<HttpResponseMessage>("Response"); | ||||
|             await _next.Invoke(context); | ||||
|  | ||||
|             await _responder.CreateResponse(context, response.Data); | ||||
|             if (PipelineError()) | ||||
|             { | ||||
|                 //todo obviously this needs to be better...prob look at response errors | ||||
|                 // and make a decision i guess | ||||
|                 var errors = GetPipelineErrors(); | ||||
|  | ||||
|                 await _responder.CreateNotFoundResponse(context); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 var response = _scopedRequestDataRepository.Get<HttpResponseMessage>("Response"); | ||||
|  | ||||
|                 await _responder.CreateResponse(context, response.Data); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										34
									
								
								src/Ocelot.Library/Middleware/OcelotMiddleware.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/Ocelot.Library/Middleware/OcelotMiddleware.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| using System.Collections.Generic; | ||||
| using Ocelot.Library.Infrastructure.Repository; | ||||
| using Ocelot.Library.Infrastructure.Responses; | ||||
|  | ||||
| namespace Ocelot.Library.Middleware | ||||
| { | ||||
|     public class OcelotMiddleware | ||||
|     { | ||||
|         private readonly IScopedRequestDataRepository _scopedRequestDataRepository; | ||||
|  | ||||
|         public OcelotMiddleware(IScopedRequestDataRepository scopedRequestDataRepository) | ||||
|         { | ||||
|             _scopedRequestDataRepository = scopedRequestDataRepository; | ||||
|         } | ||||
|  | ||||
|         public void SetPipelineError(List<Error> errors) | ||||
|         { | ||||
|             _scopedRequestDataRepository.Add("OcelotMiddlewareError", true); | ||||
|             _scopedRequestDataRepository.Add("OcelotMiddlewareErrors", errors); | ||||
|         } | ||||
|  | ||||
|         public bool PipelineError() | ||||
|         { | ||||
|             var response = _scopedRequestDataRepository.Get<bool>("OcelotMiddlewareError"); | ||||
|             return response.Data; | ||||
|         } | ||||
|  | ||||
|         public List<Error> GetPipelineErrors() | ||||
|         { | ||||
|             var response = _scopedRequestDataRepository.Get<List<Error>>("OcelotMiddlewareErrors"); | ||||
|             return response.Data; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -17,6 +17,7 @@ | ||||
|         "Microsoft.Extensions.Logging.Debug": "1.0.0", | ||||
|         "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", | ||||
|         "Microsoft.AspNetCore.Http": "1.0.0", | ||||
|         "System.Text.RegularExpressions": "4.1.0", | ||||
|         "YamlDotNet": "3.9.0" | ||||
|     }, | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,14 @@ | ||||
| using Microsoft.AspNetCore.Builder; | ||||
| using System.Collections.Generic; | ||||
| using Microsoft.AspNetCore.Builder; | ||||
| using Microsoft.AspNetCore.Hosting; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Microsoft.Extensions.Configuration; | ||||
| using Microsoft.Extensions.Configuration.Memory; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
| using Microsoft.Extensions.Logging; | ||||
| using Microsoft.Extensions.Options; | ||||
| using Ocelot.Library.Infrastructure.Configuration; | ||||
| using Ocelot.Library.Infrastructure.Configuration.Yaml; | ||||
| using Ocelot.Library.Infrastructure.DownstreamRouteFinder; | ||||
| using Ocelot.Library.Infrastructure.Repository; | ||||
| using Ocelot.Library.Infrastructure.RequestBuilder; | ||||
| @@ -26,6 +30,7 @@ namespace Ocelot | ||||
|                 .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) | ||||
|                 .AddYamlFile("configuration.yaml") | ||||
|                 .AddEnvironmentVariables(); | ||||
|  | ||||
|             Configuration = builder.Build(); | ||||
|         } | ||||
|  | ||||
| @@ -36,10 +41,12 @@ namespace Ocelot | ||||
|         { | ||||
|             services.AddOptions(); | ||||
|                          | ||||
|             services.Configure<Configuration>(Configuration); | ||||
|             services.Configure<YamlConfiguration>(Configuration); | ||||
|  | ||||
|             // Add framework services. | ||||
|             services.AddSingleton<IUrlPathToUrlTemplateMatcher, UrlPathToUrlTemplateMatcher>(); | ||||
|             services.AddSingleton<IOcelotConfiguration, OcelotConfiguration>(); | ||||
|             services.AddSingleton<IUrlPathToUrlTemplateMatcher, RegExUrlMatcher>(); | ||||
|             services.AddSingleton<ITemplateVariableNameAndValueFinder, TemplateVariableNameAndValueFinder>(); | ||||
|             services.AddSingleton<IDownstreamUrlTemplateVariableReplacer, DownstreamUrlTemplateVariableReplacer>(); | ||||
|             services.AddSingleton<IDownstreamRouteFinder, DownstreamRouteFinder>(); | ||||
|             services.AddSingleton<IHttpRequester, HttpClientHttpRequester>(); | ||||
| @@ -58,6 +65,8 @@ namespace Ocelot | ||||
|  | ||||
|             loggerFactory.AddDebug(); | ||||
|  | ||||
|             app.UseHttpResponderMiddleware(); | ||||
|  | ||||
|             app.UseDownstreamRouteFinderMiddleware(); | ||||
|  | ||||
|             app.UserDownstreamUrlCreatorMiddleware(); | ||||
| @@ -65,8 +74,6 @@ namespace Ocelot | ||||
|             app.UseHttpRequestBuilderMiddleware(); | ||||
|  | ||||
|             app.UseHttpRequesterMiddleware(); | ||||
|  | ||||
|             app.UseHttpResponderMiddleware(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,7 +6,7 @@ using System.Net.Http; | ||||
| using Microsoft.AspNetCore.Hosting; | ||||
| using Microsoft.AspNetCore.TestHost; | ||||
| using Ocelot.AcceptanceTests.Fake; | ||||
| using Ocelot.Library.Infrastructure.Configuration; | ||||
| using Ocelot.Library.Infrastructure.Configuration.Yaml; | ||||
| using Shouldly; | ||||
| using TestStack.BDDfy; | ||||
| using Xunit; | ||||
| @@ -32,7 +32,7 @@ namespace Ocelot.AcceptanceTests | ||||
|         [Fact] | ||||
|         public void should_return_response_404() | ||||
|         { | ||||
|             this.Given(x => x.GivenThereIsAConfiguration(new Configuration())) | ||||
|             this.Given(x => x.GivenThereIsAConfiguration(new YamlConfiguration())) | ||||
|                 .And(x => x.GivenTheApiGatewayIsRunning()) | ||||
|                 .When(x => x.WhenIGetUrlOnTheApiGateway("/")) | ||||
|                 .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound)) | ||||
| @@ -43,11 +43,11 @@ namespace Ocelot.AcceptanceTests | ||||
|         public void should_return_response_200() | ||||
|         { | ||||
|             this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879")) | ||||
|                 .And(x => x.GivenThereIsAConfiguration(new Configuration | ||||
|                 .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration | ||||
|                 { | ||||
|                     ReRoutes = new List<ReRoute> | ||||
|                     ReRoutes = new List<YamlReRoute> | ||||
|                     { | ||||
|                         new ReRoute | ||||
|                         new YamlReRoute | ||||
|                         { | ||||
|                             DownstreamTemplate = "http://localhost:51879/", | ||||
|                             UpstreamTemplate = "/", | ||||
| @@ -66,11 +66,11 @@ namespace Ocelot.AcceptanceTests | ||||
|         public void should_return_response_201() | ||||
|         { | ||||
|             this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879")) | ||||
|                 .And(x => x.GivenThereIsAConfiguration(new Configuration | ||||
|                 .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration | ||||
|                 { | ||||
|                     ReRoutes = new List<ReRoute> | ||||
|                     ReRoutes = new List<YamlReRoute> | ||||
|                     { | ||||
|                         new ReRoute | ||||
|                         new YamlReRoute | ||||
|                         { | ||||
|                             DownstreamTemplate = "http://localhost:51879/", | ||||
|                             UpstreamTemplate = "/", | ||||
| @@ -100,7 +100,7 @@ namespace Ocelot.AcceptanceTests | ||||
|             _client = _server.CreateClient(); | ||||
|         } | ||||
|  | ||||
|         private void GivenThereIsAConfiguration(Configuration configuration) | ||||
|         private void GivenThereIsAConfiguration(YamlConfiguration yamlConfiguration) | ||||
|         { | ||||
|             var serializer = new Serializer(); | ||||
|  | ||||
| @@ -111,7 +111,7 @@ namespace Ocelot.AcceptanceTests | ||||
|  | ||||
|             using (TextWriter writer = File.CreateText(_configurationPath)) | ||||
|             { | ||||
|                 serializer.Serialize(writer, configuration); | ||||
|                 serializer.Serialize(writer, yamlConfiguration); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| using System.Collections.Generic; | ||||
| using Ocelot.Library.Infrastructure.Configuration; | ||||
| using Ocelot.Library.Infrastructure.Configuration.Yaml; | ||||
| using Ocelot.Library.Infrastructure.Responses; | ||||
| using Shouldly; | ||||
| using TestStack.BDDfy; | ||||
| @@ -9,7 +9,7 @@ namespace Ocelot.UnitTests.Configuration | ||||
| { | ||||
|     public class ConfigurationValidationTests | ||||
|     { | ||||
|         private Library.Infrastructure.Configuration.Configuration _configuration; | ||||
|         private YamlConfiguration _yamlConfiguration; | ||||
|         private readonly IConfigurationValidator _configurationValidator; | ||||
|         private Response<ConfigurationValidationResult> _result; | ||||
|  | ||||
| @@ -21,11 +21,11 @@ namespace Ocelot.UnitTests.Configuration | ||||
|         [Fact] | ||||
|         public void configuration_is_valid_with_one_reroute() | ||||
|         { | ||||
|             this.Given(x => x.GivenAConfiguration(new Library.Infrastructure.Configuration.Configuration() | ||||
|             this.Given(x => x.GivenAConfiguration(new YamlConfiguration() | ||||
|             { | ||||
|                 ReRoutes = new List<ReRoute> | ||||
|                 ReRoutes = new List<YamlReRoute> | ||||
|                 { | ||||
|                     new ReRoute | ||||
|                     new YamlReRoute | ||||
|                     { | ||||
|                         DownstreamTemplate = "http://www.bbc.co.uk", | ||||
|                         UpstreamTemplate = "http://asdf.com" | ||||
| @@ -40,16 +40,16 @@ namespace Ocelot.UnitTests.Configuration | ||||
|         [Fact] | ||||
|         public void configuration_is_not_valid_with_duplicate_reroutes() | ||||
|         { | ||||
|             this.Given(x => x.GivenAConfiguration(new Library.Infrastructure.Configuration.Configuration() | ||||
|             this.Given(x => x.GivenAConfiguration(new YamlConfiguration() | ||||
|             { | ||||
|                 ReRoutes = new List<ReRoute> | ||||
|                 ReRoutes = new List<YamlReRoute> | ||||
|                 { | ||||
|                     new ReRoute | ||||
|                     new YamlReRoute | ||||
|                     { | ||||
|                         DownstreamTemplate = "http://www.bbc.co.uk", | ||||
|                         UpstreamTemplate = "http://asdf.com" | ||||
|                     }, | ||||
|                     new ReRoute | ||||
|                     new YamlReRoute | ||||
|                     { | ||||
|                         DownstreamTemplate = "http://www.bbc.co.uk", | ||||
|                         UpstreamTemplate = "http://lol.com" | ||||
| @@ -62,14 +62,14 @@ namespace Ocelot.UnitTests.Configuration | ||||
|                 .BDDfy(); | ||||
|         } | ||||
|  | ||||
|         private void GivenAConfiguration(Library.Infrastructure.Configuration.Configuration configuration) | ||||
|         private void GivenAConfiguration(YamlConfiguration yamlConfiguration) | ||||
|         { | ||||
|             _configuration = configuration; | ||||
|             _yamlConfiguration = yamlConfiguration; | ||||
|         } | ||||
|  | ||||
|         private void WhenIValidateTheConfiguration() | ||||
|         { | ||||
|             _result = _configurationValidator.IsValid(_configuration); | ||||
|             _result = _configurationValidator.IsValid(_yamlConfiguration); | ||||
|         } | ||||
|  | ||||
|         private void ThenTheResultIsValid() | ||||
|   | ||||
							
								
								
									
										142
									
								
								test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								test/Ocelot.UnitTests/Configuration/OcelotConfigurationTests.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,142 @@ | ||||
| using System.Collections.Generic; | ||||
| using Microsoft.Extensions.Options; | ||||
| using Moq; | ||||
| using Ocelot.Library.Infrastructure.Configuration; | ||||
| using Ocelot.Library.Infrastructure.Configuration.Yaml; | ||||
| using Shouldly; | ||||
| using TestStack.BDDfy; | ||||
| using Xunit; | ||||
|  | ||||
| namespace Ocelot.UnitTests.Configuration | ||||
| { | ||||
|     public class OcelotConfigurationTests | ||||
|     { | ||||
|         private readonly Mock<IOptions<YamlConfiguration>> _yamlConfig; | ||||
|         private OcelotConfiguration _config; | ||||
|         private YamlConfiguration _yamlConfiguration; | ||||
|  | ||||
|         public OcelotConfigurationTests() | ||||
|         { | ||||
|             _yamlConfig = new Mock<IOptions<YamlConfiguration>>(); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void should_create_template_pattern_that_matches_anything_to_end_of_string() | ||||
|         { | ||||
|             this.Given(x => x.GivenTheYamlConfigIs(new YamlConfiguration | ||||
|             { | ||||
|                 ReRoutes = new List<YamlReRoute> | ||||
|                 { | ||||
|                     new YamlReRoute | ||||
|                     { | ||||
|                         UpstreamTemplate = "/api/products/{productId}", | ||||
|                         DownstreamTemplate = "/products/{productId}", | ||||
|                         UpstreamHttpMethod = "Get" | ||||
|                     } | ||||
|                 } | ||||
|             })) | ||||
|                 .When(x => x.WhenIInstanciateTheOcelotConfig()) | ||||
|                 .Then(x => x.ThenTheReRoutesAre(new List<ReRoute> | ||||
|                 { | ||||
|                     new ReRoute("/products/{productId}","/api/products/{productId}", "Get", "/api/products/.*$") | ||||
|                 })) | ||||
|                 .BDDfy(); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void should_create_template_pattern_that_matches_more_than_one_placeholder() | ||||
|         { | ||||
|             this.Given(x => x.GivenTheYamlConfigIs(new YamlConfiguration | ||||
|             { | ||||
|                 ReRoutes = new List<YamlReRoute> | ||||
|                 { | ||||
|                     new YamlReRoute | ||||
|                     { | ||||
|                         UpstreamTemplate = "/api/products/{productId}/variants/{variantId}", | ||||
|                         DownstreamTemplate = "/products/{productId}", | ||||
|                         UpstreamHttpMethod = "Get" | ||||
|                     } | ||||
|                 } | ||||
|             })) | ||||
|                 .When(x => x.WhenIInstanciateTheOcelotConfig()) | ||||
|                 .Then(x => x.ThenTheReRoutesAre(new List<ReRoute> | ||||
|                 { | ||||
|                     new ReRoute("/products/{productId}","/api/products/{productId}/variants/{variantId}", "Get", "/api/products/.*/variants/.*$") | ||||
|                 })) | ||||
|                 .BDDfy(); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void should_create_template_pattern_that_matches_more_than_one_placeholder_with_trailing_slash() | ||||
|         { | ||||
|             this.Given(x => x.GivenTheYamlConfigIs(new YamlConfiguration | ||||
|             { | ||||
|                 ReRoutes = new List<YamlReRoute> | ||||
|                 { | ||||
|                     new YamlReRoute | ||||
|                     { | ||||
|                         UpstreamTemplate = "/api/products/{productId}/variants/{variantId}/", | ||||
|                         DownstreamTemplate = "/products/{productId}", | ||||
|                         UpstreamHttpMethod = "Get" | ||||
|                     } | ||||
|                 } | ||||
|             })) | ||||
|                 .When(x => x.WhenIInstanciateTheOcelotConfig()) | ||||
|                 .Then(x => x.ThenTheReRoutesAre(new List<ReRoute> | ||||
|                 { | ||||
|                     new ReRoute("/products/{productId}","/api/products/{productId}/variants/{variantId}/", "Get", "/api/products/.*/variants/.*/$") | ||||
|                 })) | ||||
|                 .BDDfy(); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void should_create_template_pattern_that_matches_to_end_of_string() | ||||
|         { | ||||
|             this.Given(x => x.GivenTheYamlConfigIs(new YamlConfiguration | ||||
|             { | ||||
|                 ReRoutes = new List<YamlReRoute> | ||||
|                 { | ||||
|                     new YamlReRoute | ||||
|                     { | ||||
|                         UpstreamTemplate = "/", | ||||
|                         DownstreamTemplate = "/api/products/", | ||||
|                         UpstreamHttpMethod = "Get" | ||||
|                     } | ||||
|                 } | ||||
|             })) | ||||
|                 .When(x => x.WhenIInstanciateTheOcelotConfig()) | ||||
|                 .Then(x => x.ThenTheReRoutesAre(new List<ReRoute> | ||||
|                 { | ||||
|                     new ReRoute("/api/products/","/", "Get", "/$") | ||||
|                 })) | ||||
|                 .BDDfy(); | ||||
|         } | ||||
|  | ||||
|         private void GivenTheYamlConfigIs(YamlConfiguration yamlConfiguration) | ||||
|         { | ||||
|             _yamlConfiguration = yamlConfiguration; | ||||
|             _yamlConfig | ||||
|                 .Setup(x => x.Value) | ||||
|                 .Returns(_yamlConfiguration); | ||||
|         } | ||||
|  | ||||
|         private void WhenIInstanciateTheOcelotConfig() | ||||
|         { | ||||
|             _config = new OcelotConfiguration(_yamlConfig.Object); | ||||
|         } | ||||
|  | ||||
|         private void ThenTheReRoutesAre(List<ReRoute> expectedReRoutes) | ||||
|         { | ||||
|             for (int i = 0; i < _config.ReRoutes.Count; i++) | ||||
|             { | ||||
|                 var result = _config.ReRoutes[i]; | ||||
|                 var expected = expectedReRoutes[i]; | ||||
|  | ||||
|                 result.DownstreamTemplate.ShouldBe(expected.DownstreamTemplate); | ||||
|                 result.UpstreamHttpMethod.ShouldBe(expected.UpstreamHttpMethod); | ||||
|                 result.UpstreamTemplate.ShouldBe(expected.UpstreamTemplate); | ||||
|                 result.UpstreamTemplatePattern.ShouldBe(expected.UpstreamTemplatePattern); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,5 +1,4 @@ | ||||
| using System.Collections.Generic; | ||||
| using Microsoft.Extensions.Options; | ||||
| using Moq; | ||||
| using Ocelot.Library.Infrastructure.Configuration; | ||||
| using Ocelot.Library.Infrastructure.DownstreamRouteFinder; | ||||
| @@ -14,38 +13,35 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder | ||||
|     public class DownstreamRouteFinderTests | ||||
|     { | ||||
|         private readonly IDownstreamRouteFinder _downstreamRouteFinder; | ||||
|         private readonly Mock<IOptions<Library.Infrastructure.Configuration.Configuration>> _mockConfig; | ||||
|         private readonly Mock<IOcelotConfiguration> _mockConfig; | ||||
|         private readonly Mock<IUrlPathToUrlTemplateMatcher> _mockMatcher; | ||||
|         private readonly Mock<ITemplateVariableNameAndValueFinder> _finder; | ||||
|         private string _upstreamUrlPath; | ||||
|         private Response<DownstreamRoute> _result; | ||||
|         private Response<DownstreamRoute> _response; | ||||
|         private Library.Infrastructure.Configuration.Configuration _configuration; | ||||
|         private UrlMatch _match; | ||||
|         private List<ReRoute> _reRoutesConfig; | ||||
|         private Response<UrlMatch> _match; | ||||
|         private string _upstreamHttpMethod; | ||||
|  | ||||
|         public DownstreamRouteFinderTests() | ||||
|         { | ||||
|             _mockConfig = new Mock<IOptions<Library.Infrastructure.Configuration.Configuration>>(); | ||||
|             _mockConfig = new Mock<IOcelotConfiguration>(); | ||||
|             _mockMatcher = new Mock<IUrlPathToUrlTemplateMatcher>(); | ||||
|             _downstreamRouteFinder = new Library.Infrastructure.DownstreamRouteFinder.DownstreamRouteFinder(_mockConfig.Object, _mockMatcher.Object); | ||||
|             _finder = new Mock<ITemplateVariableNameAndValueFinder>(); | ||||
|             _downstreamRouteFinder = new Library.Infrastructure.DownstreamRouteFinder.DownstreamRouteFinder(_mockConfig.Object, _mockMatcher.Object, _finder.Object); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void should_return_route() | ||||
|         { | ||||
|             this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) | ||||
|                 .And(x => x.GivenTheConfigurationIs(new Library.Infrastructure.Configuration.Configuration { | ||||
|                     ReRoutes = new List<ReRoute> | ||||
|                 .And(x => x.GivenTheTemplateVariableAndNameFinderReturns(new OkResponse<List<TemplateVariableNameAndValue>>(new List<TemplateVariableNameAndValue>()))) | ||||
|                 .And(x => x.GivenTheConfigurationIs(new List<ReRoute> | ||||
|                     { | ||||
|                         new ReRoute() | ||||
|                         { | ||||
|                             UpstreamTemplate = "someUpstreamPath", | ||||
|                             DownstreamTemplate = "someDownstreamPath", | ||||
|                             UpstreamHttpMethod = "Get" | ||||
|                         } | ||||
|                         new ReRoute("someDownstreamPath","someUpstreamPath", "Get", "someUpstreamPath") | ||||
|                     } | ||||
|                 })) | ||||
|                 .And(x => x.GivenTheUrlMatcherReturns(new UrlMatch(true, new List<TemplateVariableNameAndValue>(), "someDownstreamPath"))) | ||||
|                 )) | ||||
|                 .And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true)))) | ||||
|                 .And(x => x.GivenTheUpstreamHttpMethodIs("Get")) | ||||
|                 .When(x => x.WhenICallTheFinder()) | ||||
|                 .Then( | ||||
| @@ -58,25 +54,14 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder | ||||
|         public void should_return_correct_route_for_http_verb() | ||||
|         { | ||||
|             this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) | ||||
|                 .And(x => x.GivenTheConfigurationIs(new Library.Infrastructure.Configuration.Configuration | ||||
|                 { | ||||
|                     ReRoutes = new List<ReRoute> | ||||
|                 .And(x => x.GivenTheTemplateVariableAndNameFinderReturns(new OkResponse<List<TemplateVariableNameAndValue>>(new List<TemplateVariableNameAndValue>()))) | ||||
|                 .And(x => x.GivenTheConfigurationIs(new List<ReRoute> | ||||
|                     { | ||||
|                         new ReRoute() | ||||
|                         { | ||||
|                             UpstreamTemplate = "someUpstreamPath", | ||||
|                             DownstreamTemplate = "someDownstreamPath", | ||||
|                             UpstreamHttpMethod = "Get" | ||||
|                         }, | ||||
|                          new ReRoute() | ||||
|                         { | ||||
|                             UpstreamTemplate = "someUpstreamPath", | ||||
|                             DownstreamTemplate = "someDownstreamPathForAPost", | ||||
|                             UpstreamHttpMethod = "Post" | ||||
|                         } | ||||
|                         new ReRoute("someDownstreamPath", "someUpstreamPath", "Get", string.Empty), | ||||
|                         new ReRoute("someDownstreamPathForAPost", "someUpstreamPath", "Post", string.Empty) | ||||
|                     } | ||||
|                 })) | ||||
|                 .And(x => x.GivenTheUrlMatcherReturns(new UrlMatch(true, new List<TemplateVariableNameAndValue>(), "someDownstreamPathForAPost"))) | ||||
|                 )) | ||||
|                 .And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true)))) | ||||
|                 .And(x => x.GivenTheUpstreamHttpMethodIs("Post")) | ||||
|                 .When(x => x.WhenICallTheFinder()) | ||||
|                 .Then( | ||||
| @@ -88,19 +73,12 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder | ||||
|         public void should_not_return_route() | ||||
|         { | ||||
|             this.Given(x => x.GivenThereIsAnUpstreamUrlPath("somePath")) | ||||
|                  .And(x => x.GivenTheConfigurationIs(new Library.Infrastructure.Configuration.Configuration | ||||
|                  { | ||||
|                      ReRoutes = new List<ReRoute> | ||||
|                  .And(x => x.GivenTheConfigurationIs(new List<ReRoute> | ||||
|                      { | ||||
|                         new ReRoute() | ||||
|                         { | ||||
|                             UpstreamTemplate = "somePath", | ||||
|                             DownstreamTemplate = "somPath", | ||||
|                             UpstreamHttpMethod = "Get" | ||||
|                         } | ||||
|                         new ReRoute("somPath", "somePath", "Get", "somePath") | ||||
|                      } | ||||
|                  })) | ||||
|                  .And(x => x.GivenTheUrlMatcherReturns(new UrlMatch(false, new List<TemplateVariableNameAndValue>(), null))) | ||||
|                  )) | ||||
|                  .And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(false)))) | ||||
|                  .And(x => x.GivenTheUpstreamHttpMethodIs("Get")) | ||||
|                  .When(x => x.WhenICallTheFinder()) | ||||
|                  .Then( | ||||
| @@ -109,6 +87,13 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder | ||||
|                  .BDDfy(); | ||||
|         } | ||||
|  | ||||
|         private void GivenTheTemplateVariableAndNameFinderReturns(Response<List<TemplateVariableNameAndValue>> response) | ||||
|         { | ||||
|             _finder | ||||
|                 .Setup(x => x.Find(It.IsAny<string>(), It.IsAny<string>())) | ||||
|                 .Returns(response); | ||||
|         } | ||||
|  | ||||
|         private void GivenTheUpstreamHttpMethodIs(string upstreamHttpMethod) | ||||
|         { | ||||
|             _upstreamHttpMethod = upstreamHttpMethod; | ||||
| @@ -122,10 +107,10 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder | ||||
|         private void ThenTheUrlMatcherIsCalledCorrectly() | ||||
|         { | ||||
|             _mockMatcher | ||||
|                 .Verify(x => x.Match(_upstreamUrlPath, _configuration.ReRoutes[0].UpstreamTemplate), Times.Once); | ||||
|                 .Verify(x => x.Match(_upstreamUrlPath, _reRoutesConfig[0].UpstreamTemplate), Times.Once); | ||||
|         } | ||||
|  | ||||
|         private void GivenTheUrlMatcherReturns(UrlMatch match) | ||||
|         private void GivenTheUrlMatcherReturns(Response<UrlMatch> match) | ||||
|         { | ||||
|             _match = match; | ||||
|             _mockMatcher | ||||
| @@ -133,12 +118,12 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder | ||||
|                 .Returns(_match); | ||||
|         } | ||||
|  | ||||
|         private void GivenTheConfigurationIs(Library.Infrastructure.Configuration.Configuration configuration) | ||||
|         private void GivenTheConfigurationIs(List<ReRoute> reRoutesConfig) | ||||
|         { | ||||
|             _configuration = configuration; | ||||
|             _reRoutesConfig = reRoutesConfig; | ||||
|             _mockConfig | ||||
|                 .Setup(x => x.Value) | ||||
|                 .Returns(_configuration); | ||||
|                 .Setup(x => x.ReRoutes) | ||||
|                 .Returns(_reRoutesConfig); | ||||
|         } | ||||
|  | ||||
|         private void GivenThereIsAnUpstreamUrlPath(string upstreamUrlPath) | ||||
|   | ||||
| @@ -6,6 +6,7 @@ using System.Net.Http; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Microsoft.AspNetCore.Http.Internal; | ||||
| using Ocelot.Library.Infrastructure.RequestBuilder; | ||||
| using Ocelot.Library.Infrastructure.Responses; | ||||
| using Shouldly; | ||||
| using TestStack.BDDfy; | ||||
| using Xunit; | ||||
| @@ -22,7 +23,7 @@ namespace Ocelot.UnitTests.RequestBuilder | ||||
|         private string _query; | ||||
|         private string _contentType; | ||||
|         private readonly IRequestBuilder _requestBuilder; | ||||
|         private Request _result; | ||||
|         private Response<Request> _result; | ||||
|  | ||||
|         public RequestBuilderTests() | ||||
|         { | ||||
| @@ -131,7 +132,7 @@ namespace Ocelot.UnitTests.RequestBuilder | ||||
|  | ||||
|         private void ThenTheCorrectQueryStringIsUsed(string expected) | ||||
|         { | ||||
|             _result.HttpRequestMessage.RequestUri.Query.ShouldBe(expected); | ||||
|             _result.Data.HttpRequestMessage.RequestUri.Query.ShouldBe(expected); | ||||
|         } | ||||
|  | ||||
|         private void GivenTheQueryStringIs(string query) | ||||
| @@ -141,7 +142,7 @@ namespace Ocelot.UnitTests.RequestBuilder | ||||
|  | ||||
|         private void ThenTheCorrectCookiesAreUsed(IRequestCookieCollection expected) | ||||
|         { | ||||
|             var resultCookies = _result.CookieContainer.GetCookies(new Uri(_downstreamUrl + _query)); | ||||
|             var resultCookies = _result.Data.CookieContainer.GetCookies(new Uri(_downstreamUrl + _query)); | ||||
|             var resultDictionary = resultCookies.Cast<Cookie>().ToDictionary(cook => cook.Name, cook => cook.Value); | ||||
|  | ||||
|             foreach (var expectedCookie in expected) | ||||
| @@ -162,7 +163,7 @@ namespace Ocelot.UnitTests.RequestBuilder | ||||
|  | ||||
|             foreach (var expectedHeader in expectedHeaders) | ||||
|             { | ||||
|                 _result.HttpRequestMessage.Headers.ShouldContain(x => x.Key == expectedHeader.Key && x.Value.First() == expectedHeader.Value[0]); | ||||
|                 _result.Data.HttpRequestMessage.Headers.ShouldContain(x => x.Key == expectedHeader.Key && x.Value.First() == expectedHeader.Value[0]); | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @@ -172,7 +173,7 @@ namespace Ocelot.UnitTests.RequestBuilder | ||||
|  | ||||
|             foreach (var expectedHeader in expectedHeaders) | ||||
|             { | ||||
|                 _result.HttpRequestMessage.Content.Headers.ShouldContain(x => x.Key == expectedHeader.Key  | ||||
|                 _result.Data.HttpRequestMessage.Content.Headers.ShouldContain(x => x.Key == expectedHeader.Key  | ||||
|                 && x.Value.First() == expectedHeader.Value[0] | ||||
|                 ); | ||||
|             } | ||||
| @@ -207,17 +208,17 @@ namespace Ocelot.UnitTests.RequestBuilder | ||||
|  | ||||
|         private void ThenTheCorrectDownstreamUrlIsUsed(string expected) | ||||
|         { | ||||
|             _result.HttpRequestMessage.RequestUri.AbsoluteUri.ShouldBe(expected); | ||||
|             _result.Data.HttpRequestMessage.RequestUri.AbsoluteUri.ShouldBe(expected); | ||||
|         } | ||||
|  | ||||
|         private void ThenTheCorrectHttpMethodIsUsed(HttpMethod expected) | ||||
|         { | ||||
|             _result.HttpRequestMessage.Method.Method.ShouldBe(expected.Method); | ||||
|             _result.Data.HttpRequestMessage.Method.Method.ShouldBe(expected.Method); | ||||
|         } | ||||
|  | ||||
|         private void ThenTheCorrectContentIsUsed(HttpContent expected) | ||||
|         { | ||||
|             _result.HttpRequestMessage.Content.ReadAsStringAsync().Result.ShouldBe(expected.ReadAsStringAsync().Result); | ||||
|             _result.Data.HttpRequestMessage.Content.ReadAsStringAsync().Result.ShouldBe(expected.ReadAsStringAsync().Result); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										156
									
								
								test/Ocelot.UnitTests/UrlMatcher/RegExUrlMatcherTests.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								test/Ocelot.UnitTests/UrlMatcher/RegExUrlMatcherTests.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,156 @@ | ||||
| using Ocelot.Library.Infrastructure.Responses; | ||||
| using Ocelot.Library.Infrastructure.UrlMatcher; | ||||
| using Shouldly; | ||||
| using TestStack.BDDfy; | ||||
| using Xunit; | ||||
|  | ||||
| namespace Ocelot.UnitTests.UrlMatcher | ||||
| { | ||||
|     public class RegExUrlMatcherTests | ||||
|     { | ||||
|         private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; | ||||
|         private string _downstreamUrlPath; | ||||
|         private string _downstreamPathTemplate; | ||||
|         private Response<UrlMatch> _result; | ||||
|  | ||||
|         public RegExUrlMatcherTests() | ||||
|         { | ||||
|             _urlMatcher = new RegExUrlMatcher(); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void should_find_match_when_template_smaller_than_valid_path() | ||||
|         { | ||||
|             this.Given(x => x.GivenIHaveAUpstreamPath("/api/products/2354325435624623464235")) | ||||
|                 .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("/api/products/.*$")) | ||||
|                 .When(x => x.WhenIMatchThePaths()) | ||||
|                 .And(x => x.ThenTheResultIsTrue()) | ||||
|                 .BDDfy(); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void should_not_find_match() | ||||
|         { | ||||
|             this.Given(x => x.GivenIHaveAUpstreamPath("/api/values")) | ||||
|                 .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("/$")) | ||||
|                 .When(x => x.WhenIMatchThePaths()) | ||||
|                 .And(x => x.ThenTheResultIsFalse()) | ||||
|                 .BDDfy(); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void can_match_down_stream_url() | ||||
|         { | ||||
|             this.Given(x => x.GivenIHaveAUpstreamPath("")) | ||||
|                 .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("$")) | ||||
|                 .When(x => x.WhenIMatchThePaths()) | ||||
|                 .And(x => x.ThenTheResultIsTrue()) | ||||
|                 .BDDfy(); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void can_match_down_stream_url_with_no_slash() | ||||
|         { | ||||
|             this.Given(x => x.GivenIHaveAUpstreamPath("api")) | ||||
|                  .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api$")) | ||||
|                  .When(x => x.WhenIMatchThePaths()) | ||||
|                  .Then(x => x.ThenTheResultIsTrue()) | ||||
|                  .BDDfy(); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void can_match_down_stream_url_with_one_slash() | ||||
|         { | ||||
|             this.Given(x => x.GivenIHaveAUpstreamPath("api/")) | ||||
|                  .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/$")) | ||||
|                  .When(x => x.WhenIMatchThePaths()) | ||||
|                  .Then(x => x.ThenTheResultIsTrue()) | ||||
|                  .BDDfy(); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void can_match_down_stream_url_with_downstream_template() | ||||
|         { | ||||
|             this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/")) | ||||
|               .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/$")) | ||||
|               .When(x => x.WhenIMatchThePaths()) | ||||
|               .Then(x => x.ThenTheResultIsTrue()) | ||||
|               .BDDfy(); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void can_match_down_stream_url_with_downstream_template_with_one_place_holder() | ||||
|         { | ||||
|             this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1")) | ||||
|                .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/.*$")) | ||||
|                .When(x => x.WhenIMatchThePaths()) | ||||
|                .Then(x => x.ThenTheResultIsTrue()) | ||||
|                .BDDfy(); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void can_match_down_stream_url_with_downstream_template_with_two_place_holders() | ||||
|         { | ||||
|             this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/2")) | ||||
|                  .Given(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/.*/.*$")) | ||||
|                  .When(x => x.WhenIMatchThePaths()) | ||||
|                  .Then(x => x.ThenTheResultIsTrue()) | ||||
|                  .BDDfy(); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void can_match_down_stream_url_with_downstream_template_with_two_place_holders_seperated_by_something() | ||||
|         { | ||||
|             this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2")) | ||||
|                 .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/.*/categories/.*$")) | ||||
|                 .When(x => x.WhenIMatchThePaths()) | ||||
|                 .Then(x => x.ThenTheResultIsTrue()) | ||||
|                 .BDDfy(); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void can_match_down_stream_url_with_downstream_template_with_three_place_holders_seperated_by_something() | ||||
|         { | ||||
|             this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/123")) | ||||
|                 .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/.*/categories/.*/variant/.*$")) | ||||
|                 .When(x => x.WhenIMatchThePaths()) | ||||
|                 .Then(x => x.ThenTheResultIsTrue()) | ||||
|                 .BDDfy(); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void can_match_down_stream_url_with_downstream_template_with_three_place_holders() | ||||
|         { | ||||
|             this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/")) | ||||
|                  .And(x => x.GivenIHaveAnUpstreamUrlTemplatePattern("api/product/products/.*/categories/.*/variant/$")) | ||||
|                  .When(x => x.WhenIMatchThePaths()) | ||||
|                  .Then(x => x.ThenTheResultIsTrue()) | ||||
|                  .BDDfy(); | ||||
|         } | ||||
|  | ||||
|         private void GivenIHaveAUpstreamPath(string downstreamPath) | ||||
|         { | ||||
|             _downstreamUrlPath = downstreamPath; | ||||
|         } | ||||
|  | ||||
|         private void GivenIHaveAnUpstreamUrlTemplatePattern(string downstreamUrlTemplate) | ||||
|         { | ||||
|             _downstreamPathTemplate = downstreamUrlTemplate; | ||||
|         } | ||||
|  | ||||
|         private void WhenIMatchThePaths() | ||||
|         { | ||||
|             _result = _urlMatcher.Match(_downstreamUrlPath, _downstreamPathTemplate); | ||||
|         } | ||||
|  | ||||
|         private void ThenTheResultIsTrue() | ||||
|         { | ||||
|             _result.Data.Match.ShouldBeTrue(); | ||||
|         } | ||||
|  | ||||
|         private void ThenTheResultIsFalse() | ||||
|         { | ||||
|             _result.Data.Match.ShouldBeFalse(); | ||||
|         } | ||||
|     } | ||||
| }  | ||||
| @@ -1,5 +1,6 @@ | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using Ocelot.Library.Infrastructure.Responses; | ||||
| using Ocelot.Library.Infrastructure.UrlMatcher; | ||||
| using Shouldly; | ||||
| using TestStack.BDDfy; | ||||
| @@ -9,33 +10,14 @@ namespace Ocelot.UnitTests.UrlMatcher | ||||
| { | ||||
|     public class UrlPathToUrlTemplateMatcherTests  | ||||
|     { | ||||
|         private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; | ||||
|         private readonly ITemplateVariableNameAndValueFinder _finder; | ||||
|         private string _downstreamUrlPath; | ||||
|         private string _downstreamPathTemplate; | ||||
|         private UrlMatch _result; | ||||
|         private Response<List<TemplateVariableNameAndValue>> _result; | ||||
| 
 | ||||
|         public UrlPathToUrlTemplateMatcherTests() | ||||
|         { | ||||
|             _urlMatcher = new UrlPathToUrlTemplateMatcher(); | ||||
|         } | ||||
| 
 | ||||
|         [Fact] | ||||
|         public void should_find_match_when_template_smaller_than_valid_path() | ||||
|         { | ||||
|             this.Given(x => x.GivenIHaveAUpstreamPath("/api/products/2354325435624623464235")) | ||||
|                 .And(x => x.GivenIHaveAnUpstreamUrlTemplate("/api/products/{productId}")) | ||||
|                 .When(x => x.WhenIMatchThePaths()) | ||||
|                 .And(x => x.ThenTheResultIsTrue()) | ||||
|                 .BDDfy(); | ||||
|         } | ||||
| 
 | ||||
|         [Fact] | ||||
|         public void should_not_find_match() | ||||
|         { | ||||
|             this.Given(x => x.GivenIHaveAUpstreamPath("/api/values")) | ||||
|                 .And(x => x.GivenIHaveAnUpstreamUrlTemplate("/")) | ||||
|                 .When(x => x.WhenIMatchThePaths()) | ||||
|                 .And(x => x.ThenTheResultIsFalse()) | ||||
|                 .BDDfy(); | ||||
|             _finder = new TemplateVariableNameAndValueFinder(); | ||||
|         } | ||||
| 
 | ||||
|         [Fact] | ||||
| @@ -43,10 +25,8 @@ namespace Ocelot.UnitTests.UrlMatcher | ||||
|         { | ||||
|             this.Given(x => x.GivenIHaveAUpstreamPath("")) | ||||
|                 .And(x => x.GivenIHaveAnUpstreamUrlTemplate("")) | ||||
|                 .When(x => x.WhenIMatchThePaths()) | ||||
|                 .And(x => x.ThenTheResultIsTrue()) | ||||
|                 .When(x => x.WhenIFindTheUrlVariableNamesAndValues()) | ||||
|                 .And(x => x.ThenTheTemplatesVariablesAre(new List<TemplateVariableNameAndValue>())) | ||||
|                 .And(x => x.ThenTheDownstreamUrlTemplateIs("")) | ||||
|                 .BDDfy(); | ||||
|         } | ||||
| 
 | ||||
| @@ -55,10 +35,8 @@ namespace Ocelot.UnitTests.UrlMatcher | ||||
|         { | ||||
|             this.Given(x => x.GivenIHaveAUpstreamPath("api")) | ||||
|                  .Given(x => x.GivenIHaveAnUpstreamUrlTemplate("api")) | ||||
|                  .When(x => x.WhenIMatchThePaths()) | ||||
|                  .Then(x => x.ThenTheResultIsTrue()) | ||||
|                  .When(x => x.WhenIFindTheUrlVariableNamesAndValues()) | ||||
|                  .And(x => x.ThenTheTemplatesVariablesAre(new List<TemplateVariableNameAndValue>())) | ||||
|                  .And(x => x.ThenTheDownstreamUrlTemplateIs("api")) | ||||
|                  .BDDfy(); | ||||
|         } | ||||
| 
 | ||||
| @@ -67,10 +45,8 @@ namespace Ocelot.UnitTests.UrlMatcher | ||||
|         { | ||||
|             this.Given(x => x.GivenIHaveAUpstreamPath("api/")) | ||||
|                  .Given(x => x.GivenIHaveAnUpstreamUrlTemplate("api/")) | ||||
|                  .When(x => x.WhenIMatchThePaths()) | ||||
|                  .Then(x => x.ThenTheResultIsTrue()) | ||||
|                  .When(x => x.WhenIFindTheUrlVariableNamesAndValues()) | ||||
|                  .And(x => x.ThenTheTemplatesVariablesAre(new List<TemplateVariableNameAndValue>())) | ||||
|                  .And(x => x.ThenTheDownstreamUrlTemplateIs("api/")) | ||||
|                  .BDDfy(); | ||||
|         } | ||||
| 
 | ||||
| @@ -79,10 +55,8 @@ namespace Ocelot.UnitTests.UrlMatcher | ||||
|         { | ||||
|             this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/")) | ||||
|               .Given(x => x.GivenIHaveAnUpstreamUrlTemplate("api/product/products/")) | ||||
|               .When(x => x.WhenIMatchThePaths()) | ||||
|               .Then(x => x.ThenTheResultIsTrue()) | ||||
|               .When(x => x.WhenIFindTheUrlVariableNamesAndValues()) | ||||
|               .And(x => x.ThenTheTemplatesVariablesAre(new List<TemplateVariableNameAndValue>())) | ||||
|               .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/")) | ||||
|               .BDDfy(); | ||||
|         } | ||||
| 
 | ||||
| @@ -96,10 +70,8 @@ namespace Ocelot.UnitTests.UrlMatcher | ||||
| 
 | ||||
|             this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1")) | ||||
|                .Given(x => x.GivenIHaveAnUpstreamUrlTemplate("api/product/products/{productId}")) | ||||
|                .When(x => x.WhenIMatchThePaths()) | ||||
|                .Then(x => x.ThenTheResultIsTrue()) | ||||
|                .When(x => x.WhenIFindTheUrlVariableNamesAndValues()) | ||||
|                .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) | ||||
|                .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}")) | ||||
|                .BDDfy(); | ||||
|         } | ||||
| 
 | ||||
| @@ -114,10 +86,8 @@ namespace Ocelot.UnitTests.UrlMatcher | ||||
| 
 | ||||
|             this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/2")) | ||||
|                  .Given(x => x.GivenIHaveAnUpstreamUrlTemplate("api/product/products/{productId}/{categoryId}")) | ||||
|                  .When(x => x.WhenIMatchThePaths()) | ||||
|                  .Then(x => x.ThenTheResultIsTrue()) | ||||
|                  .When(x => x.WhenIFindTheUrlVariableNamesAndValues()) | ||||
|                  .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) | ||||
|                  .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}/{categoryId}")) | ||||
|                  .BDDfy(); | ||||
|         } | ||||
| 
 | ||||
| @@ -132,10 +102,8 @@ namespace Ocelot.UnitTests.UrlMatcher | ||||
| 
 | ||||
|             this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2")) | ||||
|                 .And(x => x.GivenIHaveAnUpstreamUrlTemplate("api/product/products/{productId}/categories/{categoryId}")) | ||||
|                 .When(x => x.WhenIMatchThePaths()) | ||||
|                 .Then(x => x.ThenTheResultIsTrue()) | ||||
|                 .When(x => x.WhenIFindTheUrlVariableNamesAndValues()) | ||||
|                 .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) | ||||
|                 .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}/categories/{categoryId}")) | ||||
|                 .BDDfy(); | ||||
|         } | ||||
| 
 | ||||
| @@ -151,10 +119,8 @@ namespace Ocelot.UnitTests.UrlMatcher | ||||
| 
 | ||||
|             this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/123")) | ||||
|                 .And(x => x.GivenIHaveAnUpstreamUrlTemplate("api/product/products/{productId}/categories/{categoryId}/variant/{variantId}")) | ||||
|                 .When(x => x.WhenIMatchThePaths()) | ||||
|                 .Then(x => x.ThenTheResultIsTrue()) | ||||
|                 .When(x => x.WhenIFindTheUrlVariableNamesAndValues()) | ||||
|                 .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) | ||||
|                 .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}/categories/{categoryId}/variant/{variantId}")) | ||||
|                 .BDDfy(); | ||||
|         } | ||||
| 
 | ||||
| @@ -169,10 +135,8 @@ namespace Ocelot.UnitTests.UrlMatcher | ||||
| 
 | ||||
|             this.Given(x => x.GivenIHaveAUpstreamPath("api/product/products/1/categories/2/variant/")) | ||||
|                  .And(x => x.GivenIHaveAnUpstreamUrlTemplate("api/product/products/{productId}/categories/{categoryId}/variant/")) | ||||
|                  .When(x => x.WhenIMatchThePaths()) | ||||
|                  .Then(x => x.ThenTheResultIsTrue()) | ||||
|                  .When(x => x.WhenIFindTheUrlVariableNamesAndValues()) | ||||
|                  .And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates)) | ||||
|                  .And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}/categories/{categoryId}/variant/")) | ||||
|                  .BDDfy(); | ||||
|         } | ||||
| 
 | ||||
| @@ -180,16 +144,12 @@ namespace Ocelot.UnitTests.UrlMatcher | ||||
|         { | ||||
|             foreach (var expectedResult in expectedResults) | ||||
|             { | ||||
|                 var result = _result.TemplateVariableNameAndValues | ||||
|                 var result = _result.Data | ||||
|                     .First(t => t.TemplateVariableName == expectedResult.TemplateVariableName); | ||||
|                 result.TemplateVariableValue.ShouldBe(expectedResult.TemplateVariableValue); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private void ThenTheDownstreamUrlTemplateIs(string expectedDownstreamUrlTemplate) | ||||
|         { | ||||
|             _result.DownstreamUrlTemplate.ShouldBe(expectedDownstreamUrlTemplate); | ||||
|         } | ||||
|         private void GivenIHaveAUpstreamPath(string downstreamPath) | ||||
|         { | ||||
|             _downstreamUrlPath = downstreamPath; | ||||
| @@ -200,19 +160,9 @@ namespace Ocelot.UnitTests.UrlMatcher | ||||
|             _downstreamPathTemplate = downstreamUrlTemplate; | ||||
|         } | ||||
| 
 | ||||
|         private void WhenIMatchThePaths() | ||||
|         private void WhenIFindTheUrlVariableNamesAndValues() | ||||
|         { | ||||
|             _result = _urlMatcher.Match(_downstreamUrlPath, _downstreamPathTemplate); | ||||
|         } | ||||
| 
 | ||||
|         private void ThenTheResultIsTrue() | ||||
|         { | ||||
|             _result.Match.ShouldBeTrue(); | ||||
|         } | ||||
| 
 | ||||
|         private void ThenTheResultIsFalse() | ||||
|         { | ||||
|             _result.Match.ShouldBeFalse(); | ||||
|             _result = _finder.Find(_downstreamUrlPath, _downstreamPathTemplate); | ||||
|         } | ||||
|     } | ||||
| }  | ||||
| @@ -1,5 +1,6 @@ | ||||
| using System.Collections.Generic; | ||||
| using Ocelot.Library.Infrastructure.DownstreamRouteFinder; | ||||
| using Ocelot.Library.Infrastructure.Responses; | ||||
| using Ocelot.Library.Infrastructure.UrlMatcher; | ||||
| using Ocelot.Library.Infrastructure.UrlTemplateReplacer; | ||||
| using Shouldly; | ||||
| @@ -11,7 +12,7 @@ namespace Ocelot.UnitTests.UrlTemplateReplacer | ||||
|     public class UpstreamUrlPathTemplateVariableReplacerTests | ||||
|     { | ||||
|         private DownstreamRoute _downstreamRoute; | ||||
|         private string _result; | ||||
|         private Response<string> _result; | ||||
|         private readonly IDownstreamUrlTemplateVariableReplacer _downstreamUrlPathReplacer; | ||||
|  | ||||
|         public UpstreamUrlPathTemplateVariableReplacerTests() | ||||
| @@ -135,7 +136,7 @@ namespace Ocelot.UnitTests.UrlTemplateReplacer | ||||
|  | ||||
|         private void ThenTheDownstreamUrlPathIsReturned(string expected) | ||||
|         { | ||||
|             _result.ShouldBe(expected); | ||||
|             _result.Data.ShouldBe(expected); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 TomPallister
					TomPallister