mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-04-22 06:22:50 +08:00
Merge pull request #12 from TomPallister/feature/simplify
Feature/simplify
This commit is contained in:
commit
4fdd694003
@ -0,0 +1,14 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ocelot.Library.Infrastructure.Configuration
|
||||||
|
{
|
||||||
|
public class Configuration
|
||||||
|
{
|
||||||
|
public Configuration()
|
||||||
|
{
|
||||||
|
ReRoutes = new List<ReRoute>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ReRoute> ReRoutes { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
namespace Ocelot.Library.Infrastructure.Configuration
|
||||||
|
{
|
||||||
|
public class ReRoute
|
||||||
|
{
|
||||||
|
public string DownstreamTemplate { get; set; }
|
||||||
|
public string UpstreamTemplate { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Ocelot.Library.Infrastructure.UrlMatcher;
|
||||||
|
|
||||||
|
namespace Ocelot.Library.Infrastructure.DownstreamRouteFinder
|
||||||
|
{
|
||||||
|
public class DownstreamRoute
|
||||||
|
{
|
||||||
|
public DownstreamRoute(List<TemplateVariableNameAndValue> templateVariableNameAndValues, string downstreamUrlTemplate)
|
||||||
|
{
|
||||||
|
TemplateVariableNameAndValues = templateVariableNameAndValues;
|
||||||
|
DownstreamUrlTemplate = downstreamUrlTemplate;
|
||||||
|
}
|
||||||
|
public List<TemplateVariableNameAndValue> TemplateVariableNameAndValues { get; private set; }
|
||||||
|
public string DownstreamUrlTemplate { get; private set; }
|
||||||
|
}
|
||||||
|
}
|
@ -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.Configuration> _configuration;
|
||||||
|
private readonly IUrlPathToUrlTemplateMatcher _urlMatcher;
|
||||||
|
|
||||||
|
public DownstreamRouteFinder(IOptions<Configuration.Configuration> configuration, IUrlPathToUrlTemplateMatcher urlMatcher)
|
||||||
|
{
|
||||||
|
_configuration = configuration;
|
||||||
|
_urlMatcher = urlMatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Response<DownstreamRoute> FindDownstreamRoute(string upstreamUrlPath)
|
||||||
|
{
|
||||||
|
|
||||||
|
foreach (var template in _configuration.Value.ReRoutes)
|
||||||
|
{
|
||||||
|
var urlMatch = _urlMatcher.Match(upstreamUrlPath, template.UpstreamTemplate);
|
||||||
|
|
||||||
|
if (urlMatch.Match)
|
||||||
|
{
|
||||||
|
return new OkResponse<DownstreamRoute>(new DownstreamRoute(urlMatch.TemplateVariableNameAndValues, template.DownstreamTemplate));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ErrorResponse<DownstreamRoute>(new List<Error>
|
||||||
|
{
|
||||||
|
new UnableToFindDownstreamRouteError()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
using Ocelot.Library.Infrastructure.Responses;
|
||||||
|
|
||||||
|
namespace Ocelot.Library.Infrastructure.DownstreamRouteFinder
|
||||||
|
{
|
||||||
|
public interface IDownstreamRouteFinder
|
||||||
|
{
|
||||||
|
Response<DownstreamRoute> FindDownstreamRoute(string upstreamUrlPath);
|
||||||
|
}
|
||||||
|
}
|
@ -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")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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;}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
using Ocelot.Library.Infrastructure.Responses;
|
|
||||||
|
|
||||||
namespace Ocelot.Library.Infrastructure.HostUrlRepository
|
|
||||||
{
|
|
||||||
public interface IHostUrlMapRepository
|
|
||||||
{
|
|
||||||
Response AddBaseUrlMap(HostUrlMap baseUrlMap);
|
|
||||||
Response<HostUrlMap> GetBaseUrlMap(string urlPathTemplate);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<string, string> _routes;
|
|
||||||
public InMemoryHostUrlMapRepository()
|
|
||||||
{
|
|
||||||
_routes = new Dictionary<string,string>();
|
|
||||||
}
|
|
||||||
public Response AddBaseUrlMap(HostUrlMap baseUrlMap)
|
|
||||||
{
|
|
||||||
if(_routes.ContainsKey(baseUrlMap.UrlPathTemplate))
|
|
||||||
{
|
|
||||||
return new ErrorResponse(new List<Error>(){new HostUrlMapKeyAlreadyExists()});
|
|
||||||
}
|
|
||||||
|
|
||||||
_routes.Add(baseUrlMap.UrlPathTemplate, baseUrlMap.UpstreamHostUrl);
|
|
||||||
|
|
||||||
return new OkResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Response<HostUrlMap> GetBaseUrlMap(string urlPathTemplate)
|
|
||||||
{
|
|
||||||
string upstreamUrl = null;
|
|
||||||
|
|
||||||
if(_routes.TryGetValue(urlPathTemplate, out upstreamUrl))
|
|
||||||
{
|
|
||||||
return new OkResponse<HostUrlMap>(new HostUrlMap(urlPathTemplate, upstreamUrl));
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ErrorResponse<HostUrlMap>(new List<Error>(){new HostUrlMapKeyDoesNotExist()});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
using Ocelot.Library.Infrastructure.Responses;
|
|
||||||
|
|
||||||
namespace Ocelot.Library.Infrastructure.UrlFinder
|
|
||||||
{
|
|
||||||
public interface IUpstreamHostUrlFinder
|
|
||||||
{
|
|
||||||
Response<string> FindUpstreamHostUrl(string downstreamHostUrl);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<string> FindUpstreamHostUrl(string downstreamBaseUrl)
|
|
||||||
{
|
|
||||||
var baseUrl = _hostUrlMapRepository.GetBaseUrlMap(downstreamBaseUrl);
|
|
||||||
|
|
||||||
if(baseUrl.IsError)
|
|
||||||
{
|
|
||||||
return new ErrorResponse<string>(new List<Error> {new UnableToFindUpstreamHostUrl()});
|
|
||||||
}
|
|
||||||
|
|
||||||
return new OkResponse<string>(baseUrl.Data.UpstreamHostUrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,7 @@
|
|||||||
|
namespace Ocelot.Library.Infrastructure.UrlMatcher
|
||||||
|
{
|
||||||
|
public interface IUrlPathToUrlTemplateMatcher
|
||||||
|
{
|
||||||
|
UrlMatch Match(string upstreamUrlPath, string upstreamUrlTemplate);
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
namespace Ocelot.Library.Infrastructure.UrlPathMatcher
|
namespace Ocelot.Library.Infrastructure.UrlMatcher
|
||||||
{
|
{
|
||||||
public class TemplateVariableNameAndValue
|
public class TemplateVariableNameAndValue
|
||||||
{
|
{
|
17
src/Ocelot.Library/Infrastructure/UrlMatcher/UrlMatch.cs
Normal file
17
src/Ocelot.Library/Infrastructure/UrlMatcher/UrlMatch.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ocelot.Library.Infrastructure.UrlMatcher
|
||||||
|
{
|
||||||
|
public class UrlMatch
|
||||||
|
{
|
||||||
|
public UrlMatch(bool match, List<TemplateVariableNameAndValue> templateVariableNameAndValues, string downstreamUrlTemplate)
|
||||||
|
{
|
||||||
|
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,46 +1,46 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
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 upstreamUrlPath, string upstreamUrlTemplate)
|
||||||
{
|
{
|
||||||
var urlPathTemplateCopy = downstreamUrlPathTemplate;
|
var urlPathTemplateCopy = upstreamUrlTemplate;
|
||||||
|
|
||||||
var templateKeysAndValues = new List<TemplateVariableNameAndValue>();
|
var templateKeysAndValues = new List<TemplateVariableNameAndValue>();
|
||||||
|
|
||||||
int counterForUrl = 0;
|
int counterForUrl = 0;
|
||||||
|
|
||||||
for (int counterForTemplate = 0; counterForTemplate < downstreamUrlPathTemplate.Length; counterForTemplate++)
|
for (int counterForTemplate = 0; counterForTemplate < upstreamUrlTemplate.Length; counterForTemplate++)
|
||||||
{
|
{
|
||||||
if (CharactersDontMatch(downstreamUrlPathTemplate[counterForTemplate], downstreamUrlPath[counterForUrl]) && ContinueScanningUrl(counterForUrl,downstreamUrlPath.Length))
|
if (CharactersDontMatch(upstreamUrlTemplate[counterForTemplate], upstreamUrlPath[counterForUrl]) && ContinueScanningUrl(counterForUrl,upstreamUrlPath.Length))
|
||||||
{
|
{
|
||||||
if (IsPlaceholder(downstreamUrlPathTemplate[counterForTemplate]))
|
if (IsPlaceholder(upstreamUrlTemplate[counterForTemplate]))
|
||||||
{
|
{
|
||||||
var variableName = GetPlaceholderVariableName(downstreamUrlPathTemplate, counterForTemplate);
|
var variableName = GetPlaceholderVariableName(upstreamUrlTemplate, counterForTemplate);
|
||||||
|
|
||||||
var variableValue = GetPlaceholderVariableValue(downstreamUrlPath, counterForUrl);
|
var variableValue = GetPlaceholderVariableValue(upstreamUrlPath, counterForUrl);
|
||||||
|
|
||||||
var templateVariableNameAndValue = new TemplateVariableNameAndValue(variableName, variableValue);
|
var templateVariableNameAndValue = new TemplateVariableNameAndValue(variableName, variableValue);
|
||||||
|
|
||||||
templateKeysAndValues.Add(templateVariableNameAndValue);
|
templateKeysAndValues.Add(templateVariableNameAndValue);
|
||||||
|
|
||||||
counterForTemplate = GetNextCounterPosition(downstreamUrlPathTemplate, counterForTemplate, '}');
|
counterForTemplate = GetNextCounterPosition(upstreamUrlTemplate, counterForTemplate, '}');
|
||||||
|
|
||||||
counterForUrl = GetNextCounterPosition(downstreamUrlPath, counterForUrl, '/');
|
counterForUrl = GetNextCounterPosition(upstreamUrlPath, counterForUrl, '/');
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return new UrlPathMatch(false, templateKeysAndValues, string.Empty);
|
return new UrlMatch(false, templateKeysAndValues, string.Empty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
counterForUrl++;
|
counterForUrl++;
|
||||||
}
|
}
|
||||||
return new UrlPathMatch(true, templateKeysAndValues, urlPathTemplateCopy);
|
return new UrlMatch(true, templateKeysAndValues, urlPathTemplateCopy);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetPlaceholderVariableValue(string urlPath, int counterForUrl)
|
private string GetPlaceholderVariableValue(string urlPath, int counterForUrl)
|
@ -1,7 +0,0 @@
|
|||||||
namespace Ocelot.Library.Infrastructure.UrlPathMatcher
|
|
||||||
{
|
|
||||||
public interface IUrlPathToUrlPathTemplateMatcher
|
|
||||||
{
|
|
||||||
UrlPathMatch Match(string downstreamUrlPath, string downStreamUrlPathTemplate);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Ocelot.Library.Infrastructure.UrlPathMatcher
|
|
||||||
{
|
|
||||||
public class UrlPathMatch
|
|
||||||
{
|
|
||||||
public UrlPathMatch(bool match, List<TemplateVariableNameAndValue> templateVariableNameAndValues, string downstreamUrlPathTemplate)
|
|
||||||
{
|
|
||||||
Match = match;
|
|
||||||
TemplateVariableNameAndValues = templateVariableNameAndValues;
|
|
||||||
DownstreamUrlPathTemplate = downstreamUrlPathTemplate;
|
|
||||||
}
|
|
||||||
public bool Match {get;private set;}
|
|
||||||
public List<TemplateVariableNameAndValue> TemplateVariableNameAndValues {get;private set;}
|
|
||||||
public string DownstreamUrlPathTemplate {get;private set;}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
using Ocelot.Library.Infrastructure.UrlPathMatcher;
|
|
||||||
|
|
||||||
namespace Ocelot.Library.Infrastructure.UrlPathReplacer
|
|
||||||
{
|
|
||||||
public interface IUpstreamUrlPathTemplateVariableReplacer
|
|
||||||
{
|
|
||||||
string ReplaceTemplateVariable(string upstreamPathTemplate, UrlPathMatch urlPathMatch);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<UrlPathTemplateMap> GetUrlPathTemplateMap(string downstreamUrlPathTemplate);
|
|
||||||
Response<List<UrlPathTemplateMap>> All { get; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<string, string> _routes;
|
|
||||||
public InMemoryUrlPathTemplateMapRepository()
|
|
||||||
{
|
|
||||||
_routes = new Dictionary<string,string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Response<List<UrlPathTemplateMap>> All
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var routes = _routes
|
|
||||||
.Select(r => new UrlPathTemplateMap(r.Key, r.Value))
|
|
||||||
.ToList();
|
|
||||||
return new OkResponse<List<UrlPathTemplateMap>>(routes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Response AddUrlPathTemplateMap(UrlPathTemplateMap urlPathMap)
|
|
||||||
{
|
|
||||||
if(_routes.ContainsKey(urlPathMap.DownstreamUrlPathTemplate))
|
|
||||||
{
|
|
||||||
return new ErrorResponse(new List<Error>(){new DownstreamUrlPathTemplateAlreadyExists()});
|
|
||||||
}
|
|
||||||
|
|
||||||
_routes.Add(urlPathMap.DownstreamUrlPathTemplate, urlPathMap.UpstreamUrlPathTemplate);
|
|
||||||
|
|
||||||
return new OkResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Response<UrlPathTemplateMap> GetUrlPathTemplateMap(string downstreamUrlPathTemplate)
|
|
||||||
{
|
|
||||||
string upstreamUrlPathTemplate = null;
|
|
||||||
|
|
||||||
if(_routes.TryGetValue(downstreamUrlPathTemplate, out upstreamUrlPathTemplate))
|
|
||||||
{
|
|
||||||
return new OkResponse<UrlPathTemplateMap>(new UrlPathTemplateMap(downstreamUrlPathTemplate, upstreamUrlPathTemplate));
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ErrorResponse<UrlPathTemplateMap>(new List<Error>(){new DownstreamUrlPathTemplateDoesNotExist()});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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;}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,22 @@
|
|||||||
|
using System.Text;
|
||||||
|
using Ocelot.Library.Infrastructure.DownstreamRouteFinder;
|
||||||
|
|
||||||
|
namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer
|
||||||
|
{
|
||||||
|
public class DownstreamUrlTemplateVariableReplacer : IDownstreamUrlTemplateVariableReplacer
|
||||||
|
{
|
||||||
|
public string ReplaceTemplateVariable(DownstreamRoute downstreamRoute)
|
||||||
|
{
|
||||||
|
var upstreamUrl = new StringBuilder();
|
||||||
|
|
||||||
|
upstreamUrl.Append(downstreamRoute.DownstreamUrlTemplate);
|
||||||
|
|
||||||
|
foreach (var templateVarAndValue in downstreamRoute.TemplateVariableNameAndValues)
|
||||||
|
{
|
||||||
|
upstreamUrl.Replace(templateVarAndValue.TemplateVariableName, templateVarAndValue.TemplateVariableValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return upstreamUrl.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
using Ocelot.Library.Infrastructure.DownstreamRouteFinder;
|
||||||
|
using Ocelot.Library.Infrastructure.UrlMatcher;
|
||||||
|
|
||||||
|
namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer
|
||||||
|
{
|
||||||
|
public interface IDownstreamUrlTemplateVariableReplacer
|
||||||
|
{
|
||||||
|
string ReplaceTemplateVariable(DownstreamRoute downstreamRoute);
|
||||||
|
}
|
||||||
|
}
|
@ -1,67 +1,62 @@
|
|||||||
using System;
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Ocelot.Library.Infrastructure.HostUrlRepository;
|
using Microsoft.Extensions.Options;
|
||||||
using Ocelot.Library.Infrastructure.UrlPathMatcher;
|
using Ocelot.Library.Infrastructure.Configuration;
|
||||||
using Ocelot.Library.Infrastructure.UrlPathReplacer;
|
using Ocelot.Library.Infrastructure.DownstreamRouteFinder;
|
||||||
using Ocelot.Library.Infrastructure.UrlPathTemplateRepository;
|
using Ocelot.Library.Infrastructure.UrlTemplateReplacer;
|
||||||
|
|
||||||
namespace Ocelot.Library.Middleware
|
namespace Ocelot.Library.Middleware
|
||||||
{
|
{
|
||||||
using System.Net;
|
|
||||||
|
|
||||||
public class ProxyMiddleware
|
public class ProxyMiddleware
|
||||||
{
|
{
|
||||||
private readonly RequestDelegate _next;
|
private readonly RequestDelegate _next;
|
||||||
private readonly IUrlPathToUrlPathTemplateMatcher _urlMatcher;
|
private readonly IDownstreamUrlTemplateVariableReplacer _urlReplacer;
|
||||||
private readonly IUrlPathTemplateMapRepository _urlPathRepository;
|
private readonly IOptions<Configuration> _configuration;
|
||||||
private readonly IHostUrlMapRepository _hostUrlRepository;
|
private readonly IDownstreamRouteFinder _downstreamRouteFinder;
|
||||||
private readonly IUpstreamUrlPathTemplateVariableReplacer _urlReplacer;
|
|
||||||
public ProxyMiddleware(RequestDelegate next,
|
public ProxyMiddleware(RequestDelegate next,
|
||||||
IUrlPathToUrlPathTemplateMatcher urlMatcher,
|
IDownstreamUrlTemplateVariableReplacer urlReplacer,
|
||||||
IUrlPathTemplateMapRepository urlPathRepository,
|
IOptions<Configuration> configuration,
|
||||||
IHostUrlMapRepository hostUrlRepository,
|
IDownstreamRouteFinder downstreamRouteFinder)
|
||||||
IUpstreamUrlPathTemplateVariableReplacer urlReplacer)
|
|
||||||
{
|
{
|
||||||
_next = next;
|
_next = next;
|
||||||
_urlMatcher = urlMatcher;
|
|
||||||
_urlPathRepository = urlPathRepository;
|
|
||||||
_hostUrlRepository = hostUrlRepository;
|
|
||||||
_urlReplacer = urlReplacer;
|
_urlReplacer = urlReplacer;
|
||||||
|
_configuration = configuration;
|
||||||
|
_downstreamRouteFinder = downstreamRouteFinder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Invoke(HttpContext context)
|
public async Task Invoke(HttpContext context)
|
||||||
{
|
{
|
||||||
|
var upstreamUrlPath = context.Request.Path.ToString();
|
||||||
|
|
||||||
var path = context.Request.Path.ToString();
|
var downstreamRoute = _downstreamRouteFinder.FindDownstreamRoute(upstreamUrlPath);
|
||||||
|
|
||||||
var urlPathTemplateMaps = _urlPathRepository.All;
|
if (downstreamRoute.IsError)
|
||||||
|
|
||||||
UrlPathMatch urlPathMatch = null;
|
|
||||||
string upstreamPathUrlTemplate = string.Empty;
|
|
||||||
|
|
||||||
foreach (var template in urlPathTemplateMaps.Data)
|
|
||||||
{
|
|
||||||
urlPathMatch = _urlMatcher.Match(path, template.DownstreamUrlPathTemplate);
|
|
||||||
|
|
||||||
if (urlPathMatch.Match)
|
|
||||||
{
|
|
||||||
upstreamPathUrlTemplate = template.UpstreamUrlPathTemplate;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (urlPathMatch == null || !urlPathMatch.Match)
|
|
||||||
{
|
{
|
||||||
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
|
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var upstreamHostUrl = _hostUrlRepository.GetBaseUrlMap(urlPathMatch.DownstreamUrlPathTemplate);
|
var downstreamUrl = _urlReplacer.ReplaceTemplateVariable(downstreamRoute.Data);
|
||||||
|
|
||||||
var pathUrl = _urlReplacer.ReplaceTemplateVariable(upstreamPathUrlTemplate, urlPathMatch);
|
|
||||||
|
|
||||||
//make a http request to this endpoint...maybe bring in a library
|
//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);
|
await _next.Invoke(context);
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
"Microsoft.Extensions.Logging.Console": "1.0.0",
|
"Microsoft.Extensions.Logging.Console": "1.0.0",
|
||||||
"Microsoft.Extensions.Logging.Debug": "1.0.0",
|
"Microsoft.Extensions.Logging.Debug": "1.0.0",
|
||||||
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",
|
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",
|
||||||
"Microsoft.AspNetCore.Http": "1.0.0"
|
"Microsoft.AspNetCore.Http": "1.0.0",
|
||||||
|
"YamlDotNet": "3.9.0"
|
||||||
},
|
},
|
||||||
|
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
|
@ -1,17 +1,16 @@
|
|||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Ocelot.Library.Infrastructure.DownstreamRouteFinder;
|
||||||
using Ocelot.Library.Middleware;
|
using Ocelot.Library.Middleware;
|
||||||
|
|
||||||
namespace Ocelot
|
namespace Ocelot
|
||||||
{
|
{
|
||||||
using Library.Infrastructure.HostUrlRepository;
|
using Library.Infrastructure.Configuration;
|
||||||
using Library.Infrastructure.UrlPathMatcher;
|
using Library.Infrastructure.UrlMatcher;
|
||||||
using Library.Infrastructure.UrlPathReplacer;
|
using Library.Infrastructure.UrlTemplateReplacer;
|
||||||
using Library.Infrastructure.UrlPathTemplateRepository;
|
|
||||||
|
|
||||||
public class Startup
|
public class Startup
|
||||||
{
|
{
|
||||||
@ -21,6 +20,7 @@ namespace Ocelot
|
|||||||
.SetBasePath(env.ContentRootPath)
|
.SetBasePath(env.ContentRootPath)
|
||||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
||||||
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
|
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
|
||||||
|
.AddYamlFile("configuration.yaml")
|
||||||
.AddEnvironmentVariables();
|
.AddEnvironmentVariables();
|
||||||
Configuration = builder.Build();
|
Configuration = builder.Build();
|
||||||
}
|
}
|
||||||
@ -30,12 +30,14 @@ namespace Ocelot
|
|||||||
// This method gets called by the runtime. Use this method to add services to the container.
|
// This method gets called by the runtime. Use this method to add services to the container.
|
||||||
public void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
|
services.AddOptions();
|
||||||
|
|
||||||
|
services.Configure<Configuration>(Configuration);
|
||||||
|
|
||||||
// Add framework services.
|
// Add framework services.
|
||||||
services.AddSingleton<IHostUrlMapRepository, InMemoryHostUrlMapRepository>();
|
services.AddSingleton<IUrlPathToUrlTemplateMatcher, UrlPathToUrlTemplateMatcher>();
|
||||||
services.AddSingleton<IUrlPathToUrlPathTemplateMatcher, UrlPathToUrlPathTemplateMatcher>();
|
services.AddSingleton<IDownstreamUrlTemplateVariableReplacer, DownstreamUrlTemplateVariableReplacer>();
|
||||||
services.AddSingleton<IHostUrlMapRepository, InMemoryHostUrlMapRepository>();
|
services.AddSingleton<IDownstreamRouteFinder, DownstreamRouteFinder>();
|
||||||
services.AddSingleton<IUpstreamUrlPathTemplateVariableReplacer, UpstreamUrlPathTemplateVariableReplacer>();
|
|
||||||
services.AddSingleton<IUrlPathTemplateMapRepository, InMemoryUrlPathTemplateMapRepository>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
|
@ -15,7 +15,8 @@
|
|||||||
"Microsoft.Extensions.Logging.Console": "1.0.0",
|
"Microsoft.Extensions.Logging.Console": "1.0.0",
|
||||||
"Microsoft.Extensions.Logging.Debug": "1.0.0",
|
"Microsoft.Extensions.Logging.Debug": "1.0.0",
|
||||||
"Microsoft.Extensions.Options.ConfigurationExtensions": "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": {
|
"tools": {
|
||||||
|
113
test/Ocelot.AcceptanceTests/OcelotTests.cs
Normal file
113
test/Ocelot.AcceptanceTests/OcelotTests.cs
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
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 TestServer _server;
|
||||||
|
private HttpClient _client;
|
||||||
|
private HttpResponseMessage _response;
|
||||||
|
|
||||||
|
public OcelotTests()
|
||||||
|
{
|
||||||
|
_fakeService = new FakeService();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_return_response_404()
|
||||||
|
{
|
||||||
|
this.Given(x => x.GivenTheApiGatewayIsRunning())
|
||||||
|
.When(x => x.WhenIRequestTheUrlOnTheApiGateway("/"))
|
||||||
|
.Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_return_response_200()
|
||||||
|
{
|
||||||
|
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879"))
|
||||||
|
.And(x => x.GivenThereIsAConfiguration(new Configuration
|
||||||
|
{
|
||||||
|
ReRoutes = new List<ReRoute>
|
||||||
|
{
|
||||||
|
new ReRoute
|
||||||
|
{
|
||||||
|
DownstreamTemplate = "http://localhost:51879/",
|
||||||
|
UpstreamTemplate = "/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.And(x => x.GivenTheApiGatewayIsRunning())
|
||||||
|
.When(x => x.WhenIRequestTheUrlOnTheApiGateway("/"))
|
||||||
|
.Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
||||||
|
.And(x => x.ThenTheResponseBodyShouldBe("Hello from Laura"))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
private void GivenTheApiGatewayIsRunning()
|
||||||
|
{
|
||||||
|
_server = new TestServer(new WebHostBuilder()
|
||||||
|
.UseStartup<Startup>());
|
||||||
|
|
||||||
|
_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(url).Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode)
|
||||||
|
{
|
||||||
|
_response.StatusCode.ShouldBe(expectedHttpStatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenTheResponseBodyShouldBe(string expectedBody)
|
||||||
|
{
|
||||||
|
_response.Content.ReadAsStringAsync().Result.ShouldBe(expectedBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_fakeService.Stop();
|
||||||
|
_client.Dispose();
|
||||||
|
_server.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,56 +0,0 @@
|
|||||||
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.Net;
|
|
||||||
using TestStack.BDDfy;
|
|
||||||
|
|
||||||
public class RouterTests : IDisposable
|
|
||||||
{
|
|
||||||
private readonly FakeService _fakeService;
|
|
||||||
private readonly TestServer _server;
|
|
||||||
private readonly HttpClient _client;
|
|
||||||
private HttpResponseMessage _response;
|
|
||||||
|
|
||||||
public RouterTests()
|
|
||||||
{
|
|
||||||
_server = new TestServer(new WebHostBuilder()
|
|
||||||
.UseStartup<Startup>());
|
|
||||||
|
|
||||||
_client = _server.CreateClient();
|
|
||||||
|
|
||||||
_fakeService = new FakeService();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void should_return_response_404()
|
|
||||||
{
|
|
||||||
this.When(x => x.WhenIRequestTheUrl("/"))
|
|
||||||
.Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound))
|
|
||||||
.BDDfy();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WhenIRequestTheUrl(string url)
|
|
||||||
{
|
|
||||||
_response = _client.GetAsync("/").Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode)
|
|
||||||
{
|
|
||||||
_response.StatusCode.ShouldBe(expectedHttpStatusCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_fakeService.Stop();
|
|
||||||
_client.Dispose();
|
|
||||||
_server.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
3
test/Ocelot.AcceptanceTests/configuration.yaml
Normal file
3
test/Ocelot.AcceptanceTests/configuration.yaml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
ReRoutes:
|
||||||
|
- DownstreamTemplate: http://localhost:51879/
|
||||||
|
UpstreamTemplate: /
|
@ -1,6 +1,14 @@
|
|||||||
{
|
{
|
||||||
"version": "1.0.0-*",
|
"version": "1.0.0-*",
|
||||||
|
|
||||||
|
"buildOptions": {
|
||||||
|
"copyToOutput": {
|
||||||
|
"include": [
|
||||||
|
"configuration.yaml"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
"testRunner": "xunit",
|
"testRunner": "xunit",
|
||||||
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -25,7 +33,8 @@
|
|||||||
"Shouldly": "2.8.0",
|
"Shouldly": "2.8.0",
|
||||||
"Ocelot": "1.0.0-*",
|
"Ocelot": "1.0.0-*",
|
||||||
"Microsoft.AspNetCore.TestHost": "1.0.0",
|
"Microsoft.AspNetCore.TestHost": "1.0.0",
|
||||||
"TestStack.BDDfy": "4.3.1"
|
"TestStack.BDDfy": "4.3.1",
|
||||||
|
"YamlDotNet": "3.9.0"
|
||||||
},
|
},
|
||||||
|
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
|
132
test/Ocelot.UnitTests/DownstreamRouteFinderTests.cs
Normal file
132
test/Ocelot.UnitTests/DownstreamRouteFinderTests.cs
Normal file
@ -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<IOptions<Configuration>> _mockConfig;
|
||||||
|
private readonly Mock<IUrlPathToUrlTemplateMatcher> _mockMatcher;
|
||||||
|
private string _upstreamUrlPath;
|
||||||
|
private Response<DownstreamRoute> _result;
|
||||||
|
private Response<DownstreamRoute> _response;
|
||||||
|
private Configuration _configuration;
|
||||||
|
private UrlMatch _match;
|
||||||
|
|
||||||
|
public DownstreamRouteFinderTests()
|
||||||
|
{
|
||||||
|
_mockConfig = new Mock<IOptions<Configuration>>();
|
||||||
|
_mockMatcher = new Mock<IUrlPathToUrlTemplateMatcher>();
|
||||||
|
_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<ReRoute>
|
||||||
|
{
|
||||||
|
new ReRoute()
|
||||||
|
{
|
||||||
|
UpstreamTemplate = "somePath",
|
||||||
|
DownstreamTemplate = "somPath"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.And(x => x.GivenTheUrlMatcherReturns(new UrlMatch(true, new List<TemplateVariableNameAndValue>(), "somePath")))
|
||||||
|
.When(x => x.WhenICallTheFinder())
|
||||||
|
.Then(
|
||||||
|
x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List<TemplateVariableNameAndValue>(), "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<ReRoute>
|
||||||
|
{
|
||||||
|
new ReRoute()
|
||||||
|
{
|
||||||
|
UpstreamTemplate = "somePath",
|
||||||
|
DownstreamTemplate = "somPath"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.And(x => x.GivenTheUrlMatcherReturns(new UrlMatch(false, new List<TemplateVariableNameAndValue>(), 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<string>(), It.IsAny<string>()))
|
||||||
|
.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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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<HostUrlMap> _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<ErrorResponse>();
|
|
||||||
_response.Errors[0].Message.ShouldBe("This key has already been used");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ThenTheKeyDoesNotExist()
|
|
||||||
{
|
|
||||||
_getRouteResponse.ShouldNotBeNull();
|
|
||||||
_getRouteResponse.ShouldBeOfType<ErrorResponse<HostUrlMap>>();
|
|
||||||
_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<OkResponse>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<string> _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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Ocelot.Library.Infrastructure.UrlPathMatcher;
|
using Ocelot.Library.Infrastructure.DownstreamRouteFinder;
|
||||||
using Ocelot.Library.Infrastructure.UrlPathReplacer;
|
using Ocelot.Library.Infrastructure.UrlMatcher;
|
||||||
|
using Ocelot.Library.Infrastructure.UrlTemplateReplacer;
|
||||||
using Shouldly;
|
using Shouldly;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
@ -10,53 +11,57 @@ namespace Ocelot.UnitTests
|
|||||||
|
|
||||||
public class UpstreamUrlPathTemplateVariableReplacerTests
|
public class UpstreamUrlPathTemplateVariableReplacerTests
|
||||||
{
|
{
|
||||||
private string _upstreamUrlPath;
|
private DownstreamRoute _downstreamRoute;
|
||||||
private UrlPathMatch _urlPathMatch;
|
|
||||||
private string _result;
|
private string _result;
|
||||||
private readonly IUpstreamUrlPathTemplateVariableReplacer _upstreamUrlPathReplacer;
|
private readonly IDownstreamUrlTemplateVariableReplacer _downstreamUrlPathReplacer;
|
||||||
|
|
||||||
public UpstreamUrlPathTemplateVariableReplacerTests()
|
public UpstreamUrlPathTemplateVariableReplacerTests()
|
||||||
{
|
{
|
||||||
_upstreamUrlPathReplacer = new UpstreamUrlPathTemplateVariableReplacer();
|
_downstreamUrlPathReplacer = new DownstreamUrlTemplateVariableReplacer();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void can_replace_no_template_variables()
|
public void can_replace_no_template_variables()
|
||||||
{
|
{
|
||||||
this.Given(x => x.GivenThereIsAnUpstreamUrlPath(""))
|
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List<TemplateVariableNameAndValue>(), "")))
|
||||||
.And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, new List<TemplateVariableNameAndValue>(), "")))
|
|
||||||
.When(x => x.WhenIReplaceTheTemplateVariables())
|
.When(x => x.WhenIReplaceTheTemplateVariables())
|
||||||
.Then(x => x.ThenTheUpstreamUrlPathIsReturned(""))
|
.Then(x => x.ThenTheDownstreamUrlPathIsReturned(""))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void can_replace_no_template_variables_with_slash()
|
||||||
|
{
|
||||||
|
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List<TemplateVariableNameAndValue>(), "/")))
|
||||||
|
.When(x => x.WhenIReplaceTheTemplateVariables())
|
||||||
|
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("/"))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void can_replace_url_no_slash()
|
public void can_replace_url_no_slash()
|
||||||
{
|
{
|
||||||
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("api"))
|
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List<TemplateVariableNameAndValue>(), "api")))
|
||||||
.And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, new List<TemplateVariableNameAndValue>(), "api")))
|
|
||||||
.When(x => x.WhenIReplaceTheTemplateVariables())
|
.When(x => x.WhenIReplaceTheTemplateVariables())
|
||||||
.Then(x => x.ThenTheUpstreamUrlPathIsReturned("api"))
|
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("api"))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void can_replace_url_one_slash()
|
public void can_replace_url_one_slash()
|
||||||
{
|
{
|
||||||
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("api/"))
|
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List<TemplateVariableNameAndValue>(), "api/")))
|
||||||
.And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, new List<TemplateVariableNameAndValue>(), "api/")))
|
|
||||||
.When(x => x.WhenIReplaceTheTemplateVariables())
|
.When(x => x.WhenIReplaceTheTemplateVariables())
|
||||||
.Then(x => x.ThenTheUpstreamUrlPathIsReturned("api/"))
|
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/"))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void can_replace_url_multiple_slash()
|
public void can_replace_url_multiple_slash()
|
||||||
{
|
{
|
||||||
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("api/product/products/"))
|
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List<TemplateVariableNameAndValue>(), "api/product/products/")))
|
||||||
.And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, new List<TemplateVariableNameAndValue>(), "api/product/products/")))
|
|
||||||
.When(x => x.WhenIReplaceTheTemplateVariables())
|
.When(x => x.WhenIReplaceTheTemplateVariables())
|
||||||
.Then(x => x.ThenTheUpstreamUrlPathIsReturned("api/product/products/"))
|
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/product/products/"))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,10 +73,9 @@ namespace Ocelot.UnitTests
|
|||||||
new TemplateVariableNameAndValue("{productId}", "1")
|
new TemplateVariableNameAndValue("{productId}", "1")
|
||||||
};
|
};
|
||||||
|
|
||||||
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("productservice/products/{productId}/"))
|
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, "productservice/products/{productId}/")))
|
||||||
.And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, templateVariables, "api/products/{productId}/")))
|
|
||||||
.When(x => x.WhenIReplaceTheTemplateVariables())
|
.When(x => x.WhenIReplaceTheTemplateVariables())
|
||||||
.Then(x => x.ThenTheUpstreamUrlPathIsReturned("productservice/products/1/"))
|
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/"))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,10 +87,9 @@ namespace Ocelot.UnitTests
|
|||||||
new TemplateVariableNameAndValue("{productId}", "1")
|
new TemplateVariableNameAndValue("{productId}", "1")
|
||||||
};
|
};
|
||||||
|
|
||||||
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("productservice/products/{productId}/variants"))
|
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, "productservice/products/{productId}/variants")))
|
||||||
.And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, templateVariables, "api/products/{productId}/")))
|
|
||||||
.When(x => x.WhenIReplaceTheTemplateVariables())
|
.When(x => x.WhenIReplaceTheTemplateVariables())
|
||||||
.Then(x => x.ThenTheUpstreamUrlPathIsReturned("productservice/products/1/variants"))
|
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants"))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,10 +102,9 @@ namespace Ocelot.UnitTests
|
|||||||
new TemplateVariableNameAndValue("{variantId}", "12")
|
new TemplateVariableNameAndValue("{variantId}", "12")
|
||||||
};
|
};
|
||||||
|
|
||||||
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("productservice/products/{productId}/variants/{variantId}"))
|
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, "productservice/products/{productId}/variants/{variantId}")))
|
||||||
.And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, templateVariables, "api/products/{productId}/{variantId}")))
|
|
||||||
.When(x => x.WhenIReplaceTheTemplateVariables())
|
.When(x => x.WhenIReplaceTheTemplateVariables())
|
||||||
.Then(x => x.ThenTheUpstreamUrlPathIsReturned("productservice/products/1/variants/12"))
|
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants/12"))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,29 +118,23 @@ namespace Ocelot.UnitTests
|
|||||||
new TemplateVariableNameAndValue("{categoryId}", "34")
|
new TemplateVariableNameAndValue("{categoryId}", "34")
|
||||||
};
|
};
|
||||||
|
|
||||||
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("productservice/category/{categoryId}/products/{productId}/variants/{variantId}"))
|
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, "productservice/category/{categoryId}/products/{productId}/variants/{variantId}")))
|
||||||
.And(x => x.GivenThereIsAUrlPathMatch(new UrlPathMatch(true, templateVariables, "api/products/{categoryId}/{productId}/{variantId}")))
|
|
||||||
.When(x => x.WhenIReplaceTheTemplateVariables())
|
.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();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenThereIsAnUpstreamUrlPath(string upstreamUrlPath)
|
private void GivenThereIsAUrlMatch(DownstreamRoute downstreamRoute)
|
||||||
{
|
{
|
||||||
_upstreamUrlPath = upstreamUrlPath;
|
_downstreamRoute = downstreamRoute;
|
||||||
}
|
|
||||||
|
|
||||||
private void GivenThereIsAUrlPathMatch(UrlPathMatch urlPathMatch)
|
|
||||||
{
|
|
||||||
_urlPathMatch = urlPathMatch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WhenIReplaceTheTemplateVariables()
|
private void WhenIReplaceTheTemplateVariables()
|
||||||
{
|
{
|
||||||
_result = _upstreamUrlPathReplacer.ReplaceTemplateVariable(_upstreamUrlPath, _urlPathMatch);
|
_result = _downstreamUrlPathReplacer.ReplaceTemplateVariable(_downstreamRoute);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenTheUpstreamUrlPathIsReturned(string expected)
|
private void ThenTheDownstreamUrlPathIsReturned(string expected)
|
||||||
{
|
{
|
||||||
_result.ShouldBe(expected);
|
_result.ShouldBe(expected);
|
||||||
}
|
}
|
||||||
|
@ -1,138 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using Ocelot.Library.Infrastructure.Responses;
|
|
||||||
using Ocelot.Library.Infrastructure.UrlPathTemplateRepository;
|
|
||||||
using Shouldly;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace Ocelot.UnitTests
|
|
||||||
{
|
|
||||||
using TestStack.BDDfy;
|
|
||||||
|
|
||||||
public class UrlPathTemplateMapRepositoryTests
|
|
||||||
{
|
|
||||||
private string _upstreamUrlPath;
|
|
||||||
private string _downstreamUrlPath;
|
|
||||||
private IUrlPathTemplateMapRepository _repository;
|
|
||||||
private Response _response;
|
|
||||||
private Response<UrlPathTemplateMap> _getResponse;
|
|
||||||
private Response<List<UrlPathTemplateMap>> _listResponse;
|
|
||||||
|
|
||||||
public UrlPathTemplateMapRepositoryTests()
|
|
||||||
{
|
|
||||||
_repository = new InMemoryUrlPathTemplateMapRepository();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void can_add_url_path()
|
|
||||||
{
|
|
||||||
this.Given(x => x.GivenIHaveAnUpstreamUrlPath("/api/products/products/{productId}"))
|
|
||||||
.And(x => x.GivenIWantToRouteRequestsToMyUpstreamUrlPath("/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"))
|
|
||||||
.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.GivenIHaveSetUpADownstreamUrlPathAndAnUpstreamUrlPath("/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();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ThenTheDownstreamUrlAlreadyBeenUsed()
|
|
||||||
{
|
|
||||||
_response.ShouldNotBeNull();
|
|
||||||
_response.ShouldBeOfType<ErrorResponse>();
|
|
||||||
_response.Errors[0].Message.ShouldBe("This key has already been used");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ThenTheKeyDoesNotExist()
|
|
||||||
{
|
|
||||||
_getResponse.ShouldNotBeNull();
|
|
||||||
_getResponse.ShouldBeOfType<ErrorResponse<UrlPathTemplateMap>>();
|
|
||||||
_getResponse.Errors[0].Message.ShouldBe("This key does not exist");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WhenIRetrieveTheUrlPathByDownstreamUrl()
|
|
||||||
{
|
|
||||||
_getResponse = _repository.GetUrlPathTemplateMap(_downstreamUrlPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
GivenIHaveAnUpstreamUrlPath(upstreamApiUrl);
|
|
||||||
GivenIWantToRouteRequestsToMyUpstreamUrlPath(downstream);
|
|
||||||
WhenIAddTheConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GivenIHaveAnUpstreamUrlPath(string upstreamApiUrl)
|
|
||||||
{
|
|
||||||
_upstreamUrlPath = upstreamApiUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GivenIWantToRouteRequestsToMyUpstreamUrlPath(string apiKey)
|
|
||||||
{
|
|
||||||
_downstreamUrlPath = apiKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WhenIAddTheConfiguration()
|
|
||||||
{
|
|
||||||
_response = _repository.AddUrlPathTemplateMap(new UrlPathTemplateMap(_downstreamUrlPath, _upstreamUrlPath));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ThenTheResponseIsSuccesful()
|
|
||||||
{
|
|
||||||
_response.ShouldBeOfType<OkResponse>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Ocelot.Library.Infrastructure.UrlPathMatcher;
|
using Ocelot.Library.Infrastructure.UrlMatcher;
|
||||||
using Shouldly;
|
using Shouldly;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
@ -8,26 +8,26 @@ namespace Ocelot.UnitTests
|
|||||||
{
|
{
|
||||||
using TestStack.BDDfy;
|
using TestStack.BDDfy;
|
||||||
|
|
||||||
public class UrlPathToUrlPathTemplateMatcherTests
|
public class UrlPathToUrlTemplateMatcherTests
|
||||||
{
|
{
|
||||||
private readonly IUrlPathToUrlPathTemplateMatcher _urlMapper;
|
private readonly IUrlPathToUrlTemplateMatcher _urlMatcher;
|
||||||
private string _downstreamPath;
|
private string _downstreamUrlPath;
|
||||||
private string _downstreamPathTemplate;
|
private string _downstreamPathTemplate;
|
||||||
private UrlPathMatch _result;
|
private UrlMatch _result;
|
||||||
public UrlPathToUrlPathTemplateMatcherTests()
|
public UrlPathToUrlTemplateMatcherTests()
|
||||||
{
|
{
|
||||||
_urlMapper = new UrlPathToUrlPathTemplateMatcher();
|
_urlMatcher = new UrlPathToUrlTemplateMatcher();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void can_match_down_stream_url()
|
public void can_match_down_stream_url()
|
||||||
{
|
{
|
||||||
this.Given(x => x.GivenIHaveADownstreamPath(""))
|
this.Given(x => x.GivenIHaveADownstreamPath(""))
|
||||||
.And(x => x.GivenIHaveAnDownstreamPathTemplate(""))
|
.And(x => x.GivenIHaveAnDownstreamUrlTemplate(""))
|
||||||
.When(x => x.WhenIMatchThePaths())
|
.When(x => x.WhenIMatchThePaths())
|
||||||
.And(x => x.ThenTheResultIsTrue())
|
.And(x => x.ThenTheResultIsTrue())
|
||||||
.And(x => x.ThenTheTemplatesDictionaryIs(new List<TemplateVariableNameAndValue>()))
|
.And(x => x.ThenTheTemplatesVariablesAre(new List<TemplateVariableNameAndValue>()))
|
||||||
.And(x => x.ThenTheUrlPathTemplateIs(""))
|
.And(x => x.ThenTheDownstreamUrlTemplateIs(""))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,11 +35,11 @@ namespace Ocelot.UnitTests
|
|||||||
public void can_match_down_stream_url_with_no_slash()
|
public void can_match_down_stream_url_with_no_slash()
|
||||||
{
|
{
|
||||||
this.Given(x => x.GivenIHaveADownstreamPath("api"))
|
this.Given(x => x.GivenIHaveADownstreamPath("api"))
|
||||||
.Given(x => x.GivenIHaveAnDownstreamPathTemplate("api"))
|
.Given(x => x.GivenIHaveAnDownstreamUrlTemplate("api"))
|
||||||
.When(x => x.WhenIMatchThePaths())
|
.When(x => x.WhenIMatchThePaths())
|
||||||
.Then(x => x.ThenTheResultIsTrue())
|
.Then(x => x.ThenTheResultIsTrue())
|
||||||
.And(x => x.ThenTheTemplatesDictionaryIs(new List<TemplateVariableNameAndValue>()))
|
.And(x => x.ThenTheTemplatesVariablesAre(new List<TemplateVariableNameAndValue>()))
|
||||||
.And(x => x.ThenTheUrlPathTemplateIs("api"))
|
.And(x => x.ThenTheDownstreamUrlTemplateIs("api"))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,11 +47,11 @@ namespace Ocelot.UnitTests
|
|||||||
public void can_match_down_stream_url_with_one_slash()
|
public void can_match_down_stream_url_with_one_slash()
|
||||||
{
|
{
|
||||||
this.Given(x => x.GivenIHaveADownstreamPath("api/"))
|
this.Given(x => x.GivenIHaveADownstreamPath("api/"))
|
||||||
.Given(x => x.GivenIHaveAnDownstreamPathTemplate("api/"))
|
.Given(x => x.GivenIHaveAnDownstreamUrlTemplate("api/"))
|
||||||
.When(x => x.WhenIMatchThePaths())
|
.When(x => x.WhenIMatchThePaths())
|
||||||
.Then(x => x.ThenTheResultIsTrue())
|
.Then(x => x.ThenTheResultIsTrue())
|
||||||
.And(x => x.ThenTheTemplatesDictionaryIs(new List<TemplateVariableNameAndValue>()))
|
.And(x => x.ThenTheTemplatesVariablesAre(new List<TemplateVariableNameAndValue>()))
|
||||||
.And(x => x.ThenTheUrlPathTemplateIs("api/"))
|
.And(x => x.ThenTheDownstreamUrlTemplateIs("api/"))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,11 +59,11 @@ namespace Ocelot.UnitTests
|
|||||||
public void can_match_down_stream_url_with_downstream_template()
|
public void can_match_down_stream_url_with_downstream_template()
|
||||||
{
|
{
|
||||||
this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/"))
|
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())
|
.When(x => x.WhenIMatchThePaths())
|
||||||
.Then(x => x.ThenTheResultIsTrue())
|
.Then(x => x.ThenTheResultIsTrue())
|
||||||
.And(x => x.ThenTheTemplatesDictionaryIs(new List<TemplateVariableNameAndValue>()))
|
.And(x => x.ThenTheTemplatesVariablesAre(new List<TemplateVariableNameAndValue>()))
|
||||||
.And(x => x.ThenTheUrlPathTemplateIs("api/product/products/"))
|
.And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/"))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,11 +71,11 @@ namespace Ocelot.UnitTests
|
|||||||
public void can_match_down_stream_url_with_downstream_template_with_one_query_string_parameter()
|
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"))
|
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())
|
.When(x => x.WhenIMatchThePaths())
|
||||||
.Then(x => x.ThenTheResultIsTrue())
|
.Then(x => x.ThenTheResultIsTrue())
|
||||||
.And(x => x.ThenTheTemplatesDictionaryIs(new List<TemplateVariableNameAndValue>()))
|
.And(x => x.ThenTheTemplatesVariablesAre(new List<TemplateVariableNameAndValue>()))
|
||||||
.And(x => x.ThenTheUrlPathTemplateIs("api/product/products/"))
|
.And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/"))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,11 +88,11 @@ namespace Ocelot.UnitTests
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1/variants/?soldout=false"))
|
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())
|
.When(x => x.WhenIMatchThePaths())
|
||||||
.Then(x => x.ThenTheResultIsTrue())
|
.Then(x => x.ThenTheResultIsTrue())
|
||||||
.And(x => x.ThenTheTemplatesDictionaryIs(expectedTemplates))
|
.And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates))
|
||||||
.And(x => x.ThenTheUrlPathTemplateIs("api/product/products/{productId}/variants/"))
|
.And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}/variants/"))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,11 +105,11 @@ namespace Ocelot.UnitTests
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1"))
|
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())
|
.When(x => x.WhenIMatchThePaths())
|
||||||
.Then(x => x.ThenTheResultIsTrue())
|
.Then(x => x.ThenTheResultIsTrue())
|
||||||
.And(x => x.ThenTheTemplatesDictionaryIs(expectedTemplates))
|
.And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates))
|
||||||
.And(x => x.ThenTheUrlPathTemplateIs("api/product/products/{productId}"))
|
.And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}"))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,11 +123,11 @@ namespace Ocelot.UnitTests
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1/2"))
|
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())
|
.When(x => x.WhenIMatchThePaths())
|
||||||
.Then(x => x.ThenTheResultIsTrue())
|
.Then(x => x.ThenTheResultIsTrue())
|
||||||
.And(x => x.ThenTheTemplatesDictionaryIs(expectedTemplates))
|
.And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates))
|
||||||
.And(x => x.ThenTheUrlPathTemplateIs("api/product/products/{productId}/{categoryId}"))
|
.And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}/{categoryId}"))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,11 +141,11 @@ namespace Ocelot.UnitTests
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1/categories/2"))
|
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())
|
.When(x => x.WhenIMatchThePaths())
|
||||||
.Then(x => x.ThenTheResultIsTrue())
|
.Then(x => x.ThenTheResultIsTrue())
|
||||||
.And(x => x.ThenTheTemplatesDictionaryIs(expectedTemplates))
|
.And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates))
|
||||||
.And(x => x.ThenTheUrlPathTemplateIs("api/product/products/{productId}/categories/{categoryId}"))
|
.And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}/categories/{categoryId}"))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,11 +160,11 @@ namespace Ocelot.UnitTests
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1/categories/2/variant/123"))
|
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())
|
.When(x => x.WhenIMatchThePaths())
|
||||||
.Then(x => x.ThenTheResultIsTrue())
|
.Then(x => x.ThenTheResultIsTrue())
|
||||||
.And(x => x.ThenTheTemplatesDictionaryIs(expectedTemplates))
|
.And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates))
|
||||||
.And(x => x.ThenTheUrlPathTemplateIs("api/product/products/{productId}/categories/{categoryId}/variant/{variantId}"))
|
.And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}/categories/{categoryId}/variant/{variantId}"))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,15 +178,15 @@ namespace Ocelot.UnitTests
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.Given(x => x.GivenIHaveADownstreamPath("api/product/products/1/categories/2/variant/"))
|
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())
|
.When(x => x.WhenIMatchThePaths())
|
||||||
.Then(x => x.ThenTheResultIsTrue())
|
.Then(x => x.ThenTheResultIsTrue())
|
||||||
.And(x => x.ThenTheTemplatesDictionaryIs(expectedTemplates))
|
.And(x => x.ThenTheTemplatesVariablesAre(expectedTemplates))
|
||||||
.And(x => x.ThenTheUrlPathTemplateIs("api/product/products/{productId}/categories/{categoryId}/variant/"))
|
.And(x => x.ThenTheDownstreamUrlTemplateIs("api/product/products/{productId}/categories/{categoryId}/variant/"))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenTheTemplatesDictionaryIs(List<TemplateVariableNameAndValue> expectedResults)
|
private void ThenTheTemplatesVariablesAre(List<TemplateVariableNameAndValue> expectedResults)
|
||||||
{
|
{
|
||||||
foreach (var expectedResult in 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)
|
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()
|
private void WhenIMatchThePaths()
|
||||||
{
|
{
|
||||||
_result = _urlMapper.Match(_downstreamPath, _downstreamPathTemplate);
|
_result = _urlMatcher.Match(_downstreamUrlPath, _downstreamPathTemplate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenTheResultIsTrue()
|
private void ThenTheResultIsTrue()
|
@ -23,7 +23,9 @@
|
|||||||
"xunit": "2.1.0",
|
"xunit": "2.1.0",
|
||||||
"dotnet-test-xunit": "2.2.0-preview2-build1029",
|
"dotnet-test-xunit": "2.2.0-preview2-build1029",
|
||||||
"Shouldly": "2.8.0",
|
"Shouldly": "2.8.0",
|
||||||
"TestStack.BDDfy": "4.3.1"
|
"TestStack.BDDfy": "4.3.1",
|
||||||
|
"YamlDotNet": "3.9.0",
|
||||||
|
"Moq": "4.6.38-alpha"
|
||||||
},
|
},
|
||||||
|
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user