From 0f71c040d9e098d2d495e81384df41a5fdba868c Mon Sep 17 00:00:00 2001 From: TomPallister Date: Sat, 21 Jan 2017 09:59:47 +0000 Subject: [PATCH 01/14] split DownstreamTemplate into DownstreamPathTemplate, DownstreamScheme, DownstreamHost and DownstreamPort in order to prepare for service discovery --- Ocelot.sln | 2 + README.md | 11 +- configuration-explanation.txt | 19 ++- .../Configuration/Builder/ReRouteBuilder.cs | 18 ++- .../Creator/FileOcelotConfigurationCreator.cs | 11 +- src/Ocelot/Configuration/File/FileReRoute.cs | 3 +- src/Ocelot/Configuration/ReRoute.cs | 13 +- .../DownstreamPathTemplateAlreadyUsedError.cs | 11 ++ ...wnstreamPathTemplateContainsSchemeError.cs | 12 ++ .../DownstreamTemplateAlreadyUsedError.cs | 11 -- .../DownstreamTemplateContainsHostError.cs | 12 -- .../DownstreamTemplateContainsSchemeError.cs | 12 -- .../Validator/FileConfigurationValidator.cs | 16 +-- .../ServiceCollectionExtensions.cs | 4 +- .../DownstreamRouteFinderMiddleware.cs | 2 +- .../DownstreamHostNullOrEmptyError.cs | 12 ++ .../DownstreamPathNullOrEmptyError.cs | 12 ++ .../DownstreamSchemeNullOrEmptyError.cs | 12 ++ .../DownstreamUrlCreator/IUrlBuilder.cs | 12 ++ .../DownstreamUrlCreatorMiddleware.cs | 39 ++++-- src/Ocelot/DownstreamUrlCreator/UrlBuilder.cs | 47 +++++++ .../DownstreamUrlTemplateVariableReplacer.cs | 14 +- ...wnstreamUrlPathTemplateVariableReplacer.cs | 5 +- src/Ocelot/Errors/OcelotErrorCode.cs | 8 +- src/Ocelot/Values/DownstreamPath.cs | 12 ++ src/Ocelot/Values/DownstreamPathTemplate.cs | 12 ++ .../DownstreamUrl.cs | 4 +- src/Ocelot/Values/HostAndPort.cs | 14 ++ .../AuthenticationTests.cs | 41 ++++-- .../AuthorisationTests.cs | 10 +- test/Ocelot.AcceptanceTests/CachingTests.cs | 10 +- .../CaseSensitiveRoutingTests.cs | 30 ++++- .../ClaimsToHeadersForwardingTests.cs | 5 +- .../ClaimsToQueryStringForwardingTests.cs | 5 +- .../CustomMiddlewareTests.cs | 30 ++++- test/Ocelot.AcceptanceTests/RequestIdTests.cs | 15 ++- .../ReturnsErrorTests.cs | 2 +- test/Ocelot.AcceptanceTests/RoutingTests.cs | 91 ++++++++++++- .../Ocelot.AcceptanceTests/configuration.json | 2 +- test/Ocelot.ManualTest/Program.cs | 1 - test/Ocelot.ManualTest/configuration.json | 100 +++++++++++--- .../Claims/ClaimsBuilderMiddlewareTests.cs | 2 +- .../ConfigurationValidationTests.cs | 47 ++----- .../FileConfigurationCreatorTests.cs | 58 ++++---- .../InMemoryConfigurationRepositoryTests.cs | 10 +- .../DownstreamRouteFinderMiddlewareTests.cs | 2 +- .../DownstreamRouteFinderTests.cs | 14 +- .../DownstreamUrlCreatorMiddlewareTests.cs | 33 +++-- .../DownstreamUrlCreator/UrlBuilderTests.cs | 124 ++++++++++++++++++ ...eamUrlPathTemplateVariableReplacerTests.cs | 25 ++-- ...ttpRequestHeadersBuilderMiddlewareTests.cs | 2 +- .../QueryStringBuilderMiddlewareTests.cs | 2 +- .../RequestId/RequestIdMiddlewareTests.cs | 4 +- 53 files changed, 767 insertions(+), 258 deletions(-) create mode 100644 src/Ocelot/Configuration/Validator/DownstreamPathTemplateAlreadyUsedError.cs create mode 100644 src/Ocelot/Configuration/Validator/DownstreamPathTemplateContainsSchemeError.cs delete mode 100644 src/Ocelot/Configuration/Validator/DownstreamTemplateAlreadyUsedError.cs delete mode 100644 src/Ocelot/Configuration/Validator/DownstreamTemplateContainsHostError.cs delete mode 100644 src/Ocelot/Configuration/Validator/DownstreamTemplateContainsSchemeError.cs create mode 100644 src/Ocelot/DownstreamUrlCreator/DownstreamHostNullOrEmptyError.cs create mode 100644 src/Ocelot/DownstreamUrlCreator/DownstreamPathNullOrEmptyError.cs create mode 100644 src/Ocelot/DownstreamUrlCreator/DownstreamSchemeNullOrEmptyError.cs create mode 100644 src/Ocelot/DownstreamUrlCreator/IUrlBuilder.cs create mode 100644 src/Ocelot/DownstreamUrlCreator/UrlBuilder.cs create mode 100644 src/Ocelot/Values/DownstreamPath.cs create mode 100644 src/Ocelot/Values/DownstreamPathTemplate.cs rename src/Ocelot/{DownstreamUrlCreator/UrlTemplateReplacer => Values}/DownstreamUrl.cs (74%) create mode 100644 src/Ocelot/Values/HostAndPort.cs create mode 100644 test/Ocelot.UnitTests/DownstreamUrlCreator/UrlBuilderTests.cs diff --git a/Ocelot.sln b/Ocelot.sln index 5ebd0660..0165beb0 100644 --- a/Ocelot.sln +++ b/Ocelot.sln @@ -17,8 +17,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Ocelot.nuspec = Ocelot.nuspec push-to-nuget.bat = push-to-nuget.bat README.md = README.md + run-acceptance-tests.bat = run-acceptance-tests.bat run-benchmarks.bat = run-benchmarks.bat run-tests.bat = run-tests.bat + run-unit-tests.bat = run-unit-tests.bat EndProjectSection EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Ocelot", "src\Ocelot\Ocelot.xproj", "{D6DF4206-0DBA-41D8-884D-C3E08290FDBB}" diff --git a/README.md b/README.md index dd5f1043..249a99a3 100644 --- a/README.md +++ b/README.md @@ -136,17 +136,20 @@ In order to set up a ReRoute you need to add one to the json array called ReRout the following. { - "DownstreamTemplate": "http://jsonplaceholder.typicode.com/posts/{postId}", + "DownstreamPathTemplate": "/api/posts/{postId}", + "DownstreamScheme": "https", + "DownstreamPort": 80, + "DownstreamHost" "localhost" "UpstreamTemplate": "/posts/{postId}", "UpstreamHttpMethod": "Put" } -The DownstreamTemplate is the URL that this request will be forwarded to. +The DownstreamPathTemplate,Scheme, Port and Host make the URL that this request will be forwarded to. The UpstreamTemplate is the URL that Ocelot will use to identity which -DownstreamTemplate to use for a given request. Finally the UpstreamHttpMethod is used so +DownstreamPathTemplate to use for a given request. Finally the UpstreamHttpMethod is used so Ocelot can distinguish between requests to the same URL and is obviously needed to work :) In Ocelot you can add placeholders for variables to your Templates in the form of {something}. -The placeholder needs to be in both the DownstreamTemplate and UpstreamTemplate. If it is +The placeholder needs to be in both the DownstreamPathTemplate and UpstreamTemplate. If it is Ocelot will attempt to replace the placeholder with the correct variable value from the Upstream URL when the request comes in. diff --git a/configuration-explanation.txt b/configuration-explanation.txt index 898be89f..ad020469 100644 --- a/configuration-explanation.txt +++ b/configuration-explanation.txt @@ -1,11 +1,20 @@ { "ReRoutes": [ { - # The url we are forwarding the request to, ocelot will not add a trailing slash - "DownstreamTemplate": "http://somehost.com/identityserverexample", - # The path we are listening on for this re route, Ocelot will add a trailing slash to - # this property. Then when a request is made Ocelot makes sure a trailing slash is added - # to that so everything matches + # The downstream path we are forwarding the request to, ocelot will not add a trailing slash. + # Ocelot replaces any placeholders {etc} with matched values from the incoming request. + "DownstreamPathTemplate": "/identityserverexample/{someid}/something", + # The scheme you want Ocelot to use when making the downstream request + "DownstreamScheme": "https", + # The port you want Ocelot to use when making the downstream request, will default to + # scheme if nothing set + "DownstreamPort": 80, + # The host address of the downstream service, should not have a trailing slash or scheme + # if there is a trailing slash Ocelot will remove it. + "DownstreamHost" "localhost" + # The path template we are listening on for this re route, Ocelot will add a trailing + # slash to this property. Then when a request is made Ocelot makes sure a trailing + # slash is added, so everything matches "UpstreamTemplate": "/identityserverexample", # The method we are listening for on this re route "UpstreamHttpMethod": "Get", diff --git a/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs b/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs index 3f5ef40b..1e06a440 100644 --- a/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs +++ b/src/Ocelot/Configuration/Builder/ReRouteBuilder.cs @@ -1,11 +1,12 @@ using System; using System.Collections.Generic; +using Ocelot.Values; namespace Ocelot.Configuration.Builder { public class ReRouteBuilder { - private string _downstreamTemplate; + private string _downstreamPathTemplate; private string _upstreamTemplate; private string _upstreamTemplatePattern; private string _upstreamHttpMethod; @@ -30,6 +31,7 @@ namespace Ocelot.Configuration.Builder private string _serviceDiscoveryAddress; private string _downstreamScheme; private string _downstreamHost; + private int _dsPort; public ReRouteBuilder() { @@ -72,9 +74,9 @@ namespace Ocelot.Configuration.Builder return this; } - public ReRouteBuilder WithDownstreamTemplate(string input) + public ReRouteBuilder WithDownstreamPathTemplate(string input) { - _downstreamTemplate = input; + _downstreamPathTemplate = input; return this; } @@ -184,11 +186,17 @@ namespace Ocelot.Configuration.Builder return this; } + public ReRouteBuilder WithDownstreamPort(int port) + { + _dsPort = port; + return this; + } + public ReRoute Build() { - Func downstreamHostFunc = () => { return _downstreamHost; }; + Func downstreamHostFunc = () => new HostAndPort(_downstreamHost, _dsPort); - return new ReRoute(_downstreamTemplate, _upstreamTemplate, _upstreamHttpMethod, _upstreamTemplatePattern, + return new ReRoute(new DownstreamPathTemplate(_downstreamPathTemplate), _upstreamTemplate, _upstreamHttpMethod, _upstreamTemplatePattern, _isAuthenticated, new AuthenticationOptions(_authenticationProvider, _authenticationProviderUrl, _scopeName, _requireHttps, _additionalScopes, _scopeSecret), _configHeaderExtractorProperties, _claimToClaims, _routeClaimRequirement, _isAuthorised, _claimToQueries, _requestIdHeaderKey, _isCached, _fileCacheOptions, _serviceName, diff --git a/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs index c71aba23..8884f0d9 100644 --- a/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs +++ b/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs @@ -8,6 +8,7 @@ using Ocelot.Configuration.Parser; using Ocelot.Configuration.Validator; using Ocelot.Responses; using Ocelot.Utilities; +using Ocelot.Values; namespace Ocelot.Configuration.Creator { @@ -96,7 +97,7 @@ namespace Ocelot.Configuration.Creator && !string.IsNullOrEmpty(globalConfiguration?.ServiceDiscoveryProvider?.Provider); - Func downstreamHostFunc = () => { return reRoute.DownstreamHost; }; + Func downstreamHostAndPortFunc = () => new HostAndPort(reRoute.DownstreamHost.Trim('/'), reRoute.DownstreamPort); if (isAuthenticated) { @@ -109,22 +110,22 @@ namespace Ocelot.Configuration.Creator var claimsToClaims = GetAddThingsToRequest(reRoute.AddClaimsToRequest); var claimsToQueries = GetAddThingsToRequest(reRoute.AddQueriesToRequest); - return new ReRoute(reRoute.DownstreamTemplate, reRoute.UpstreamTemplate, + return new ReRoute(new DownstreamPathTemplate(reRoute.DownstreamPathTemplate), reRoute.UpstreamTemplate, reRoute.UpstreamHttpMethod, upstreamTemplate, isAuthenticated, authOptionsForRoute, claimsToHeaders, claimsToClaims, reRoute.RouteClaimsRequirement, isAuthorised, claimsToQueries, requestIdKey, isCached, new CacheOptions(reRoute.FileCacheOptions.TtlSeconds), reRoute.ServiceName, useServiceDiscovery, globalConfiguration?.ServiceDiscoveryProvider?.Provider, - globalConfiguration?.ServiceDiscoveryProvider?.Address, downstreamHostFunc, reRoute.DownstreamScheme); + globalConfiguration?.ServiceDiscoveryProvider?.Address, downstreamHostAndPortFunc, reRoute.DownstreamScheme); } - return new ReRoute(reRoute.DownstreamTemplate, reRoute.UpstreamTemplate, + return new ReRoute(new DownstreamPathTemplate(reRoute.DownstreamPathTemplate), reRoute.UpstreamTemplate, reRoute.UpstreamHttpMethod, upstreamTemplate, isAuthenticated, null, new List(), new List(), reRoute.RouteClaimsRequirement, isAuthorised, new List(), requestIdKey, isCached, new CacheOptions(reRoute.FileCacheOptions.TtlSeconds), reRoute.ServiceName, useServiceDiscovery, globalConfiguration?.ServiceDiscoveryProvider?.Provider, - globalConfiguration?.ServiceDiscoveryProvider?.Address, downstreamHostFunc, reRoute.DownstreamScheme); + globalConfiguration?.ServiceDiscoveryProvider?.Address, downstreamHostAndPortFunc, reRoute.DownstreamScheme); } private string BuildUpstreamTemplate(FileReRoute reRoute) diff --git a/src/Ocelot/Configuration/File/FileReRoute.cs b/src/Ocelot/Configuration/File/FileReRoute.cs index 3afa03ce..a653224a 100644 --- a/src/Ocelot/Configuration/File/FileReRoute.cs +++ b/src/Ocelot/Configuration/File/FileReRoute.cs @@ -14,7 +14,7 @@ namespace Ocelot.Configuration.File FileCacheOptions = new FileCacheOptions(); } - public string DownstreamTemplate { get; set; } + public string DownstreamPathTemplate { get; set; } public string UpstreamTemplate { get; set; } public string UpstreamHttpMethod { get; set; } public FileAuthenticationOptions AuthenticationOptions { get; set; } @@ -28,5 +28,6 @@ namespace Ocelot.Configuration.File public string ServiceName { get; set; } public string DownstreamScheme {get;set;} public string DownstreamHost {get;set;} + public int DownstreamPort { get; set; } } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/ReRoute.cs b/src/Ocelot/Configuration/ReRoute.cs index 8778e5f7..960374cc 100644 --- a/src/Ocelot/Configuration/ReRoute.cs +++ b/src/Ocelot/Configuration/ReRoute.cs @@ -1,17 +1,18 @@ using System; using System.Collections.Generic; +using Ocelot.Values; namespace Ocelot.Configuration { public class ReRoute { - public ReRoute(string downstreamTemplate, string upstreamTemplate, string upstreamHttpMethod, string upstreamTemplatePattern, + public ReRoute(DownstreamPathTemplate downstreamPathTemplate, string upstreamTemplate, string upstreamHttpMethod, string upstreamTemplatePattern, bool isAuthenticated, AuthenticationOptions authenticationOptions, List configurationHeaderExtractorProperties, List claimsToClaims, Dictionary routeClaimsRequirement, bool isAuthorised, List claimsToQueries, string requestIdKey, bool isCached, CacheOptions fileCacheOptions, string serviceName, bool useServiceDiscovery, - string serviceDiscoveryProvider, string serviceDiscoveryAddress, Func downstreamHost, string downstreamScheme) + string serviceDiscoveryProvider, string serviceDiscoveryAddress, Func downstreamHostAndPort, string downstreamScheme) { - DownstreamTemplate = downstreamTemplate; + DownstreamPathTemplate = downstreamPathTemplate; UpstreamTemplate = upstreamTemplate; UpstreamHttpMethod = upstreamHttpMethod; UpstreamTemplatePattern = upstreamTemplatePattern; @@ -32,11 +33,11 @@ namespace Ocelot.Configuration UseServiceDiscovery = useServiceDiscovery; ServiceDiscoveryProvider = serviceDiscoveryProvider; ServiceDiscoveryAddress = serviceDiscoveryAddress; - DownstreamHost = downstreamHost; + DownstreamHostAndPort = downstreamHostAndPort; DownstreamScheme = downstreamScheme; } - public string DownstreamTemplate { get; private set; } + public DownstreamPathTemplate DownstreamPathTemplate { get; private set; } public string UpstreamTemplate { get; private set; } public string UpstreamTemplatePattern { get; private set; } public string UpstreamHttpMethod { get; private set; } @@ -54,7 +55,7 @@ namespace Ocelot.Configuration public bool UseServiceDiscovery { get; private set;} public string ServiceDiscoveryProvider { get; private set;} public string ServiceDiscoveryAddress { get; private set;} - public Func DownstreamHost {get;private set;} + public Func DownstreamHostAndPort {get;private set;} public string DownstreamScheme {get;private set;} } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/Validator/DownstreamPathTemplateAlreadyUsedError.cs b/src/Ocelot/Configuration/Validator/DownstreamPathTemplateAlreadyUsedError.cs new file mode 100644 index 00000000..e350753c --- /dev/null +++ b/src/Ocelot/Configuration/Validator/DownstreamPathTemplateAlreadyUsedError.cs @@ -0,0 +1,11 @@ +using Ocelot.Errors; + +namespace Ocelot.Configuration.Validator +{ + public class DownstreamPathTemplateAlreadyUsedError : Error + { + public DownstreamPathTemplateAlreadyUsedError(string message) : base(message, OcelotErrorCode.DownstreampathTemplateAlreadyUsedError) + { + } + } +} diff --git a/src/Ocelot/Configuration/Validator/DownstreamPathTemplateContainsSchemeError.cs b/src/Ocelot/Configuration/Validator/DownstreamPathTemplateContainsSchemeError.cs new file mode 100644 index 00000000..a3dfa309 --- /dev/null +++ b/src/Ocelot/Configuration/Validator/DownstreamPathTemplateContainsSchemeError.cs @@ -0,0 +1,12 @@ +using Ocelot.Errors; + +namespace Ocelot.Configuration.Validator +{ + public class DownstreamPathTemplateContainsSchemeError : Error + { + public DownstreamPathTemplateContainsSchemeError(string message) + : base(message, OcelotErrorCode.DownstreamPathTemplateContainsSchemeError) + { + } + } +} diff --git a/src/Ocelot/Configuration/Validator/DownstreamTemplateAlreadyUsedError.cs b/src/Ocelot/Configuration/Validator/DownstreamTemplateAlreadyUsedError.cs deleted file mode 100644 index b836b1eb..00000000 --- a/src/Ocelot/Configuration/Validator/DownstreamTemplateAlreadyUsedError.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Ocelot.Errors; - -namespace Ocelot.Configuration.Validator -{ - public class DownstreamTemplateAlreadyUsedError : Error - { - public DownstreamTemplateAlreadyUsedError(string message) : base(message, OcelotErrorCode.DownstreamTemplateAlreadyUsedError) - { - } - } -} diff --git a/src/Ocelot/Configuration/Validator/DownstreamTemplateContainsHostError.cs b/src/Ocelot/Configuration/Validator/DownstreamTemplateContainsHostError.cs deleted file mode 100644 index 8d9dba92..00000000 --- a/src/Ocelot/Configuration/Validator/DownstreamTemplateContainsHostError.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ocelot.Errors; - -namespace Ocelot.Configuration.Validator -{ - public class DownstreamTemplateContainsHostError : Error - { - public DownstreamTemplateContainsHostError(string message) - : base(message, OcelotErrorCode.DownstreamTemplateContainsHostError) - { - } - } -} diff --git a/src/Ocelot/Configuration/Validator/DownstreamTemplateContainsSchemeError.cs b/src/Ocelot/Configuration/Validator/DownstreamTemplateContainsSchemeError.cs deleted file mode 100644 index 1901fc88..00000000 --- a/src/Ocelot/Configuration/Validator/DownstreamTemplateContainsSchemeError.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Ocelot.Errors; - -namespace Ocelot.Configuration.Validator -{ - public class DownstreamTemplateContainsSchemeError : Error - { - public DownstreamTemplateContainsSchemeError(string message) - : base(message, OcelotErrorCode.DownstreamTemplateContainsSchemeError) - { - } - } -} diff --git a/src/Ocelot/Configuration/Validator/FileConfigurationValidator.cs b/src/Ocelot/Configuration/Validator/FileConfigurationValidator.cs index 3a675d41..412613eb 100644 --- a/src/Ocelot/Configuration/Validator/FileConfigurationValidator.cs +++ b/src/Ocelot/Configuration/Validator/FileConfigurationValidator.cs @@ -26,7 +26,7 @@ namespace Ocelot.Configuration.Validator return new OkResponse(result); } - result = CheckForReRoutesContainingDownstreamScheme(configuration); + result = CheckForReRoutesContainingDownstreamSchemeInDownstreamPathTemplate(configuration); if (result.IsError) { @@ -70,25 +70,25 @@ namespace Ocelot.Configuration.Validator return Enum.TryParse(provider, true, out supportedProvider); } - private ConfigurationValidationResult CheckForReRoutesContainingDownstreamScheme(FileConfiguration configuration) + private ConfigurationValidationResult CheckForReRoutesContainingDownstreamSchemeInDownstreamPathTemplate(FileConfiguration configuration) { var errors = new List(); foreach(var reRoute in configuration.ReRoutes) { - if(reRoute.DownstreamTemplate.Contains("https://") - || reRoute.DownstreamTemplate.Contains("http://")) + if(reRoute.DownstreamPathTemplate.Contains("https://") + || reRoute.DownstreamPathTemplate.Contains("http://")) { - errors.Add(new DownstreamTemplateContainsSchemeError($"{reRoute.DownstreamTemplate} contains scheme")); + errors.Add(new DownstreamPathTemplateContainsSchemeError($"{reRoute.DownstreamPathTemplate} contains scheme")); } } if(errors.Any()) { - return new ConfigurationValidationResult(false, errors); + return new ConfigurationValidationResult(true, errors); } - return new ConfigurationValidationResult(true, errors); + return new ConfigurationValidationResult(false, errors); } private ConfigurationValidationResult CheckForDupliateReRoutes(FileConfiguration configuration) @@ -105,7 +105,7 @@ namespace Ocelot.Configuration.Validator .Where(x => x.Skip(1).Any()); var errors = dupes - .Select(d => new DownstreamTemplateAlreadyUsedError(string.Format("Duplicate DownstreamTemplate: {0}", d.Key.UpstreamTemplate))) + .Select(d => new DownstreamPathTemplateAlreadyUsedError(string.Format("Duplicate DownstreamPath: {0}", d.Key.UpstreamTemplate))) .Cast() .ToList(); diff --git a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs index 04839abb..9f40b009 100644 --- a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs @@ -18,6 +18,7 @@ using Ocelot.Configuration.Repository; using Ocelot.Configuration.Validator; using Ocelot.DownstreamRouteFinder.Finder; using Ocelot.DownstreamRouteFinder.UrlMatcher; +using Ocelot.DownstreamUrlCreator; using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer; using Ocelot.Headers; using Ocelot.Infrastructure.Claims.Parser; @@ -59,6 +60,7 @@ namespace Ocelot.DependencyInjection services.AddMvcCore().AddJsonFormatters(); services.AddLogging(); services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); @@ -69,7 +71,7 @@ namespace Ocelot.DependencyInjection services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs b/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs index a74b6316..f445b46b 100644 --- a/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs +++ b/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs @@ -44,7 +44,7 @@ namespace Ocelot.DownstreamRouteFinder.Middleware return; } - _logger.LogDebug("downstream template is {downstreamRoute.Data.ReRoute.DownstreamTemplate}", downstreamRoute.Data.ReRoute.DownstreamTemplate); + _logger.LogDebug("downstream template is {downstreamRoute.Data.ReRoute.DownstreamPath}", downstreamRoute.Data.ReRoute.DownstreamPathTemplate); SetDownstreamRouteForThisRequest(downstreamRoute.Data); diff --git a/src/Ocelot/DownstreamUrlCreator/DownstreamHostNullOrEmptyError.cs b/src/Ocelot/DownstreamUrlCreator/DownstreamHostNullOrEmptyError.cs new file mode 100644 index 00000000..8978f665 --- /dev/null +++ b/src/Ocelot/DownstreamUrlCreator/DownstreamHostNullOrEmptyError.cs @@ -0,0 +1,12 @@ +using Ocelot.Errors; + +namespace Ocelot.DownstreamUrlCreator +{ + public class DownstreamHostNullOrEmptyError : Error + { + public DownstreamHostNullOrEmptyError() + : base("downstream host was null or empty", OcelotErrorCode.DownstreamHostNullOrEmptyError) + { + } + } +} \ No newline at end of file diff --git a/src/Ocelot/DownstreamUrlCreator/DownstreamPathNullOrEmptyError.cs b/src/Ocelot/DownstreamUrlCreator/DownstreamPathNullOrEmptyError.cs new file mode 100644 index 00000000..fbc1a5f5 --- /dev/null +++ b/src/Ocelot/DownstreamUrlCreator/DownstreamPathNullOrEmptyError.cs @@ -0,0 +1,12 @@ +using Ocelot.Errors; + +namespace Ocelot.DownstreamUrlCreator +{ + public class DownstreamPathNullOrEmptyError : Error + { + public DownstreamPathNullOrEmptyError() + : base("downstream path was null or empty", OcelotErrorCode.DownstreamPathNullOrEmptyError) + { + } + } +} \ No newline at end of file diff --git a/src/Ocelot/DownstreamUrlCreator/DownstreamSchemeNullOrEmptyError.cs b/src/Ocelot/DownstreamUrlCreator/DownstreamSchemeNullOrEmptyError.cs new file mode 100644 index 00000000..e52d3488 --- /dev/null +++ b/src/Ocelot/DownstreamUrlCreator/DownstreamSchemeNullOrEmptyError.cs @@ -0,0 +1,12 @@ +using Ocelot.Errors; + +namespace Ocelot.DownstreamUrlCreator +{ + public class DownstreamSchemeNullOrEmptyError : Error + { + public DownstreamSchemeNullOrEmptyError() + : base("downstream scheme was null or empty", OcelotErrorCode.DownstreamSchemeNullOrEmptyError) + { + } + } +} \ No newline at end of file diff --git a/src/Ocelot/DownstreamUrlCreator/IUrlBuilder.cs b/src/Ocelot/DownstreamUrlCreator/IUrlBuilder.cs new file mode 100644 index 00000000..18683e62 --- /dev/null +++ b/src/Ocelot/DownstreamUrlCreator/IUrlBuilder.cs @@ -0,0 +1,12 @@ +using Ocelot.Configuration; +using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer; +using Ocelot.Responses; +using Ocelot.Values; + +namespace Ocelot.DownstreamUrlCreator +{ + public interface IUrlBuilder + { + Response Build(string downstreamPath, string downstreamScheme, HostAndPort downstreamHostAndPort); + } +} diff --git a/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs b/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs index 8d0af0bd..8144b42b 100644 --- a/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs +++ b/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; +using Ocelot.Configuration; using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer; using Ocelot.Infrastructure.RequestData; using Ocelot.Logging; @@ -11,17 +12,20 @@ namespace Ocelot.DownstreamUrlCreator.Middleware public class DownstreamUrlCreatorMiddleware : OcelotMiddleware { private readonly RequestDelegate _next; - private readonly IDownstreamUrlPathPlaceholderReplacer _urlReplacer; + private readonly IDownstreamPathPlaceholderReplacer _replacer; private readonly IOcelotLogger _logger; + private readonly IUrlBuilder _urlBuilder; public DownstreamUrlCreatorMiddleware(RequestDelegate next, IOcelotLoggerFactory loggerFactory, - IDownstreamUrlPathPlaceholderReplacer urlReplacer, - IRequestScopedDataRepository requestScopedDataRepository) + IDownstreamPathPlaceholderReplacer replacer, + IRequestScopedDataRepository requestScopedDataRepository, + IUrlBuilder urlBuilder) :base(requestScopedDataRepository) { _next = next; - _urlReplacer = urlReplacer; + _replacer = replacer; + _urlBuilder = urlBuilder; _logger = loggerFactory.CreateLogger(); } @@ -29,19 +33,34 @@ namespace Ocelot.DownstreamUrlCreator.Middleware { _logger.LogDebug("started calling downstream url creator middleware"); - var downstreamUrl = _urlReplacer.Replace(DownstreamRoute.ReRoute.DownstreamTemplate, DownstreamRoute.TemplatePlaceholderNameAndValues); + var dsPath = _replacer + .Replace(DownstreamRoute.ReRoute.DownstreamPathTemplate, DownstreamRoute.TemplatePlaceholderNameAndValues); - if (downstreamUrl.IsError) + if (dsPath.IsError) { - _logger.LogDebug("IDownstreamUrlPathPlaceholderReplacer returned an error, setting pipeline error"); + _logger.LogDebug("IDownstreamPathPlaceholderReplacer returned an error, setting pipeline error"); - SetPipelineError(downstreamUrl.Errors); + SetPipelineError(dsPath.Errors); return; } - _logger.LogDebug("downstream url is {downstreamUrl.Data.Value}", downstreamUrl.Data.Value); + var dsScheme = DownstreamRoute.ReRoute.DownstreamScheme; - SetDownstreamUrlForThisRequest(downstreamUrl.Data.Value); + var dsHostAndPort = DownstreamRoute.ReRoute.DownstreamHostAndPort(); + + var dsUrl = _urlBuilder.Build(dsPath.Data.Value, dsScheme, dsHostAndPort); + + if (dsUrl.IsError) + { + _logger.LogDebug("IUrlBuilder returned an error, setting pipeline error"); + + SetPipelineError(dsUrl.Errors); + return; + } + + _logger.LogDebug("downstream url is {downstreamUrl.Data.Value}", dsUrl.Data.Value); + + SetDownstreamUrlForThisRequest(dsUrl.Data.Value); _logger.LogDebug("calling next middleware"); diff --git a/src/Ocelot/DownstreamUrlCreator/UrlBuilder.cs b/src/Ocelot/DownstreamUrlCreator/UrlBuilder.cs new file mode 100644 index 00000000..2124ce3b --- /dev/null +++ b/src/Ocelot/DownstreamUrlCreator/UrlBuilder.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using Ocelot.Configuration; +using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer; +using Ocelot.Errors; +using Ocelot.Responses; +using Ocelot.Values; + +namespace Ocelot.DownstreamUrlCreator +{ + public class UrlBuilder : IUrlBuilder + { + public Response Build(string downstreamPath, string downstreamScheme, HostAndPort downstreamHostAndPort) + { + if (string.IsNullOrEmpty(downstreamPath)) + { + return new ErrorResponse(new List {new DownstreamPathNullOrEmptyError()}); + } + + if (string.IsNullOrEmpty(downstreamScheme)) + { + return new ErrorResponse(new List { new DownstreamSchemeNullOrEmptyError() }); + } + + if (string.IsNullOrEmpty(downstreamHostAndPort.DownstreamHost)) + { + return new ErrorResponse(new List { new DownstreamHostNullOrEmptyError() }); + } + + var builder = new UriBuilder + { + Host = downstreamHostAndPort.DownstreamHost, + Path = downstreamPath, + Scheme = downstreamScheme + }; + + if (downstreamHostAndPort.DownstreamPort > 0) + { + builder.Port = downstreamHostAndPort.DownstreamPort; + } + + var url = builder.Uri.ToString(); + + return new OkResponse(new DownstreamUrl(url)); + } + } +} \ No newline at end of file diff --git a/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs b/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs index 9c19f2f9..9e925631 100644 --- a/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs +++ b/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/DownstreamUrlTemplateVariableReplacer.cs @@ -1,25 +1,25 @@ using System.Collections.Generic; using System.Text; -using Ocelot.DownstreamRouteFinder; using Ocelot.DownstreamRouteFinder.UrlMatcher; using Ocelot.Responses; +using Ocelot.Values; namespace Ocelot.DownstreamUrlCreator.UrlTemplateReplacer { - public class DownstreamUrlPathPlaceholderReplacer : IDownstreamUrlPathPlaceholderReplacer + public class DownstreamTemplatePathPlaceholderReplacer : IDownstreamPathPlaceholderReplacer { - public Response Replace(string downstreamTemplate, List urlPathPlaceholderNameAndValues) + public Response Replace(DownstreamPathTemplate downstreamPathTemplate, List urlPathPlaceholderNameAndValues) { - var upstreamUrl = new StringBuilder(); + var downstreamPath = new StringBuilder(); - upstreamUrl.Append(downstreamTemplate); + downstreamPath.Append(downstreamPathTemplate.Value); foreach (var placeholderVariableAndValue in urlPathPlaceholderNameAndValues) { - upstreamUrl.Replace(placeholderVariableAndValue.TemplateVariableName, placeholderVariableAndValue.TemplateVariableValue); + downstreamPath.Replace(placeholderVariableAndValue.TemplateVariableName, placeholderVariableAndValue.TemplateVariableValue); } - return new OkResponse(new DownstreamUrl(upstreamUrl.ToString())); + return new OkResponse(new DownstreamPath(downstreamPath.ToString())); } } } \ No newline at end of file diff --git a/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs b/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs index 164c42ef..72d5d4b6 100644 --- a/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs +++ b/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/IDownstreamUrlPathTemplateVariableReplacer.cs @@ -1,11 +1,12 @@ using System.Collections.Generic; using Ocelot.DownstreamRouteFinder.UrlMatcher; using Ocelot.Responses; +using Ocelot.Values; namespace Ocelot.DownstreamUrlCreator.UrlTemplateReplacer { - public interface IDownstreamUrlPathPlaceholderReplacer + public interface IDownstreamPathPlaceholderReplacer { - Response Replace(string downstreamTemplate, List urlPathPlaceholderNameAndValues); + Response Replace(DownstreamPathTemplate downstreamPathTemplate, List urlPathPlaceholderNameAndValues); } } \ No newline at end of file diff --git a/src/Ocelot/Errors/OcelotErrorCode.cs b/src/Ocelot/Errors/OcelotErrorCode.cs index f0a336f0..5de770cd 100644 --- a/src/Ocelot/Errors/OcelotErrorCode.cs +++ b/src/Ocelot/Errors/OcelotErrorCode.cs @@ -4,7 +4,7 @@ { UnauthenticatedError, UnknownError, - DownstreamTemplateAlreadyUsedError, + DownstreampathTemplateAlreadyUsedError, UnableToFindDownstreamRouteError, CannotAddDataError, CannotFindDataError, @@ -18,7 +18,9 @@ UnauthorizedError, ClaimValueNotAuthorisedError, UserDoesNotHaveClaimError, - DownstreamTemplateContainsSchemeError, - DownstreamTemplateContainsHostError + DownstreamPathTemplateContainsSchemeError, + DownstreamPathNullOrEmptyError, + DownstreamSchemeNullOrEmptyError, + DownstreamHostNullOrEmptyError } } diff --git a/src/Ocelot/Values/DownstreamPath.cs b/src/Ocelot/Values/DownstreamPath.cs new file mode 100644 index 00000000..90f2e83e --- /dev/null +++ b/src/Ocelot/Values/DownstreamPath.cs @@ -0,0 +1,12 @@ +namespace Ocelot.Values +{ + public class DownstreamPath + { + public DownstreamPath(string value) + { + Value = value; + } + + public string Value { get; private set; } + } +} diff --git a/src/Ocelot/Values/DownstreamPathTemplate.cs b/src/Ocelot/Values/DownstreamPathTemplate.cs new file mode 100644 index 00000000..a4c720eb --- /dev/null +++ b/src/Ocelot/Values/DownstreamPathTemplate.cs @@ -0,0 +1,12 @@ +namespace Ocelot.Values +{ + public class DownstreamPathTemplate + { + public DownstreamPathTemplate(string value) + { + Value = value; + } + + public string Value { get; private set; } + } +} diff --git a/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/DownstreamUrl.cs b/src/Ocelot/Values/DownstreamUrl.cs similarity index 74% rename from src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/DownstreamUrl.cs rename to src/Ocelot/Values/DownstreamUrl.cs index ea90179e..f809c84b 100644 --- a/src/Ocelot/DownstreamUrlCreator/UrlTemplateReplacer/DownstreamUrl.cs +++ b/src/Ocelot/Values/DownstreamUrl.cs @@ -1,4 +1,4 @@ -namespace Ocelot.DownstreamUrlCreator.UrlTemplateReplacer +namespace Ocelot.Values { public class DownstreamUrl { @@ -9,4 +9,4 @@ public string Value { get; private set; } } -} +} \ No newline at end of file diff --git a/src/Ocelot/Values/HostAndPort.cs b/src/Ocelot/Values/HostAndPort.cs new file mode 100644 index 00000000..cd336dec --- /dev/null +++ b/src/Ocelot/Values/HostAndPort.cs @@ -0,0 +1,14 @@ +namespace Ocelot.Values +{ + public class HostAndPort + { + public HostAndPort(string downstreamHost, int downstreamPort) + { + DownstreamHost = downstreamHost; + DownstreamPort = downstreamPort; + } + + public string DownstreamHost { get; private set; } + public int DownstreamPort { get; private set; } + } +} \ No newline at end of file diff --git a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs index 874afe59..8b14f4f1 100644 --- a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs @@ -23,7 +23,11 @@ namespace Ocelot.AcceptanceTests private readonly Steps _steps; private IWebHost _identityServerBuilder; private string _identityServerRootUrl = "http://localhost:51888"; - private string _downstreamServiceRootUrl = "http://localhost:51876/"; + private string _downstreamServicePath = "/"; + private string _downstreamServiceHost = "localhost"; + private int _downstreamServicePort = 51876; + private string _downstreamServiceScheme = "http"; + private string _downstreamServiceUrl = "http://localhost:51876"; public AuthenticationTests() { @@ -39,7 +43,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = _downstreamServiceRootUrl, + DownstreamPathTemplate = _downstreamServicePath, + DownstreamPort = _downstreamServicePort, + DownstreamHost = _downstreamServiceHost, + DownstreamScheme = _downstreamServiceScheme, UpstreamTemplate = "/", UpstreamHttpMethod = "Post", AuthenticationOptions = new FileAuthenticationOptions @@ -56,7 +63,7 @@ namespace Ocelot.AcceptanceTests }; this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", AccessTokenType.Jwt)) - .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceRootUrl, 201, string.Empty)) + .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .And(x => _steps.GivenThePostHasContent("postContent")) @@ -74,7 +81,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = _downstreamServiceRootUrl, + DownstreamPathTemplate = _downstreamServicePath, + DownstreamPort = _downstreamServicePort, + DownstreamHost = _downstreamServiceHost, + DownstreamScheme = _downstreamServiceScheme, UpstreamTemplate = "/", UpstreamHttpMethod = "Post", AuthenticationOptions = new FileAuthenticationOptions @@ -91,7 +101,7 @@ namespace Ocelot.AcceptanceTests }; this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", AccessTokenType.Reference)) - .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceRootUrl, 201, string.Empty)) + .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .And(x => _steps.GivenThePostHasContent("postContent")) @@ -109,7 +119,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = _downstreamServiceRootUrl, + DownstreamPathTemplate = _downstreamServicePath, + DownstreamPort = _downstreamServicePort, + DownstreamHost = _downstreamServiceHost, + DownstreamScheme = _downstreamServiceScheme, UpstreamTemplate = "/", UpstreamHttpMethod = "Get", AuthenticationOptions = new FileAuthenticationOptions @@ -126,7 +139,7 @@ namespace Ocelot.AcceptanceTests }; this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", AccessTokenType.Jwt)) - .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceRootUrl, 200, "Hello from Laura")) + .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 200, "Hello from Laura")) .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) @@ -146,7 +159,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = _downstreamServiceRootUrl, + DownstreamPathTemplate = _downstreamServicePath, + DownstreamPort = _downstreamServicePort, + DownstreamHost = _downstreamServiceHost, + DownstreamScheme = _downstreamServiceScheme, UpstreamTemplate = "/", UpstreamHttpMethod = "Post", AuthenticationOptions = new FileAuthenticationOptions @@ -163,7 +179,7 @@ namespace Ocelot.AcceptanceTests }; this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", AccessTokenType.Jwt)) - .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceRootUrl, 201, string.Empty)) + .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) @@ -183,7 +199,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = _downstreamServiceRootUrl, + DownstreamPathTemplate = _downstreamServicePath, + DownstreamPort = _downstreamServicePort, + DownstreamHost = _downstreamServiceHost, + DownstreamScheme = _downstreamServiceScheme, UpstreamTemplate = "/", UpstreamHttpMethod = "Post", AuthenticationOptions = new FileAuthenticationOptions @@ -200,7 +219,7 @@ namespace Ocelot.AcceptanceTests }; this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", AccessTokenType.Reference)) - .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceRootUrl, 201, string.Empty)) + .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) diff --git a/test/Ocelot.AcceptanceTests/AuthorisationTests.cs b/test/Ocelot.AcceptanceTests/AuthorisationTests.cs index 4ceb03f6..1f86c6ff 100644 --- a/test/Ocelot.AcceptanceTests/AuthorisationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthorisationTests.cs @@ -37,7 +37,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:51876/", + DownstreamPathTemplate = "/", + DownstreamPort = 51876, + DownstreamScheme = "http", + DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", AuthenticationOptions = new FileAuthenticationOptions @@ -91,7 +94,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:51876/", + DownstreamPathTemplate = "/", + DownstreamPort = 51876, + DownstreamScheme = "http", + DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", AuthenticationOptions = new FileAuthenticationOptions diff --git a/test/Ocelot.AcceptanceTests/CachingTests.cs b/test/Ocelot.AcceptanceTests/CachingTests.cs index 34f10b7a..e4e628af 100644 --- a/test/Ocelot.AcceptanceTests/CachingTests.cs +++ b/test/Ocelot.AcceptanceTests/CachingTests.cs @@ -31,7 +31,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:51879/", + DownstreamPathTemplate = "/", + DownstreamPort = 51879, + DownstreamScheme = "http", + DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", FileCacheOptions = new FileCacheOptions @@ -64,7 +67,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:51879/", + DownstreamPathTemplate = "/", + DownstreamPort = 51879, + DownstreamScheme = "http", + DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", FileCacheOptions = new FileCacheOptions diff --git a/test/Ocelot.AcceptanceTests/CaseSensitiveRoutingTests.cs b/test/Ocelot.AcceptanceTests/CaseSensitiveRoutingTests.cs index 81a12381..81824602 100644 --- a/test/Ocelot.AcceptanceTests/CaseSensitiveRoutingTests.cs +++ b/test/Ocelot.AcceptanceTests/CaseSensitiveRoutingTests.cs @@ -30,7 +30,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:51879/api/products/{productId}", + DownstreamPathTemplate = "/api/products/{productId}", + DownstreamPort = 51879, + DownstreamScheme = "http", + DownstreamHost = "localhost", UpstreamTemplate = "/products/{productId}", UpstreamHttpMethod = "Get" } @@ -54,7 +57,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:51879/api/products/{productId}", + DownstreamPathTemplate = "/api/products/{productId}", + DownstreamPort = 51879, + DownstreamScheme = "http", + DownstreamHost = "localhost", UpstreamTemplate = "/products/{productId}", UpstreamHttpMethod = "Get", ReRouteIsCaseSensitive = false @@ -79,7 +85,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:51879/api/products/{productId}", + DownstreamPathTemplate = "/api/products/{productId}", + DownstreamPort = 51879, + DownstreamScheme = "http", + DownstreamHost = "localhost", UpstreamTemplate = "/products/{productId}", UpstreamHttpMethod = "Get", ReRouteIsCaseSensitive = true @@ -104,7 +113,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:51879/api/products/{productId}", + DownstreamPathTemplate = "/api/products/{productId}", + DownstreamPort = 51879, + DownstreamScheme = "http", + DownstreamHost = "localhost", UpstreamTemplate = "/PRODUCTS/{productId}", UpstreamHttpMethod = "Get", ReRouteIsCaseSensitive = true @@ -129,7 +141,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:51879/api/products/{productId}", + DownstreamPathTemplate = "/api/products/{productId}", + DownstreamPort = 51879, + DownstreamScheme = "http", + DownstreamHost = "localhost", UpstreamTemplate = "/products/{productId}", UpstreamHttpMethod = "Get", ReRouteIsCaseSensitive = true @@ -154,7 +169,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:51879/api/products/{productId}", + DownstreamPathTemplate = "/api/products/{productId}", + DownstreamPort = 51879, + DownstreamScheme = "http", + DownstreamHost = "localhost", UpstreamTemplate = "/PRODUCTS/{productId}", UpstreamHttpMethod = "Get", ReRouteIsCaseSensitive = true diff --git a/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs b/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs index 160686d5..08bbd968 100644 --- a/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs +++ b/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs @@ -51,7 +51,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:52876/", + DownstreamPathTemplate = "/", + DownstreamPort = 52876, + DownstreamScheme = "http", + DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", AuthenticationOptions = new FileAuthenticationOptions diff --git a/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs b/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs index 36583018..04dc25db 100644 --- a/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs +++ b/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs @@ -51,7 +51,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:57876/", + DownstreamPathTemplate = "/", + DownstreamPort = 57876, + DownstreamScheme = "http", + DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", AuthenticationOptions = new FileAuthenticationOptions diff --git a/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs b/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs index 1a267a98..f6f6de20 100644 --- a/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs +++ b/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs @@ -45,7 +45,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:41879/", + DownstreamPathTemplate = "/", + DownstreamPort = 41879, + DownstreamScheme = "http", + DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", } @@ -79,7 +82,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:41879/", + DownstreamPathTemplate = "/", + DownstreamPort = 41879, + DownstreamScheme = "http", + DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", } @@ -113,7 +119,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:41879/", + DownstreamPathTemplate = "41879/", + DownstreamPort = 41879, + DownstreamScheme = "http", + DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", } @@ -147,7 +156,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:41879/", + DownstreamPathTemplate = "/", + DownstreamPort = 41879, + DownstreamScheme = "http", + DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", } @@ -181,7 +193,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:41879/", + DownstreamPathTemplate = "/", + DownstreamPort = 41879, + DownstreamScheme = "http", + DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", } @@ -215,7 +230,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:41879/", + DownstreamPathTemplate = "/", + DownstreamPort = 41879, + DownstreamScheme = "http", + DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", } diff --git a/test/Ocelot.AcceptanceTests/RequestIdTests.cs b/test/Ocelot.AcceptanceTests/RequestIdTests.cs index 512736ae..9334786b 100644 --- a/test/Ocelot.AcceptanceTests/RequestIdTests.cs +++ b/test/Ocelot.AcceptanceTests/RequestIdTests.cs @@ -33,7 +33,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:51879/", + DownstreamPathTemplate = "/", + DownstreamPort = 51879, + DownstreamScheme = "http", + DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", RequestIdKey = _steps.RequestIdKey @@ -58,7 +61,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:51879/", + DownstreamPathTemplate = "/", + DownstreamPort = 51879, + DownstreamScheme = "http", + DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", RequestIdKey = _steps.RequestIdKey @@ -85,7 +91,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:51879/", + DownstreamPathTemplate = "/", + DownstreamPort = 51879, + DownstreamScheme = "http", + DownstreamHost = "localhost", UpstreamTemplate = "/", UpstreamHttpMethod = "Get", } diff --git a/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs b/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs index 902de662..81307781 100644 --- a/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs +++ b/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs @@ -29,7 +29,7 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:53876/", + DownstreamPathTemplate = "http://localhost:53876/", UpstreamTemplate = "/", UpstreamHttpMethod = "Get" } diff --git a/test/Ocelot.AcceptanceTests/RoutingTests.cs b/test/Ocelot.AcceptanceTests/RoutingTests.cs index 84e00d5b..4f97114f 100644 --- a/test/Ocelot.AcceptanceTests/RoutingTests.cs +++ b/test/Ocelot.AcceptanceTests/RoutingTests.cs @@ -40,7 +40,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:51879/", + DownstreamPathTemplate = "/", + DownstreamScheme = "http", + DownstreamHost = "localhost", + DownstreamPort = 51879, UpstreamTemplate = "/", UpstreamHttpMethod = "Get", } @@ -56,6 +59,62 @@ namespace Ocelot.AcceptanceTests .BDDfy(); } + [Fact] + public void should_return_response_200_when_path_missing_forward_slash_as_first_char() + { + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = "api/products", + DownstreamScheme = "http", + DownstreamHost = "localhost", + DownstreamPort = 51879, + UpstreamTemplate = "/", + UpstreamHttpMethod = "Get", + } + } + }; + + this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/api/products", 200, "Hello from Laura")) + .And(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunning()) + .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) + .BDDfy(); + } + + [Fact] + public void should_return_response_200_when_host_has_trailing_slash() + { + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = "/api/products", + DownstreamScheme = "http", + DownstreamHost = "localhost/", + DownstreamPort = 51879, + UpstreamTemplate = "/", + UpstreamHttpMethod = "Get", + } + } + }; + + this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/api/products", 200, "Hello from Laura")) + .And(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunning()) + .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) + .BDDfy(); + } + [Fact] public void should_not_care_about_no_trailing() { @@ -65,7 +124,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:51879/products", + DownstreamPathTemplate = "/products", + DownstreamScheme = "http", + DownstreamHost = "localhost", + DownstreamPort = 51879, UpstreamTemplate = "/products/", UpstreamHttpMethod = "Get", } @@ -90,7 +152,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:51879/products", + DownstreamPathTemplate = "/products", + DownstreamScheme = "http", + DownstreamHost = "localhost", + DownstreamPort = 51879, UpstreamTemplate = "/products", UpstreamHttpMethod = "Get", } @@ -115,7 +180,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:51879/products", + DownstreamPathTemplate = "/products", + DownstreamScheme = "http", + DownstreamHost = "localhost", + DownstreamPort = 51879, UpstreamTemplate = "/products/{productId}", UpstreamHttpMethod = "Get", } @@ -139,7 +207,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:51879/api/products/{productId}", + DownstreamPathTemplate = "/api/products/{productId}", + DownstreamScheme = "http", + DownstreamHost = "localhost", + DownstreamPort = 51879, UpstreamTemplate = "/products/{productId}", UpstreamHttpMethod = "Get" } @@ -164,7 +235,10 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:51879/", + DownstreamPathTemplate = "/", + DownstreamHost = "localhost", + DownstreamPort = 51879, + DownstreamScheme = "http", UpstreamTemplate = "/", UpstreamHttpMethod = "Post" } @@ -189,8 +263,11 @@ namespace Ocelot.AcceptanceTests { new FileReRoute { - DownstreamTemplate = "http://localhost:51879/newThing", + DownstreamPathTemplate = "/newThing", UpstreamTemplate = "/newThing", + DownstreamScheme = "http", + DownstreamHost = "localhost", + DownstreamPort = 51879, UpstreamHttpMethod = "Get", } } diff --git a/test/Ocelot.AcceptanceTests/configuration.json b/test/Ocelot.AcceptanceTests/configuration.json index 984f851c..f28abefe 100755 --- a/test/Ocelot.AcceptanceTests/configuration.json +++ b/test/Ocelot.AcceptanceTests/configuration.json @@ -1 +1 @@ -{"ReRoutes":[{"DownstreamTemplate":"http://localhost:41879/","UpstreamTemplate":"/","UpstreamHttpMethod":"Get","AuthenticationOptions":{"Provider":null,"ProviderRootUrl":null,"ScopeName":null,"RequireHttps":false,"AdditionalScopes":[],"ScopeSecret":null},"AddHeadersToRequest":{},"AddClaimsToRequest":{},"RouteClaimsRequirement":{},"AddQueriesToRequest":{},"RequestIdKey":null,"FileCacheOptions":{"TtlSeconds":0},"ReRouteIsCaseSensitive":false}],"GlobalConfiguration":{"RequestIdKey":null}} \ No newline at end of file +{"ReRoutes":[{"DownstreamPathTemplate":"/","UpstreamTemplate":"/","UpstreamHttpMethod":"Get","AuthenticationOptions":{"Provider":null,"ProviderRootUrl":null,"ScopeName":null,"RequireHttps":false,"AdditionalScopes":[],"ScopeSecret":null},"AddHeadersToRequest":{},"AddClaimsToRequest":{},"RouteClaimsRequirement":{},"AddQueriesToRequest":{},"RequestIdKey":null,"FileCacheOptions":{"TtlSeconds":0},"ReRouteIsCaseSensitive":false,"ServiceName":null,"DownstreamScheme":"http","DownstreamHost":"localhost","DownstreamPort":41879}],"GlobalConfiguration":{"RequestIdKey":null,"ServiceDiscoveryProvider":{"Provider":null,"Address":null}}} \ No newline at end of file diff --git a/test/Ocelot.ManualTest/Program.cs b/test/Ocelot.ManualTest/Program.cs index 7b6b8535..a049d3ea 100644 --- a/test/Ocelot.ManualTest/Program.cs +++ b/test/Ocelot.ManualTest/Program.cs @@ -10,7 +10,6 @@ namespace Ocelot.ManualTest var host = new WebHostBuilder() .UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() .UseStartup() .Build(); diff --git a/test/Ocelot.ManualTest/configuration.json b/test/Ocelot.ManualTest/configuration.json index 15276d6e..f7e2bb75 100644 --- a/test/Ocelot.ManualTest/configuration.json +++ b/test/Ocelot.ManualTest/configuration.json @@ -1,7 +1,10 @@ { "ReRoutes": [ { - "DownstreamTemplate": "http://localhost:52876/", + "DownstreamPathTemplate": "/", + "DownstreamScheme": "http", + "DownstreamHost": "localhost", + "DownstreamPort": 52876, "UpstreamTemplate": "/identityserverexample", "UpstreamHttpMethod": "Get", "AuthenticationOptions": { @@ -38,108 +41,165 @@ "RequestIdKey": "OcRequestId" }, { - "DownstreamTemplate": "http://jsonplaceholder.typicode.com/posts", + "DownstreamPathTemplate": "/posts", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, "UpstreamTemplate": "/posts", "UpstreamHttpMethod": "Get", "FileCacheOptions": { "TtlSeconds": 15 } }, { - "DownstreamTemplate": "http://jsonplaceholder.typicode.com/posts/{postId}", + "DownstreamPathTemplate": "/posts/{postId}", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, "UpstreamTemplate": "/posts/{postId}", "UpstreamHttpMethod": "Get" }, { - "DownstreamTemplate": "http://jsonplaceholder.typicode.com/posts/{postId}/comments", + "DownstreamPathTemplate": "/posts/{postId}/comments", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, "UpstreamTemplate": "/posts/{postId}/comments", "UpstreamHttpMethod": "Get" }, { - "DownstreamTemplate": "http://jsonplaceholder.typicode.com/comments", + "DownstreamPathTemplate": "/comments", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, "UpstreamTemplate": "/comments", "UpstreamHttpMethod": "Get" }, { - "DownstreamTemplate": "http://jsonplaceholder.typicode.com/posts", + "DownstreamPathTemplate": "/posts", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, "UpstreamTemplate": "/posts", "UpstreamHttpMethod": "Post" }, { - "DownstreamTemplate": "http://jsonplaceholder.typicode.com/posts/{postId}", + "DownstreamPathTemplate": "/posts/{postId}", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, "UpstreamTemplate": "/posts/{postId}", "UpstreamHttpMethod": "Put" }, { - "DownstreamTemplate": "http://jsonplaceholder.typicode.com/posts/{postId}", + "DownstreamPathTemplate": "/posts/{postId}", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, "UpstreamTemplate": "/posts/{postId}", "UpstreamHttpMethod": "Patch" }, { - "DownstreamTemplate": "http://jsonplaceholder.typicode.com/posts/{postId}", + "DownstreamPathTemplate": "/posts/{postId}", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, "UpstreamTemplate": "/posts/{postId}", "UpstreamHttpMethod": "Delete" }, { - "DownstreamTemplate": "http://products20161126090340.azurewebsites.net/api/products", + "DownstreamPathTemplate": "/api/products", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, "UpstreamTemplate": "/products", "UpstreamHttpMethod": "Get", "FileCacheOptions": { "TtlSeconds": 15 } }, { - "DownstreamTemplate": "http://products20161126090340.azurewebsites.net/api/products/{productId}", + "DownstreamPathTemplate": "/api/products/{productId}", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, "UpstreamTemplate": "/products/{productId}", "UpstreamHttpMethod": "Get", "FileCacheOptions": { "TtlSeconds": 15 } }, { - "DownstreamTemplate": "http://products20161126090340.azurewebsites.net/api/products", + "DownstreamPathTemplate": "/api/products", + "DownstreamScheme": "http", + "DownstreamHost": "products20161126090340.azurewebsites.net", + "DownstreamPort": 80, "UpstreamTemplate": "/products", "UpstreamHttpMethod": "Post", "FileCacheOptions": { "TtlSeconds": 15 } }, { - "DownstreamTemplate": "http://products20161126090340.azurewebsites.net/api/products/{productId}", + "DownstreamPathTemplate": "/api/products/{productId}", + "DownstreamScheme": "http", + "DownstreamHost": "products20161126090340.azurewebsites.net", + "DownstreamPort": 80, "UpstreamTemplate": "/products/{productId}", "UpstreamHttpMethod": "Put", "FileCacheOptions": { "TtlSeconds": 15 } }, { - "DownstreamTemplate": "http://products20161126090340.azurewebsites.net/api/products/{productId}", + "DownstreamPathTemplate": "/api/products/{productId}", + "DownstreamScheme": "http", + "DownstreamHost": "products20161126090340.azurewebsites.net", + "DownstreamPort": 80, "UpstreamTemplate": "/products/{productId}", "UpstreamHttpMethod": "Delete", "FileCacheOptions": { "TtlSeconds": 15 } }, { - "DownstreamTemplate": "http://customers20161126090811.azurewebsites.net/api/customers", + "DownstreamPathTemplate": "/api/customers", + "DownstreamScheme": "http", + "DownstreamHost": "customers20161126090811.azurewebsites.net", + "DownstreamPort": 80, "UpstreamTemplate": "/customers", "UpstreamHttpMethod": "Get", "FileCacheOptions": { "TtlSeconds": 15 } }, { - "DownstreamTemplate": "http://customers20161126090811.azurewebsites.net/api/customers/{customerId}", + "DownstreamPathTemplate": "/api/customers/{customerId}", + "DownstreamScheme": "http", + "DownstreamHost": "customers20161126090811.azurewebsites.net", + "DownstreamPort": 80, "UpstreamTemplate": "/customers/{customerId}", "UpstreamHttpMethod": "Get", "FileCacheOptions": { "TtlSeconds": 15 } }, { - "DownstreamTemplate": "http://customers20161126090811.azurewebsites.net/api/customers", + "DownstreamPathTemplate": "/api/customers", + "DownstreamScheme": "http", + "DownstreamHost": "customers20161126090811.azurewebsites.net", + "DownstreamPort": 80, "UpstreamTemplate": "/customers", "UpstreamHttpMethod": "Post", "FileCacheOptions": { "TtlSeconds": 15 } }, { - "DownstreamTemplate": "http://customers20161126090811.azurewebsites.net/api/customers/{customerId}", + "DownstreamPathTemplate": "/api/customers/{customerId}", + "DownstreamScheme": "http", + "DownstreamHost": "customers20161126090811.azurewebsites.net", + "DownstreamPort": 80, "UpstreamTemplate": "/customers/{customerId}", "UpstreamHttpMethod": "Put", "FileCacheOptions": { "TtlSeconds": 15 } }, { - "DownstreamTemplate": "http://customers20161126090811.azurewebsites.net/api/customers/{customerId}", + "DownstreamPathTemplate": "/api/customers/{customerId}", + "DownstreamScheme": "http", + "DownstreamHost": "customers20161126090811.azurewebsites.net", + "DownstreamPort": 80, "UpstreamTemplate": "/customers/{customerId}", "UpstreamHttpMethod": "Delete", "FileCacheOptions": { "TtlSeconds": 15 } }, { - "DownstreamTemplate": "http://jsonplaceholder.typicode.com/posts", + "DownstreamPathTemplate": "/posts", + "DownstreamScheme": "http", + "DownstreamHost": "jsonplaceholder.typicode.com", + "DownstreamPort": 80, "UpstreamTemplate": "/posts/", "UpstreamHttpMethod": "Get", "FileCacheOptions": { "TtlSeconds": 15 } diff --git a/test/Ocelot.UnitTests/Claims/ClaimsBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/Claims/ClaimsBuilderMiddlewareTests.cs index e3cccdc0..8822e6b2 100644 --- a/test/Ocelot.UnitTests/Claims/ClaimsBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Claims/ClaimsBuilderMiddlewareTests.cs @@ -67,7 +67,7 @@ namespace Ocelot.UnitTests.Claims { var downstreamRoute = new DownstreamRoute(new List(), new ReRouteBuilder() - .WithDownstreamTemplate("any old string") + .WithDownstreamPathTemplate("any old string") .WithClaimsToClaims(new List { new ClaimToThing("sub", "UserType", "|", 0) diff --git a/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs b/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs index 174ea8bc..8a3e24f9 100644 --- a/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs +++ b/test/Ocelot.UnitTests/Configuration/ConfigurationValidationTests.cs @@ -10,8 +10,8 @@ namespace Ocelot.UnitTests.Configuration { public class ConfigurationValidationTests { - private FileConfiguration _fileConfiguration; private readonly IConfigurationValidator _configurationValidator; + private FileConfiguration _fileConfiguration; private Response _result; public ConfigurationValidationTests() @@ -22,32 +22,13 @@ namespace Ocelot.UnitTests.Configuration [Fact] public void configuration_is_invalid_if_scheme_in_downstream_template() { - this.Given(x => x.GivenAConfiguration(new FileConfiguration() + this.Given(x => x.GivenAConfiguration(new FileConfiguration { ReRoutes = new List { new FileReRoute { - DownstreamTemplate = "http://www.bbc.co.uk/api/products/{productId}", - UpstreamTemplate = "http://asdf.com" - } - } - })) - .When(x => x.WhenIValidateTheConfiguration()) - .Then(x => x.ThenTheResultIsNotValid()) - .BDDfy(); - } - - [Fact] - public void configuration_is_invalid_if_host_in_downstream_template() - { - this.Given(x => x.GivenAConfiguration(new FileConfiguration() - { - ReRoutes = new List - { - new FileReRoute - { - DownstreamTemplate = "www.bbc.co.uk/api/products/{productId}", + DownstreamPathTemplate = "http://www.bbc.co.uk/api/products/{productId}", UpstreamTemplate = "http://asdf.com" } } @@ -60,13 +41,13 @@ namespace Ocelot.UnitTests.Configuration [Fact] public void configuration_is_valid_with_one_reroute() { - this.Given(x => x.GivenAConfiguration(new FileConfiguration() + this.Given(x => x.GivenAConfiguration(new FileConfiguration { ReRoutes = new List { new FileReRoute { - DownstreamTemplate = "/api/products/", + DownstreamPathTemplate = "/api/products/", UpstreamTemplate = "http://asdf.com" } } @@ -79,13 +60,13 @@ namespace Ocelot.UnitTests.Configuration [Fact] public void configuration_is_valid_with_valid_authentication_provider() { - this.Given(x => x.GivenAConfiguration(new FileConfiguration() + this.Given(x => x.GivenAConfiguration(new FileConfiguration { ReRoutes = new List { new FileReRoute { - DownstreamTemplate = "/api/products/", + DownstreamPathTemplate = "/api/products/", UpstreamTemplate = "http://asdf.com", AuthenticationOptions = new FileAuthenticationOptions { @@ -102,13 +83,13 @@ namespace Ocelot.UnitTests.Configuration [Fact] public void configuration_is_invalid_with_invalid_authentication_provider() { - this.Given(x => x.GivenAConfiguration(new FileConfiguration() + this.Given(x => x.GivenAConfiguration(new FileConfiguration { ReRoutes = new List { new FileReRoute { - DownstreamTemplate = "/api/products/", + DownstreamPathTemplate = "/api/products/", UpstreamTemplate = "http://asdf.com", AuthenticationOptions = new FileAuthenticationOptions { @@ -126,25 +107,25 @@ namespace Ocelot.UnitTests.Configuration [Fact] public void configuration_is_not_valid_with_duplicate_reroutes() { - this.Given(x => x.GivenAConfiguration(new FileConfiguration() + this.Given(x => x.GivenAConfiguration(new FileConfiguration { ReRoutes = new List { new FileReRoute { - DownstreamTemplate = "/api/products/", + DownstreamPathTemplate = "/api/products/", UpstreamTemplate = "http://asdf.com" }, new FileReRoute { - DownstreamTemplate = "http://www.bbc.co.uk", + DownstreamPathTemplate = "http://www.bbc.co.uk", UpstreamTemplate = "http://asdf.com" } } })) .When(x => x.WhenIValidateTheConfiguration()) .Then(x => x.ThenTheResultIsNotValid()) - .And(x => x.ThenTheErrorIs()) + .And(x => x.ThenTheErrorIs()) .BDDfy(); } @@ -173,4 +154,4 @@ namespace Ocelot.UnitTests.Configuration _result.Data.Errors[0].ShouldBeOfType(); } } -} +} \ No newline at end of file diff --git a/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs index 4207a333..fc80a478 100644 --- a/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs @@ -46,7 +46,7 @@ namespace Ocelot.UnitTests.Configuration { DownstreamHost = "127.0.0.1", UpstreamTemplate = "/api/products/{productId}", - DownstreamTemplate = "/products/{productId}", + DownstreamPathTemplate = "/products/{productId}", UpstreamHttpMethod = "Get", } }, @@ -57,7 +57,7 @@ namespace Ocelot.UnitTests.Configuration { new ReRouteBuilder() .WithDownstreamHost("127.0.0.1") - .WithDownstreamTemplate("/products/{productId}") + .WithDownstreamPathTemplate("/products/{productId}") .WithUpstreamTemplate("/api/products/{productId}") .WithUpstreamHttpMethod("Get") .WithUpstreamTemplatePattern("(?i)/api/products/.*/$") @@ -76,7 +76,7 @@ namespace Ocelot.UnitTests.Configuration { DownstreamScheme = "https", UpstreamTemplate = "/api/products/{productId}", - DownstreamTemplate = "/products/{productId}", + DownstreamPathTemplate = "/products/{productId}", UpstreamHttpMethod = "Get", } }, @@ -87,7 +87,7 @@ namespace Ocelot.UnitTests.Configuration { new ReRouteBuilder() .WithDownstreamScheme("https") - .WithDownstreamTemplate("/products/{productId}") + .WithDownstreamPathTemplate("/products/{productId}") .WithUpstreamTemplate("/api/products/{productId}") .WithUpstreamHttpMethod("Get") .WithUpstreamTemplatePattern("(?i)/api/products/.*/$") @@ -106,7 +106,7 @@ namespace Ocelot.UnitTests.Configuration new FileReRoute { UpstreamTemplate = "/api/products/{productId}", - DownstreamTemplate = "/products/{productId}", + DownstreamPathTemplate = "/products/{productId}", UpstreamHttpMethod = "Get", ReRouteIsCaseSensitive = false, ServiceName = "ProductService" @@ -126,7 +126,7 @@ namespace Ocelot.UnitTests.Configuration .Then(x => x.ThenTheReRoutesAre(new List { new ReRouteBuilder() - .WithDownstreamTemplate("/products/{productId}") + .WithDownstreamPathTemplate("/products/{productId}") .WithUpstreamTemplate("/api/products/{productId}") .WithUpstreamHttpMethod("Get") .WithUpstreamTemplatePattern("(?i)/api/products/.*/$") @@ -149,7 +149,7 @@ namespace Ocelot.UnitTests.Configuration new FileReRoute { UpstreamTemplate = "/api/products/{productId}", - DownstreamTemplate = "/products/{productId}", + DownstreamPathTemplate = "/products/{productId}", UpstreamHttpMethod = "Get", ReRouteIsCaseSensitive = false, } @@ -160,7 +160,7 @@ namespace Ocelot.UnitTests.Configuration .Then(x => x.ThenTheReRoutesAre(new List { new ReRouteBuilder() - .WithDownstreamTemplate("/products/{productId}") + .WithDownstreamPathTemplate("/products/{productId}") .WithUpstreamTemplate("/api/products/{productId}") .WithUpstreamHttpMethod("Get") .WithUpstreamTemplatePattern("(?i)/api/products/.*/$") @@ -182,7 +182,7 @@ namespace Ocelot.UnitTests.Configuration new FileReRoute { UpstreamTemplate = "/api/products/{productId}", - DownstreamTemplate = "/products/{productId}", + DownstreamPathTemplate = "/products/{productId}", UpstreamHttpMethod = "Get", ReRouteIsCaseSensitive = false } @@ -193,7 +193,7 @@ namespace Ocelot.UnitTests.Configuration .Then(x => x.ThenTheReRoutesAre(new List { new ReRouteBuilder() - .WithDownstreamTemplate("/products/{productId}") + .WithDownstreamPathTemplate("/products/{productId}") .WithUpstreamTemplate("/api/products/{productId}") .WithUpstreamHttpMethod("Get") .WithUpstreamTemplatePattern("(?i)/api/products/.*/$") @@ -212,7 +212,7 @@ namespace Ocelot.UnitTests.Configuration new FileReRoute { UpstreamTemplate = "/api/products/{productId}", - DownstreamTemplate = "/products/{productId}", + DownstreamPathTemplate = "/products/{productId}", UpstreamHttpMethod = "Get" } } @@ -222,7 +222,7 @@ namespace Ocelot.UnitTests.Configuration .Then(x => x.ThenTheReRoutesAre(new List { new ReRouteBuilder() - .WithDownstreamTemplate("/products/{productId}") + .WithDownstreamPathTemplate("/products/{productId}") .WithUpstreamTemplate("/api/products/{productId}") .WithUpstreamHttpMethod("Get") .WithUpstreamTemplatePattern("(?i)/api/products/.*/$") @@ -241,7 +241,7 @@ namespace Ocelot.UnitTests.Configuration new FileReRoute { UpstreamTemplate = "/api/products/{productId}", - DownstreamTemplate = "/products/{productId}", + DownstreamPathTemplate = "/products/{productId}", UpstreamHttpMethod = "Get", ReRouteIsCaseSensitive = true } @@ -252,7 +252,7 @@ namespace Ocelot.UnitTests.Configuration .Then(x => x.ThenTheReRoutesAre(new List { new ReRouteBuilder() - .WithDownstreamTemplate("/products/{productId}") + .WithDownstreamPathTemplate("/products/{productId}") .WithUpstreamTemplate("/api/products/{productId}") .WithUpstreamHttpMethod("Get") .WithUpstreamTemplatePattern("/api/products/.*/$") @@ -271,7 +271,7 @@ namespace Ocelot.UnitTests.Configuration new FileReRoute { UpstreamTemplate = "/api/products/{productId}", - DownstreamTemplate = "/products/{productId}", + DownstreamPathTemplate = "/products/{productId}", UpstreamHttpMethod = "Get", ReRouteIsCaseSensitive = true } @@ -286,7 +286,7 @@ namespace Ocelot.UnitTests.Configuration .Then(x => x.ThenTheReRoutesAre(new List { new ReRouteBuilder() - .WithDownstreamTemplate("/products/{productId}") + .WithDownstreamPathTemplate("/products/{productId}") .WithUpstreamTemplate("/api/products/{productId}") .WithUpstreamHttpMethod("Get") .WithUpstreamTemplatePattern("/api/products/.*/$") @@ -306,7 +306,7 @@ namespace Ocelot.UnitTests.Configuration new FileReRoute { UpstreamTemplate = "/api/products/{productId}", - DownstreamTemplate = "/products/{productId}", + DownstreamPathTemplate = "/products/{productId}", UpstreamHttpMethod = "Get", ReRouteIsCaseSensitive = true } @@ -317,7 +317,7 @@ namespace Ocelot.UnitTests.Configuration .Then(x => x.ThenTheReRoutesAre(new List { new ReRouteBuilder() - .WithDownstreamTemplate("/products/{productId}") + .WithDownstreamPathTemplate("/products/{productId}") .WithUpstreamTemplate("/api/products/{productId}") .WithUpstreamHttpMethod("Get") .WithUpstreamTemplatePattern("/api/products/.*/$") @@ -332,7 +332,7 @@ namespace Ocelot.UnitTests.Configuration var expected = new List { new ReRouteBuilder() - .WithDownstreamTemplate("/products/{productId}") + .WithDownstreamPathTemplate("/products/{productId}") .WithUpstreamTemplate("/api/products/{productId}") .WithUpstreamHttpMethod("Get") .WithUpstreamTemplatePattern("/api/products/.*/$") @@ -355,7 +355,7 @@ namespace Ocelot.UnitTests.Configuration new FileReRoute { UpstreamTemplate = "/api/products/{productId}", - DownstreamTemplate = "/products/{productId}", + DownstreamPathTemplate = "/products/{productId}", UpstreamHttpMethod = "Get", ReRouteIsCaseSensitive = true, AuthenticationOptions = new FileAuthenticationOptions @@ -395,7 +395,7 @@ namespace Ocelot.UnitTests.Configuration var expected = new List { new ReRouteBuilder() - .WithDownstreamTemplate("/products/{productId}") + .WithDownstreamPathTemplate("/products/{productId}") .WithUpstreamTemplate("/api/products/{productId}") .WithUpstreamHttpMethod("Get") .WithUpstreamTemplatePattern("/api/products/.*/$") @@ -414,7 +414,7 @@ namespace Ocelot.UnitTests.Configuration new FileReRoute { UpstreamTemplate = "/api/products/{productId}", - DownstreamTemplate = "/products/{productId}", + DownstreamPathTemplate = "/products/{productId}", UpstreamHttpMethod = "Get", ReRouteIsCaseSensitive = true, AuthenticationOptions = new FileAuthenticationOptions @@ -446,7 +446,7 @@ namespace Ocelot.UnitTests.Configuration new FileReRoute { UpstreamTemplate = "/api/products/{productId}/variants/{variantId}", - DownstreamTemplate = "/products/{productId}", + DownstreamPathTemplate = "/products/{productId}", UpstreamHttpMethod = "Get", ReRouteIsCaseSensitive = true } @@ -457,7 +457,7 @@ namespace Ocelot.UnitTests.Configuration .Then(x => x.ThenTheReRoutesAre(new List { new ReRouteBuilder() - .WithDownstreamTemplate("/products/{productId}") + .WithDownstreamPathTemplate("/products/{productId}") .WithUpstreamTemplate("/api/products/{productId}/variants/{variantId}") .WithUpstreamHttpMethod("Get") .WithUpstreamTemplatePattern("/api/products/.*/variants/.*/$") @@ -476,7 +476,7 @@ namespace Ocelot.UnitTests.Configuration new FileReRoute { UpstreamTemplate = "/api/products/{productId}/variants/{variantId}/", - DownstreamTemplate = "/products/{productId}", + DownstreamPathTemplate = "/products/{productId}", UpstreamHttpMethod = "Get", ReRouteIsCaseSensitive = true } @@ -487,7 +487,7 @@ namespace Ocelot.UnitTests.Configuration .Then(x => x.ThenTheReRoutesAre(new List { new ReRouteBuilder() - .WithDownstreamTemplate("/products/{productId}") + .WithDownstreamPathTemplate("/products/{productId}") .WithUpstreamTemplate("/api/products/{productId}/variants/{variantId}/") .WithUpstreamHttpMethod("Get") .WithUpstreamTemplatePattern("/api/products/.*/variants/.*/$") @@ -506,7 +506,7 @@ namespace Ocelot.UnitTests.Configuration new FileReRoute { UpstreamTemplate = "/", - DownstreamTemplate = "/api/products/", + DownstreamPathTemplate = "/api/products/", UpstreamHttpMethod = "Get", ReRouteIsCaseSensitive = true } @@ -517,7 +517,7 @@ namespace Ocelot.UnitTests.Configuration .Then(x => x.ThenTheReRoutesAre(new List { new ReRouteBuilder() - .WithDownstreamTemplate("/api/products/") + .WithDownstreamPathTemplate("/api/products/") .WithUpstreamTemplate("/") .WithUpstreamHttpMethod("Get") .WithUpstreamTemplatePattern("/$") @@ -553,7 +553,7 @@ namespace Ocelot.UnitTests.Configuration var result = _config.Data.ReRoutes[i]; var expected = expectedReRoutes[i]; - result.DownstreamTemplate.ShouldBe(expected.DownstreamTemplate); + result.DownstreamPathTemplate.Value.ShouldBe(expected.DownstreamPathTemplate.Value); result.UpstreamHttpMethod.ShouldBe(expected.UpstreamHttpMethod); result.UpstreamTemplate.ShouldBe(expected.UpstreamTemplate); result.UpstreamTemplatePattern.ShouldBe(expected.UpstreamTemplatePattern); diff --git a/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs b/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs index 8f7af24e..ec46f914 100644 --- a/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs +++ b/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs @@ -44,7 +44,7 @@ namespace Ocelot.UnitTests.Configuration private void ThenTheConfigurationIsReturned() { - _getResult.Data.ReRoutes[0].DownstreamTemplate.ShouldBe("initial"); + _getResult.Data.ReRoutes[0].DownstreamPathTemplate.Value.ShouldBe("initial"); } private void WhenIGetTheConfiguration() @@ -75,16 +75,16 @@ namespace Ocelot.UnitTests.Configuration class FakeConfig : IOcelotConfiguration { - private readonly string _downstreamTemplate; + private readonly string _downstreamTemplatePath; - public FakeConfig(string downstreamTemplate) + public FakeConfig(string downstreamTemplatePath) { - _downstreamTemplate = downstreamTemplate; + _downstreamTemplatePath = downstreamTemplatePath; } public List ReRoutes => new List { - new ReRouteBuilder().WithDownstreamTemplate(_downstreamTemplate).Build() + new ReRouteBuilder().WithDownstreamPathTemplate(_downstreamTemplatePath).Build() }; } } diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs index 22dfea80..0d5a6d48 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs @@ -61,7 +61,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder [Fact] public void should_call_scoped_data_repository_correctly() { - this.Given(x => x.GivenTheDownStreamRouteFinderReturns(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamTemplate("any old string").Build()))) + this.Given(x => x.GivenTheDownStreamRouteFinderReturns(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamPathTemplate("any old string").Build()))) .When(x => x.WhenICallTheMiddleware()) .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) .BDDfy(); diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs index bb390d32..c0afca42 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderTests.cs @@ -44,7 +44,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .And(x => x.GivenTheConfigurationIs(new List { new ReRouteBuilder() - .WithDownstreamTemplate("someDownstreamPath") + .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamTemplate("someUpstreamPath") .WithUpstreamHttpMethod("Get") .WithUpstreamTemplatePattern("someUpstreamPath") @@ -57,7 +57,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .Then( x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), new ReRouteBuilder() - .WithDownstreamTemplate("someDownstreamPath") + .WithDownstreamPathTemplate("someDownstreamPath") .Build() ))) .And(x => x.ThenTheUrlMatcherIsCalledCorrectly()) @@ -75,13 +75,13 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .And(x => x.GivenTheConfigurationIs(new List { new ReRouteBuilder() - .WithDownstreamTemplate("someDownstreamPath") + .WithDownstreamPathTemplate("someDownstreamPath") .WithUpstreamTemplate("someUpstreamPath") .WithUpstreamHttpMethod("Get") .WithUpstreamTemplatePattern("") .Build(), new ReRouteBuilder() - .WithDownstreamTemplate("someDownstreamPathForAPost") + .WithDownstreamPathTemplate("someDownstreamPathForAPost") .WithUpstreamTemplate("someUpstreamPath") .WithUpstreamHttpMethod("Post") .WithUpstreamTemplatePattern("") @@ -94,7 +94,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .Then( x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List(), new ReRouteBuilder() - .WithDownstreamTemplate("someDownstreamPathForAPost") + .WithDownstreamPathTemplate("someDownstreamPathForAPost") .Build() ))) .BDDfy(); @@ -107,7 +107,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .And(x => x.GivenTheConfigurationIs(new List { new ReRouteBuilder() - .WithDownstreamTemplate("somPath") + .WithDownstreamPathTemplate("somPath") .WithUpstreamTemplate("somePath") .WithUpstreamHttpMethod("Get") .WithUpstreamTemplatePattern("somePath") @@ -174,7 +174,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder private void ThenTheFollowingIsReturned(DownstreamRoute expected) { - _result.Data.ReRoute.DownstreamTemplate.ShouldBe(expected.ReRoute.DownstreamTemplate); + _result.Data.ReRoute.DownstreamPathTemplate.Value.ShouldBe(expected.ReRoute.DownstreamPathTemplate.Value); for (int i = 0; i < _result.Data.TemplatePlaceholderNameAndValues.Count; i++) { diff --git a/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs b/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs index 98bc5f0b..5581a32e 100644 --- a/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs @@ -7,15 +7,18 @@ using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Moq; +using Ocelot.Configuration; using Ocelot.Configuration.Builder; using Ocelot.DownstreamRouteFinder; using Ocelot.DownstreamRouteFinder.Middleware; using Ocelot.DownstreamRouteFinder.UrlMatcher; +using Ocelot.DownstreamUrlCreator; using Ocelot.DownstreamUrlCreator.Middleware; using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer; using Ocelot.Infrastructure.RequestData; using Ocelot.Logging; using Ocelot.Responses; +using Ocelot.Values; using TestStack.BDDfy; using Xunit; @@ -23,21 +26,23 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator { public class DownstreamUrlCreatorMiddlewareTests : IDisposable { - private readonly Mock _downstreamUrlTemplateVariableReplacer; + private readonly Mock _downstreamUrlTemplateVariableReplacer; private readonly Mock _scopedRepository; + private readonly Mock _urlBuilder; private readonly string _url; private readonly TestServer _server; private readonly HttpClient _client; private Response _downstreamRoute; private HttpResponseMessage _result; + private OkResponse _downstreamPath; private OkResponse _downstreamUrl; public DownstreamUrlCreatorMiddlewareTests() { _url = "http://localhost:51879"; - _downstreamUrlTemplateVariableReplacer = new Mock(); + _downstreamUrlTemplateVariableReplacer = new Mock(); _scopedRepository = new Mock(); - + _urlBuilder = new Mock(); var builder = new WebHostBuilder() .ConfigureServices(x => { @@ -45,6 +50,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator x.AddLogging(); x.AddSingleton(_downstreamUrlTemplateVariableReplacer.Object); x.AddSingleton(_scopedRepository.Object); + x.AddSingleton(_urlBuilder.Object); }) .UseUrls(_url) .UseKestrel() @@ -61,21 +67,30 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator } [Fact] - public void should_call_scoped_data_repository_correctly() + public void should_call_dependencies_correctly() { - this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamTemplate("any old string").Build()))) - .And(x => x.TheUrlReplacerReturns("any old string")) + this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamPathTemplate("any old string").Build()))) + .And(x => x.TheUrlReplacerReturns("/api/products/1")) + .And(x => x.TheUrlBuilderReturns("http://www.bbc.co.uk/api/products/1")) .When(x => x.WhenICallTheMiddleware()) .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) .BDDfy(); } + private void TheUrlBuilderReturns(string dsUrl) + { + _downstreamUrl = new OkResponse(new DownstreamUrl(dsUrl)); + _urlBuilder + .Setup(x => x.Build(It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(_downstreamUrl); + } + private void TheUrlReplacerReturns(string downstreamUrl) { - _downstreamUrl = new OkResponse(new DownstreamUrl(downstreamUrl)); + _downstreamPath = new OkResponse(new DownstreamPath(downstreamUrl)); _downstreamUrlTemplateVariableReplacer - .Setup(x => x.Replace(It.IsAny(), It.IsAny>())) - .Returns(_downstreamUrl); + .Setup(x => x.Replace(It.IsAny(), It.IsAny>())) + .Returns(_downstreamPath); } private void ThenTheScopedDataRepositoryIsCalledCorrectly() diff --git a/test/Ocelot.UnitTests/DownstreamUrlCreator/UrlBuilderTests.cs b/test/Ocelot.UnitTests/DownstreamUrlCreator/UrlBuilderTests.cs new file mode 100644 index 00000000..7e512798 --- /dev/null +++ b/test/Ocelot.UnitTests/DownstreamUrlCreator/UrlBuilderTests.cs @@ -0,0 +1,124 @@ +using System; +using Ocelot.Configuration; +using Ocelot.DownstreamUrlCreator; +using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer; +using Ocelot.Responses; +using Ocelot.Values; +using Shouldly; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests.DownstreamUrlCreator +{ + public class UrlBuilderTests + { + private readonly IUrlBuilder _urlBuilder; + private string _dsPath; + private string _dsScheme; + private string _dsHost; + private int _dsPort; + + private Response _result; + + public UrlBuilderTests() + { + _urlBuilder = new UrlBuilder(); + } + + [Fact] + public void should_return_error_when_downstream_path_is_null() + { + this.Given(x => x.GivenADownstreamPath(null)) + .When(x => x.WhenIBuildTheUrl()) + .Then(x => x.ThenThereIsAnErrorOfType()) + .BDDfy(); + } + + [Fact] + public void should_return_error_when_downstream_scheme_is_null() + { + this.Given(x => x.GivenADownstreamScheme(null)) + .And(x => x.GivenADownstreamPath("test")) + .When(x => x.WhenIBuildTheUrl()) + .Then(x => x.ThenThereIsAnErrorOfType()) + .BDDfy(); + } + + [Fact] + public void should_return_error_when_downstream_host_is_null() + { + this.Given(x => x.GivenADownstreamScheme(null)) + .And(x => x.GivenADownstreamPath("test")) + .And(x => x.GivenADownstreamScheme("test")) + .When(x => x.WhenIBuildTheUrl()) + .Then(x => x.ThenThereIsAnErrorOfType()) + .BDDfy(); + } + + [Fact] + public void should_not_use_port_if_zero() + { + this.Given(x => x.GivenADownstreamPath("/api/products/1")) + .And(x => x.GivenADownstreamScheme("http")) + .And(x => x.GivenADownstreamHost("127.0.0.1")) + .And(x => x.GivenADownstreamPort(0)) + .When(x => x.WhenIBuildTheUrl()) + .Then(x => x.ThenTheUrlIsReturned("http://127.0.0.1/api/products/1")) + .And(x => x.ThenTheUrlIsWellFormed()) + .BDDfy(); + } + + [Fact] + public void should_build_well_formed_uri() + { + this.Given(x => x.GivenADownstreamPath("/api/products/1")) + .And(x => x.GivenADownstreamScheme("http")) + .And(x => x.GivenADownstreamHost("127.0.0.1")) + .And(x => x.GivenADownstreamPort(5000)) + .When(x => x.WhenIBuildTheUrl()) + .Then(x => x.ThenTheUrlIsReturned("http://127.0.0.1:5000/api/products/1")) + .And(x => x.ThenTheUrlIsWellFormed()) + .BDDfy(); + } + + private void ThenThereIsAnErrorOfType() + { + _result.Errors[0].ShouldBeOfType(); + } + + private void GivenADownstreamPath(string dsPath) + { + _dsPath = dsPath; + } + + private void GivenADownstreamScheme(string dsScheme) + { + _dsScheme = dsScheme; + } + + private void GivenADownstreamHost(string dsHost) + { + _dsHost = dsHost; + } + + private void GivenADownstreamPort(int dsPort) + { + _dsPort = dsPort; + } + + private void WhenIBuildTheUrl() + { + _result = _urlBuilder.Build(_dsPath, _dsScheme, new HostAndPort(_dsHost, _dsPort)); + } + + private void ThenTheUrlIsReturned(string expected) + { + _result.Data.Value.ShouldBe(expected); + } + + private void ThenTheUrlIsWellFormed() + { + Uri.IsWellFormedUriString(_result.Data.Value, UriKind.Absolute).ShouldBeTrue(); + } + } +} diff --git a/test/Ocelot.UnitTests/DownstreamUrlCreator/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs b/test/Ocelot.UnitTests/DownstreamUrlCreator/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs index b1ad369b..a7a5a89b 100644 --- a/test/Ocelot.UnitTests/DownstreamUrlCreator/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs +++ b/test/Ocelot.UnitTests/DownstreamUrlCreator/UrlTemplateReplacer/UpstreamUrlPathTemplateVariableReplacerTests.cs @@ -4,6 +4,7 @@ using Ocelot.DownstreamRouteFinder; using Ocelot.DownstreamRouteFinder.UrlMatcher; using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer; using Ocelot.Responses; +using Ocelot.Values; using Shouldly; using TestStack.BDDfy; using Xunit; @@ -13,12 +14,12 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer public class UpstreamUrlPathTemplateVariableReplacerTests { private DownstreamRoute _downstreamRoute; - private Response _result; - private readonly IDownstreamUrlPathPlaceholderReplacer _downstreamUrlPathReplacer; + private Response _result; + private readonly IDownstreamPathPlaceholderReplacer _downstreamPathReplacer; public UpstreamUrlPathTemplateVariableReplacerTests() { - _downstreamUrlPathReplacer = new DownstreamUrlPathPlaceholderReplacer(); + _downstreamPathReplacer = new DownstreamTemplatePathPlaceholderReplacer(); } [Fact] @@ -33,7 +34,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer [Fact] public void can_replace_no_template_variables_with_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamTemplate("/").Build()))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamPathTemplate("/").Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("/")) .BDDfy(); @@ -42,7 +43,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer [Fact] public void can_replace_url_no_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamTemplate("api").Build()))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamPathTemplate("api").Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api")) .BDDfy(); @@ -51,7 +52,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer [Fact] public void can_replace_url_one_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamTemplate("api/").Build()))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamPathTemplate("api/").Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/")) .BDDfy(); @@ -60,7 +61,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer [Fact] public void can_replace_url_multiple_slash() { - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamTemplate("api/product/products/").Build()))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List(), new ReRouteBuilder().WithDownstreamPathTemplate("api/product/products/").Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/product/products/")) .BDDfy(); @@ -74,7 +75,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer new UrlPathPlaceholderNameAndValue("{productId}", "1") }; - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRouteBuilder().WithDownstreamTemplate("productservice/products/{productId}/").Build()))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRouteBuilder().WithDownstreamPathTemplate("productservice/products/{productId}/").Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/")) .BDDfy(); @@ -88,7 +89,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer new UrlPathPlaceholderNameAndValue("{productId}", "1") }; - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRouteBuilder().WithDownstreamTemplate("productservice/products/{productId}/variants").Build()))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRouteBuilder().WithDownstreamPathTemplate("productservice/products/{productId}/variants").Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants")) .BDDfy(); @@ -103,7 +104,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer new UrlPathPlaceholderNameAndValue("{variantId}", "12") }; - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRouteBuilder().WithDownstreamTemplate("productservice/products/{productId}/variants/{variantId}").Build()))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRouteBuilder().WithDownstreamPathTemplate("productservice/products/{productId}/variants/{variantId}").Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants/12")) .BDDfy(); @@ -119,7 +120,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer new UrlPathPlaceholderNameAndValue("{categoryId}", "34") }; - this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRouteBuilder().WithDownstreamTemplate("productservice/category/{categoryId}/products/{productId}/variants/{variantId}").Build()))) + this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables, new ReRouteBuilder().WithDownstreamPathTemplate("productservice/category/{categoryId}/products/{productId}/variants/{variantId}").Build()))) .When(x => x.WhenIReplaceTheTemplateVariables()) .Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/category/34/products/1/variants/12")) .BDDfy(); @@ -132,7 +133,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer private void WhenIReplaceTheTemplateVariables() { - _result = _downstreamUrlPathReplacer.Replace(_downstreamRoute.ReRoute.DownstreamTemplate, _downstreamRoute.TemplatePlaceholderNameAndValues); + _result = _downstreamPathReplacer.Replace(_downstreamRoute.ReRoute.DownstreamPathTemplate, _downstreamRoute.TemplatePlaceholderNameAndValues); } private void ThenTheDownstreamUrlPathIsReturned(string expected) diff --git a/test/Ocelot.UnitTests/Headers/HttpRequestHeadersBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/Headers/HttpRequestHeadersBuilderMiddlewareTests.cs index b85802af..3516d26b 100644 --- a/test/Ocelot.UnitTests/Headers/HttpRequestHeadersBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Headers/HttpRequestHeadersBuilderMiddlewareTests.cs @@ -67,7 +67,7 @@ namespace Ocelot.UnitTests.Headers { var downstreamRoute = new DownstreamRoute(new List(), new ReRouteBuilder() - .WithDownstreamTemplate("any old string") + .WithDownstreamPathTemplate("any old string") .WithClaimsToHeaders(new List { new ClaimToThing("UserId", "Subject", "", 0) diff --git a/test/Ocelot.UnitTests/QueryStrings/QueryStringBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/QueryStrings/QueryStringBuilderMiddlewareTests.cs index e4c7375e..39b32937 100644 --- a/test/Ocelot.UnitTests/QueryStrings/QueryStringBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/QueryStrings/QueryStringBuilderMiddlewareTests.cs @@ -65,7 +65,7 @@ namespace Ocelot.UnitTests.QueryStrings { var downstreamRoute = new DownstreamRoute(new List(), new ReRouteBuilder() - .WithDownstreamTemplate("any old string") + .WithDownstreamPathTemplate("any old string") .WithClaimsToQueries(new List { new ClaimToThing("UserId", "Subject", "", 0) diff --git a/test/Ocelot.UnitTests/RequestId/RequestIdMiddlewareTests.cs b/test/Ocelot.UnitTests/RequestId/RequestIdMiddlewareTests.cs index 8c023783..543613a8 100644 --- a/test/Ocelot.UnitTests/RequestId/RequestIdMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/RequestId/RequestIdMiddlewareTests.cs @@ -71,7 +71,7 @@ namespace Ocelot.UnitTests.RequestId { var downstreamRoute = new DownstreamRoute(new List(), new ReRouteBuilder() - .WithDownstreamTemplate("any old string") + .WithDownstreamPathTemplate("any old string") .WithRequestIdKey("LSRequestId").Build()); var requestId = Guid.NewGuid().ToString(); @@ -88,7 +88,7 @@ namespace Ocelot.UnitTests.RequestId { var downstreamRoute = new DownstreamRoute(new List(), new ReRouteBuilder() - .WithDownstreamTemplate("any old string") + .WithDownstreamPathTemplate("any old string") .WithRequestIdKey("LSRequestId").Build()); this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute)) From d7ad6df582b48726870eeb80b2aef5c88f7b8860 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Sat, 21 Jan 2017 10:07:06 +0000 Subject: [PATCH 02/14] removed rc1 status as all dependencies out of pre --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 69ddc117..83110722 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,6 +7,6 @@ build_script: test_script: - run-tests.bat after_test: -- push-to-nuget.bat %appveyor_build_version%-rc1 %nugetApiKey% +- push-to-nuget.bat %appveyor_build_version% %nugetApiKey% cache: - '%USERPROFILE%\.nuget\packages' \ No newline at end of file From 2cd69d1908b7009637c915ed2d6e6c5edd06f3b9 Mon Sep 17 00:00:00 2001 From: Philip Wood Date: Tue, 24 Jan 2017 21:11:15 +0000 Subject: [PATCH 03/14] #20 - added cake build to do same functionality as batch scripts. Also does semver versioning of assemblies, if running in AppVeyor, generates release notes and publishes packages to appveyor. --- .gitignore | 1 + Ocelot.sln | 2 + build.cake | 218 +++++++++++++++++++++++ build.ps1 | 189 ++++++++++++++++++++ src/Ocelot/project.json | 2 +- test/Ocelot.AcceptanceTests/project.json | 8 +- test/Ocelot.Benchmarks/project.json | 4 +- test/Ocelot.ManualTest/project.json | 4 +- test/Ocelot.UnitTests/project.json | 4 +- version.ps1 | 1 + 10 files changed, 422 insertions(+), 11 deletions(-) create mode 100644 build.cake create mode 100644 build.ps1 create mode 100644 version.ps1 diff --git a/.gitignore b/.gitignore index 61b1c211..1a7759c2 100644 --- a/.gitignore +++ b/.gitignore @@ -235,3 +235,4 @@ _Pvt_Extensions # FAKE - F# Make .fake/ +tools/ diff --git a/Ocelot.sln b/Ocelot.sln index 0165beb0..c1f647af 100644 --- a/Ocelot.sln +++ b/Ocelot.sln @@ -11,6 +11,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution appveyor.yml = appveyor.yml build-and-run-tests.bat = build-and-run-tests.bat build.bat = build.bat + build.cake = build.cake + build.ps1 = build.ps1 configuration-explanation.txt = configuration-explanation.txt global.json = global.json LICENSE.md = LICENSE.md diff --git a/build.cake b/build.cake new file mode 100644 index 00000000..513f99dd --- /dev/null +++ b/build.cake @@ -0,0 +1,218 @@ +#tool "nuget:?package=GitVersion.CommandLine" +#tool "nuget:?package=OpenCover" +#tool "nuget:?package=ReportGenerator" +#tool "nuget:?package=GitReleaseNotes" +#addin nuget:?package=Cake.DoInDirectory + +var target = Argument("target", "Default"); +var artifactsDir = Directory("artifacts"); + +Information("target is " +target); + +// versioning +var committedVersion = "0.0.0-dev"; +var buildVersion = committedVersion; + +//compile +var compileConfig = Argument("configuration", "Release"); +Information("Build configuration is " + compileConfig); + +// unit testing +var artifactsForUnitTestsDir = artifactsDir + Directory("UnitTests"); +var unitTestAssemblies = @"./test/Ocelot.UnitTests"; + +// acceptance testing +var artifactsForAcceptanceTestsDir = artifactsDir + Directory("AcceptanceTests"); +var acceptanceTestAssemblies = @"./test/Ocelot.AcceptanceTests"; + +//benchmark testing +var artifactsForBenchmarkTestsDir = artifactsDir + Directory("BenchmarkTests"); +var benchmarkTestAssemblies = @"./test/Ocelot.Benchmarks"; + +// packaging +var packagesDir = artifactsDir + Directory("Packages"); +var projectJson = "./src/Ocelot/project.json"; + +// release notes +var releaseNotesFile = packagesDir + File("releasenotes.md"); + +Task("Default") + .IsDependentOn("RunTests") + .IsDependentOn("Package") + .Does(() => + { + }); + +Task("Clean") + .Does(() => + { + if (DirectoryExists(artifactsDir)) + { + DeleteDirectory(artifactsDir, recursive:true); + } + CreateDirectory(artifactsDir); + }); + +Task("Version") + .Does(() => + { + var nugetVersion = GetVersion(); + Information("SemVer version number: " + nugetVersion); + + if (AppVeyor.IsRunningOnAppVeyor) + { + Information("Persisting version number..."); + PersistVersion(nugetVersion); + buildVersion = nugetVersion; + } + else + { + Information("We are not running on build server, so we won't persist the version number."); + } + }); + +Task("Restore") + .IsDependentOn("Clean") + .IsDependentOn("Version") + .Does(() => + { + DotNetCoreRestore("./src"); + DotNetCoreRestore("./test"); + }); + +Task("RunUnitTests") + .IsDependentOn("Restore") + .Does(() => + { + var buildSettings = new DotNetCoreTestSettings + { + Configuration = compileConfig, + }; + + EnsureDirectoryExists(artifactsForUnitTestsDir); + DotNetCoreTest(unitTestAssemblies, buildSettings); + }); + +Task("RunAcceptanceTests") + .IsDependentOn("Restore") + .Does(() => + { + var buildSettings = new DotNetCoreTestSettings + { + Configuration = "Debug", //acceptance test config is hard-coded for debug + }; + + EnsureDirectoryExists(artifactsForAcceptanceTestsDir); + + DoInDirectory("test/Ocelot.AcceptanceTests", () => + { + DotNetCoreTest(".", buildSettings); + }); + + }); + +Task("RunBenchmarkTests") + .IsDependentOn("Restore") + .Does(() => + { + var buildSettings = new DotNetCoreRunSettings + { + Configuration = compileConfig, + }; + + EnsureDirectoryExists(artifactsForBenchmarkTestsDir); + + DoInDirectory(benchmarkTestAssemblies, () => + { + DotNetCoreRun(".", "--args", buildSettings); + }); + }); + +Task("RunTests") + .IsDependentOn("RunUnitTests") + .IsDependentOn("RunAcceptanceTests") + .Does(() => + { + }); + +Task("Package") + .Does(() => + { + EnsureDirectoryExists(packagesDir); + + GenerateReleaseNotes(); + + var settings = new DotNetCorePackSettings + { + OutputDirectory = packagesDir, + NoBuild = true + }; + + DotNetCorePack(projectJson, settings); + + System.IO.File.WriteAllLines(packagesDir + File("artifacts"), new[]{ + "nuget:Ocelot." + buildVersion + ".nupkg", + "nugetSymbols:Ocelot." + buildVersion + ".symbols.nupkg", + "releaseNotes:releasenotes.md" + }); + + if (AppVeyor.IsRunningOnAppVeyor) + { + var path = packagesDir.ToString() + @"/**/*"; + + foreach (var file in GetFiles(path)) + { + AppVeyor.UploadArtifact(file.FullPath); + } + } + }); + +RunTarget(target); + +private string GetVersion() +{ + GitVersion(new GitVersionSettings{ + UpdateAssemblyInfo = false, + OutputType = GitVersionOutput.BuildServer + }); + + var versionInfo = GitVersion(new GitVersionSettings{ OutputType = GitVersionOutput.Json }); + return versionInfo.NuGetVersion; +} + +private void PersistVersion(string version) +{ + Information(string.Format("We'll search all project.json files for {0} and replace with {1}...", committedVersion, version)); + var projectJsonFiles = GetFiles("./**/project.json"); + + foreach(var projectJsonFile in projectJsonFiles) + { + var file = projectJsonFile.ToString(); + + Information(string.Format("Updating {0}...", file)); + + var updatedProjectJson = System.IO.File.ReadAllText(file) + .Replace(committedVersion, version); + + System.IO.File.WriteAllText(file, updatedProjectJson); + } +} + +private void GenerateReleaseNotes() +{ + Information("Generating release notes at " + releaseNotesFile); + + var releaseNotesExitCode = StartProcess( + @"tools/GitReleaseNotes/tools/gitreleasenotes.exe", + new ProcessSettings { Arguments = ". /o " + releaseNotesFile }); + + if (string.IsNullOrEmpty(System.IO.File.ReadAllText(releaseNotesFile))) + { + System.IO.File.WriteAllText(releaseNotesFile, "No issues closed since last release"); + } + + if (releaseNotesExitCode != 0) + { + throw new Exception("Failed to generate release notes"); + } +} \ No newline at end of file diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 00000000..44de5793 --- /dev/null +++ b/build.ps1 @@ -0,0 +1,189 @@ +########################################################################## +# This is the Cake bootstrapper script for PowerShell. +# This file was downloaded from https://github.com/cake-build/resources +# Feel free to change this file to fit your needs. +########################################################################## + +<# + +.SYNOPSIS +This is a Powershell script to bootstrap a Cake build. + +.DESCRIPTION +This Powershell script will download NuGet if missing, restore NuGet tools (including Cake) +and execute your Cake build script with the parameters you provide. + +.PARAMETER Script +The build script to execute. +.PARAMETER Target +The build script target to run. +.PARAMETER Configuration +The build configuration to use. +.PARAMETER Verbosity +Specifies the amount of information to be displayed. +.PARAMETER Experimental +Tells Cake to use the latest Roslyn release. +.PARAMETER WhatIf +Performs a dry run of the build script. +No tasks will be executed. +.PARAMETER Mono +Tells Cake to use the Mono scripting engine. +.PARAMETER SkipToolPackageRestore +Skips restoring of packages. +.PARAMETER ScriptArgs +Remaining arguments are added here. + +.LINK +http://cakebuild.net + +#> + +[CmdletBinding()] +Param( + [string]$Script = "build.cake", + [string]$Target = "Default", + [ValidateSet("Release", "Debug")] + [string]$Configuration = "Release", + [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")] + [string]$Verbosity = "Verbose", + [switch]$Experimental, + [Alias("DryRun","Noop")] + [switch]$WhatIf, + [switch]$Mono, + [switch]$SkipToolPackageRestore, + [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)] + [string[]]$ScriptArgs +) + +[Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null +function MD5HashFile([string] $filePath) +{ + if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf)) + { + return $null + } + + [System.IO.Stream] $file = $null; + [System.Security.Cryptography.MD5] $md5 = $null; + try + { + $md5 = [System.Security.Cryptography.MD5]::Create() + $file = [System.IO.File]::OpenRead($filePath) + return [System.BitConverter]::ToString($md5.ComputeHash($file)) + } + finally + { + if ($file -ne $null) + { + $file.Dispose() + } + } +} + +Write-Host "Preparing to run build script..." + +if(!$PSScriptRoot){ + $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent +} + +$TOOLS_DIR = Join-Path $PSScriptRoot "tools" +$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe" +$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe" +$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" +$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config" +$PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum" + +# Should we use mono? +$UseMono = ""; +if($Mono.IsPresent) { + Write-Verbose -Message "Using the Mono based scripting engine." + $UseMono = "-mono" +} + +# Should we use the new Roslyn? +$UseExperimental = ""; +if($Experimental.IsPresent -and !($Mono.IsPresent)) { + Write-Verbose -Message "Using experimental version of Roslyn." + $UseExperimental = "-experimental" +} + +# Is this a dry run? +$UseDryRun = ""; +if($WhatIf.IsPresent) { + $UseDryRun = "-dryrun" +} + +# Make sure tools folder exists +if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) { + Write-Verbose -Message "Creating tools directory..." + New-Item -Path $TOOLS_DIR -Type directory | out-null +} + +# Make sure that packages.config exist. +if (!(Test-Path $PACKAGES_CONFIG)) { + Write-Verbose -Message "Downloading packages.config..." + try { (New-Object System.Net.WebClient).DownloadFile("http://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch { + Throw "Could not download packages.config." + } +} + +# Try find NuGet.exe in path if not exists +if (!(Test-Path $NUGET_EXE)) { + Write-Verbose -Message "Trying to find nuget.exe in PATH..." + $existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_) } + $NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1 + if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) { + Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)." + $NUGET_EXE = $NUGET_EXE_IN_PATH.FullName + } +} + +# Try download NuGet.exe if not exists +if (!(Test-Path $NUGET_EXE)) { + Write-Verbose -Message "Downloading NuGet.exe..." + try { + (New-Object System.Net.WebClient).DownloadFile($NUGET_URL, $NUGET_EXE) + } catch { + Throw "Could not download NuGet.exe." + } +} + +# Save nuget.exe path to environment to be available to child processed +$ENV:NUGET_EXE = $NUGET_EXE + +# Restore tools from NuGet? +if(-Not $SkipToolPackageRestore.IsPresent) { + Push-Location + Set-Location $TOOLS_DIR + + # Check for changes in packages.config and remove installed tools if true. + [string] $md5Hash = MD5HashFile($PACKAGES_CONFIG) + if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or + ($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) { + Write-Verbose -Message "Missing or changed package.config hash..." + Remove-Item * -Recurse -Exclude packages.config,nuget.exe + } + + Write-Verbose -Message "Restoring tools from NuGet..." + $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`"" + + if ($LASTEXITCODE -ne 0) { + Throw "An error occured while restoring NuGet tools." + } + else + { + $md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII" + } + Write-Verbose -Message ($NuGetOutput | out-string) + Pop-Location +} + +# Make sure that Cake has been installed. +if (!(Test-Path $CAKE_EXE)) { + Throw "Could not find Cake.exe at $CAKE_EXE" +} + +# Start Cake +Write-Host "Running build script..." +Invoke-Expression "& `"$CAKE_EXE`" `"$Script`" -target=`"$Target`" -configuration=`"$Configuration`" -verbosity=`"$Verbosity`" $UseMono $UseDryRun $UseExperimental $ScriptArgs" +exit $LASTEXITCODE \ No newline at end of file diff --git a/src/Ocelot/project.json b/src/Ocelot/project.json index 85008568..8d259469 100644 --- a/src/Ocelot/project.json +++ b/src/Ocelot/project.json @@ -1,5 +1,5 @@ { - "version": "1.0.0-*", + "version": "0.0.0-dev", "dependencies": { "Microsoft.AspNetCore.Server.IISIntegration": "1.1.0", diff --git a/test/Ocelot.AcceptanceTests/project.json b/test/Ocelot.AcceptanceTests/project.json index 4b364510..17f35a3c 100644 --- a/test/Ocelot.AcceptanceTests/project.json +++ b/test/Ocelot.AcceptanceTests/project.json @@ -1,5 +1,5 @@ { - "version": "1.0.0-*", + "version": "0.0.0-dev", "buildOptions": { "copyToOutput": { @@ -22,10 +22,10 @@ "Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0", "Microsoft.AspNetCore.Http": "1.1.0", "Microsoft.DotNet.InternalAbstractions": "1.0.0", - "Ocelot": "1.0.0-*", + "Ocelot": "0.0.0-dev", "xunit": "2.2.0-beta2-build3300", "dotnet-test-xunit": "2.2.0-preview2-build1029", - "Ocelot.ManualTest": "1.0.0-*", + "Ocelot.ManualTest": "0.0.0-dev", "Microsoft.AspNetCore.TestHost": "1.1.0", "IdentityServer4": "1.0.1", "Microsoft.AspNetCore.Mvc": "1.1.0", @@ -36,7 +36,7 @@ }, "runtimes": { "win10-x64": {}, - "osx.10.11-x64":{}, + "osx.10.11-x64": {}, "win7-x64": {} }, "frameworks": { diff --git a/test/Ocelot.Benchmarks/project.json b/test/Ocelot.Benchmarks/project.json index da310ddd..5f7a4987 100644 --- a/test/Ocelot.Benchmarks/project.json +++ b/test/Ocelot.Benchmarks/project.json @@ -1,11 +1,11 @@ { - "version": "1.0.0-*", + "version": "0.0.0-dev", "buildOptions": { "emitEntryPoint": true }, "dependencies": { - "Ocelot": "1.0.0-*", + "Ocelot": "0.0.0-dev", "BenchmarkDotNet": "0.10.1" }, "runtimes": { diff --git a/test/Ocelot.ManualTest/project.json b/test/Ocelot.ManualTest/project.json index 181bdb07..3ae09ccb 100644 --- a/test/Ocelot.ManualTest/project.json +++ b/test/Ocelot.ManualTest/project.json @@ -1,5 +1,5 @@ { - "version": "1.0.0-*", + "version": "0.0.0-dev", "dependencies": { "Microsoft.AspNetCore.Http": "1.1.0", @@ -10,7 +10,7 @@ "Microsoft.Extensions.Logging.Console": "1.1.0", "Microsoft.Extensions.Logging.Debug": "1.1.0", "Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0", - "Ocelot": "1.0.0-*", + "Ocelot": "0.0.0-dev", "Microsoft.AspNetCore.Server.Kestrel": "1.1.0", "Microsoft.NETCore.App": "1.1.0" }, diff --git a/test/Ocelot.UnitTests/project.json b/test/Ocelot.UnitTests/project.json index 605b25d6..ab3e6cb1 100644 --- a/test/Ocelot.UnitTests/project.json +++ b/test/Ocelot.UnitTests/project.json @@ -1,5 +1,5 @@ { - "version": "1.0.0-*", + "version": "0.0.0-dev", "testRunner": "xunit", @@ -13,7 +13,7 @@ "Microsoft.Extensions.Logging.Debug": "1.1.0", "Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0", "Microsoft.AspNetCore.Http": "1.1.0", - "Ocelot": "1.0.0-*", + "Ocelot": "0.0.0-dev", "xunit": "2.2.0-beta2-build3300", "dotnet-test-xunit": "2.2.0-preview2-build1029", "Moq": "4.6.38-alpha", diff --git a/version.ps1 b/version.ps1 new file mode 100644 index 00000000..621201b6 --- /dev/null +++ b/version.ps1 @@ -0,0 +1 @@ +.\tools\GitVersion.CommandLine\tools\GitVersion.exe \ No newline at end of file From 93ebb6a0d369c62c215f33b9ead1dabbe13fb7e6 Mon Sep 17 00:00:00 2001 From: Philip Wood Date: Tue, 24 Jan 2017 21:27:25 +0000 Subject: [PATCH 04/14] #20 - bump commit --- test.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 test.txt diff --git a/test.txt b/test.txt new file mode 100644 index 00000000..30d74d25 --- /dev/null +++ b/test.txt @@ -0,0 +1 @@ +test \ No newline at end of file From e747d3386a63bb935eef6d25bb9554b2caf09995 Mon Sep 17 00:00:00 2001 From: Philip Wood Date: Sun, 29 Jan 2017 13:00:50 +0000 Subject: [PATCH 05/14] #20 - add release scripts --- Ocelot.sln | 2 + build.cake | 141 ++++++++++++++++++++++++++++++++++++++++++++++++---- release.ps1 | 1 + 3 files changed, 135 insertions(+), 9 deletions(-) create mode 100644 release.ps1 diff --git a/Ocelot.sln b/Ocelot.sln index c1f647af..3bc1f60a 100644 --- a/Ocelot.sln +++ b/Ocelot.sln @@ -19,6 +19,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Ocelot.nuspec = Ocelot.nuspec push-to-nuget.bat = push-to-nuget.bat README.md = README.md + release.cake = release.cake + release.ps1 = release.ps1 run-acceptance-tests.bat = run-acceptance-tests.bat run-benchmarks.bat = run-benchmarks.bat run-tests.bat = run-tests.bat diff --git a/build.cake b/build.cake index 513f99dd..73dbae18 100644 --- a/build.cake +++ b/build.cake @@ -3,6 +3,7 @@ #tool "nuget:?package=ReportGenerator" #tool "nuget:?package=GitReleaseNotes" #addin nuget:?package=Cake.DoInDirectory +#addin "Cake.Json" var target = Argument("target", "Default"); var artifactsDir = Directory("artifacts"); @@ -25,20 +26,32 @@ var unitTestAssemblies = @"./test/Ocelot.UnitTests"; var artifactsForAcceptanceTestsDir = artifactsDir + Directory("AcceptanceTests"); var acceptanceTestAssemblies = @"./test/Ocelot.AcceptanceTests"; -//benchmark testing +// benchmark testing var artifactsForBenchmarkTestsDir = artifactsDir + Directory("BenchmarkTests"); var benchmarkTestAssemblies = @"./test/Ocelot.Benchmarks"; // packaging -var packagesDir = artifactsDir + Directory("Packages"); var projectJson = "./src/Ocelot/project.json"; - -// release notes +var packagesDir = artifactsDir + Directory("Packages"); var releaseNotesFile = packagesDir + File("releasenotes.md"); +var artifactsFile = packagesDir + File("artifacts.txt"); + +//unstable releases +var publishUnstableBuilds = true; +var nugetFeedUnstableKey = EnvironmentVariable("nuget-apikey-unstable"); +var nugetFeedUnstableUploadUrl = "https://www.myget.org/F/ocelot-unstable/api/v2/package"; +var nugetFeedUnstableSymbolsUploadUrl = "https://www.myget.org/F/ocelot-unstable/symbols/api/v2/package"; + +//stable releases +var releaseTag = ""; +var nugetFeedStableKey = EnvironmentVariable("nuget-apikey-stable"); +var nugetFeedStableUploadUrl = "https://www.myget.org/F/ocelot-stable/api/v2/package"; +var nugetFeedStableSymbolsUploadUrl = "https://www.myget.org/F/ocelot-stable/symbols/api/v2/package"; Task("Default") .IsDependentOn("RunTests") - .IsDependentOn("Package") + .IsDependentOn("CreatePackages") + .IsDependentOn("ReleasePackagesToUnstableFeed") .Does(() => { }); @@ -56,7 +69,7 @@ Task("Clean") Task("Version") .Does(() => { - var nugetVersion = GetVersion(); + var nugetVersion = GetNuGetVersionForCommit(); Information("SemVer version number: " + nugetVersion); if (AppVeyor.IsRunningOnAppVeyor) @@ -135,7 +148,7 @@ Task("RunTests") { }); -Task("Package") +Task("CreatePackages") .Does(() => { EnsureDirectoryExists(packagesDir); @@ -150,7 +163,7 @@ Task("Package") DotNetCorePack(projectJson, settings); - System.IO.File.WriteAllLines(packagesDir + File("artifacts"), new[]{ + System.IO.File.WriteAllLines(artifactsFile, new[]{ "nuget:Ocelot." + buildVersion + ".nupkg", "nugetSymbols:Ocelot." + buildVersion + ".symbols.nupkg", "releaseNotes:releasenotes.md" @@ -167,9 +180,71 @@ Task("Package") } }); +Task("ReleasePackagesToUnstableFeed") + .IsDependentOn("CreatePackages") + .Does(() => + { + PublishPackages(nugetFeedUnstableKey, nugetFeedUnstableUploadUrl, nugetFeedUnstableSymbolsUploadUrl); + }); + +Task("EnsureStableReleaseRequirements") + .Does(() => + { + if (!AppVeyor.IsRunningOnAppVeyor) + { + throw new Exception("Stable release should happen via appveyor"); + } + + var isTag = + AppVeyor.Environment.Repository.Tag.IsTag && + !string.IsNullOrWhiteSpace(AppVeyor.Environment.Repository.Tag.Name); + + if (!isTag) + { + throw new Exception("Stable release should happen from a published GitHub release"); + } + }); + +Task("UpdateVersionInfo") + .IsDependentOn("EnsureStableReleaseRequirements") + .Does(() => + { + releaseTag = AppVeyor.Environment.Repository.Tag.Name; + AppVeyor.UpdateBuildVersion(releaseTag); + }); + +Task("DownloadGitHubReleaseArtifacts") + .IsDependentOn("UpdateVersionInfo") + .Does(() => + { + EnsureDirectoryExists(packagesDir); + + var assets_url = ParseJson(GetResource("https://api.github.com/repos/binarymash/pipelinetesting/releases/tags/" + releaseTag)) + .GetValue("assets_url") + .Value(); + + foreach(var asset in DeserializeJson(GetResource(assets_url))) + { + var file = packagesDir + File(asset.Value("name")); + Information("Downloading " + file); + DownloadFile(asset.Value("browser_download_url"), file); + } + }); + +Task("ReleasePackagesToStableFeed") + .IsDependentOn("DownloadGitHubReleaseArtifacts") + .Does(() => + { + PublishPackages(nugetFeedStableKey, nugetFeedStableUploadUrl, nugetFeedStableSymbolsUploadUrl); + }); + +Task("Release") + .IsDependentOn("ReleasePackagesToStableFeed"); + RunTarget(target); -private string GetVersion() +/// Gets nuique nuget version for this commit +private string GetNuGetVersionForCommit() { GitVersion(new GitVersionSettings{ UpdateAssemblyInfo = false, @@ -180,9 +255,11 @@ private string GetVersion() return versionInfo.NuGetVersion; } +/// Updates project version in all of our projects private void PersistVersion(string version) { Information(string.Format("We'll search all project.json files for {0} and replace with {1}...", committedVersion, version)); + var projectJsonFiles = GetFiles("./**/project.json"); foreach(var projectJsonFile in projectJsonFiles) @@ -198,6 +275,7 @@ private void PersistVersion(string version) } } +/// generates release notes based on issues closed in GitHub since the last release private void GenerateReleaseNotes() { Information("Generating release notes at " + releaseNotesFile); @@ -215,4 +293,49 @@ private void GenerateReleaseNotes() { throw new Exception("Failed to generate release notes"); } +} + +/// Publishes code and symbols packages to nuget feed, based on contents of artifacts file +private void PublishPackages(string feedApiKey, string codeFeedUrl, string symbolFeedUrl) +{ + var artifacts = System.IO.File + .ReadAllLines(artifactsFile) + .Select(l => l.Split(':')) + .ToDictionary(v => v[0], v => v[1]); + + var codePackage = packagesDir + File(artifacts["nuget"]); + var symbolsPackage = packagesDir + File(artifacts["nugetSymbols"]); + + NuGetPush( + codePackage, + new NuGetPushSettings { + ApiKey = feedApiKey, + Source = codeFeedUrl + }); + + NuGetPush( + symbolsPackage, + new NuGetPushSettings { + ApiKey = feedApiKey, + Source = symbolFeedUrl + }); + +} + +/// gets the resource from the specified url +private string GetResource(string url) +{ + Information("Getting resource from " + url); + + var assetsRequest = System.Net.WebRequest.CreateHttp(url); + assetsRequest.Method = "GET"; + assetsRequest.Accept = "application/vnd.github.v3+json"; + assetsRequest.UserAgent = "BuildScript"; + + using (var assetsResponse = assetsRequest.GetResponse()) + { + var assetsStream = assetsResponse.GetResponseStream(); + var assetsReader = new StreamReader(assetsStream); + return assetsReader.ReadToEnd(); + } } \ No newline at end of file diff --git a/release.ps1 b/release.ps1 new file mode 100644 index 00000000..6cf4c66b --- /dev/null +++ b/release.ps1 @@ -0,0 +1 @@ +./build.ps1 -target Release \ No newline at end of file From b50d2b1acae5ea8c420b155fc87023b7c38e7afa Mon Sep 17 00:00:00 2001 From: Philip Wood Date: Sun, 29 Jan 2017 13:17:57 +0000 Subject: [PATCH 06/14] #20 - remove obsolete file --- Ocelot.sln | 1 - 1 file changed, 1 deletion(-) diff --git a/Ocelot.sln b/Ocelot.sln index 3bc1f60a..282c7120 100644 --- a/Ocelot.sln +++ b/Ocelot.sln @@ -19,7 +19,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Ocelot.nuspec = Ocelot.nuspec push-to-nuget.bat = push-to-nuget.bat README.md = README.md - release.cake = release.cake release.ps1 = release.ps1 run-acceptance-tests.bat = run-acceptance-tests.bat run-benchmarks.bat = run-benchmarks.bat From 0172950dab730150b86336f525ffffa3265d321c Mon Sep 17 00:00:00 2001 From: Philip Wood Date: Sun, 29 Jan 2017 13:47:59 +0000 Subject: [PATCH 07/14] #20 - added release notes to repo --- ReleaseNotes.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 ReleaseNotes.md diff --git a/ReleaseNotes.md b/ReleaseNotes.md new file mode 100644 index 00000000..a647c6c3 --- /dev/null +++ b/ReleaseNotes.md @@ -0,0 +1 @@ +No issues closed since last release \ No newline at end of file From e4a22e57d715506b1f55e073d0b01ba5578c4e48 Mon Sep 17 00:00:00 2001 From: Philip Wood Date: Sun, 29 Jan 2017 14:10:49 +0000 Subject: [PATCH 08/14] #20 - fix download of github release tags --- build.cake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build.cake b/build.cake index 73dbae18..0781fcfc 100644 --- a/build.cake +++ b/build.cake @@ -43,6 +43,7 @@ var nugetFeedUnstableUploadUrl = "https://www.myget.org/F/ocelot-unstable/api/v2 var nugetFeedUnstableSymbolsUploadUrl = "https://www.myget.org/F/ocelot-unstable/symbols/api/v2/package"; //stable releases +var tagsUrl = "https://api.github.com/repos/binarymash/ocelot/releases/tags/"; var releaseTag = ""; var nugetFeedStableKey = EnvironmentVariable("nuget-apikey-stable"); var nugetFeedStableUploadUrl = "https://www.myget.org/F/ocelot-stable/api/v2/package"; @@ -219,7 +220,8 @@ Task("DownloadGitHubReleaseArtifacts") { EnsureDirectoryExists(packagesDir); - var assets_url = ParseJson(GetResource("https://api.github.com/repos/binarymash/pipelinetesting/releases/tags/" + releaseTag)) + var releaseUrl = tagsUrl + releaseTag; + var assets_url = ParseJson(GetResource(releaseUrl)) .GetValue("assets_url") .Value(); From 33854067d44c24937cf1f4b633bf8fd397e59c5a Mon Sep 17 00:00:00 2001 From: Philip Wood Date: Sun, 29 Jan 2017 15:14:31 +0000 Subject: [PATCH 09/14] #20 - Tidy up. Update command line scripts. Fix running benchmarks. --- Ocelot.sln | 10 +++--- build-and-release-unstable.ps1 | 1 + build-and-run-tests.bat | 2 -- build-and-run-tests.ps1 | 1 + build.bat | 8 ----- build.cake | 56 ++++++++++++++++++---------------- run-acceptance-tests.bat | 8 ----- run-acceptance-tests.ps1 | 1 + run-benchmarks.bat | 15 --------- run-benchmarks.ps1 | 1 + run-tests.bat | 2 -- run-unit-tests.bat | 8 ----- run-unit-tests.ps1 | 1 + test.txt | 1 - 14 files changed, 39 insertions(+), 76 deletions(-) create mode 100644 build-and-release-unstable.ps1 delete mode 100755 build-and-run-tests.bat create mode 100644 build-and-run-tests.ps1 delete mode 100755 build.bat delete mode 100755 run-acceptance-tests.bat create mode 100644 run-acceptance-tests.ps1 delete mode 100644 run-benchmarks.bat create mode 100644 run-benchmarks.ps1 delete mode 100755 run-tests.bat delete mode 100755 run-unit-tests.bat create mode 100644 run-unit-tests.ps1 delete mode 100644 test.txt diff --git a/Ocelot.sln b/Ocelot.sln index 282c7120..2f8fd206 100644 --- a/Ocelot.sln +++ b/Ocelot.sln @@ -9,21 +9,19 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ProjectSection(SolutionItems) = preProject .gitignore = .gitignore appveyor.yml = appveyor.yml - build-and-run-tests.bat = build-and-run-tests.bat - build.bat = build.bat + build-and-run-tests.ps1 = build-and-run-tests.ps1 build.cake = build.cake build.ps1 = build.ps1 configuration-explanation.txt = configuration-explanation.txt global.json = global.json LICENSE.md = LICENSE.md Ocelot.nuspec = Ocelot.nuspec - push-to-nuget.bat = push-to-nuget.bat README.md = README.md release.ps1 = release.ps1 - run-acceptance-tests.bat = run-acceptance-tests.bat + run-acceptance-tests.ps1 = run-acceptance-tests.ps1 run-benchmarks.bat = run-benchmarks.bat - run-tests.bat = run-tests.bat - run-unit-tests.bat = run-unit-tests.bat + run-benchmarks.ps1 = run-benchmarks.ps1 + run-unit-tests.ps1 = run-unit-tests.ps1 EndProjectSection EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Ocelot", "src\Ocelot\Ocelot.xproj", "{D6DF4206-0DBA-41D8-884D-C3E08290FDBB}" diff --git a/build-and-release-unstable.ps1 b/build-and-release-unstable.ps1 new file mode 100644 index 00000000..9a29f95f --- /dev/null +++ b/build-and-release-unstable.ps1 @@ -0,0 +1 @@ +./build.ps1 -target build-full \ No newline at end of file diff --git a/build-and-run-tests.bat b/build-and-run-tests.bat deleted file mode 100755 index 764682b6..00000000 --- a/build-and-run-tests.bat +++ /dev/null @@ -1,2 +0,0 @@ -./run-tests.bat -./build.bat \ No newline at end of file diff --git a/build-and-run-tests.ps1 b/build-and-run-tests.ps1 new file mode 100644 index 00000000..f82502e5 --- /dev/null +++ b/build-and-run-tests.ps1 @@ -0,0 +1 @@ +./build.ps1 -target RunTests \ No newline at end of file diff --git a/build.bat b/build.bat deleted file mode 100755 index 656515d4..00000000 --- a/build.bat +++ /dev/null @@ -1,8 +0,0 @@ -echo ------------------------- - -echo Building Ocelot -dotnet restore src/Ocelot -dotnet build src/Ocelot -c Release - - - diff --git a/build.cake b/build.cake index 0781fcfc..3fbeeaf7 100644 --- a/build.cake +++ b/build.cake @@ -2,21 +2,15 @@ #tool "nuget:?package=OpenCover" #tool "nuget:?package=ReportGenerator" #tool "nuget:?package=GitReleaseNotes" -#addin nuget:?package=Cake.DoInDirectory -#addin "Cake.Json" +#addin "nuget:?package=Cake.DoInDirectory" +#addin "nuget:?package=Cake.Json" -var target = Argument("target", "Default"); -var artifactsDir = Directory("artifacts"); - -Information("target is " +target); - -// versioning -var committedVersion = "0.0.0-dev"; -var buildVersion = committedVersion; - -//compile +// compile var compileConfig = Argument("configuration", "Release"); -Information("Build configuration is " + compileConfig); +var projectJson = "./src/Ocelot/project.json"; + +// build artifacts +var artifactsDir = Directory("artifacts"); // unit testing var artifactsForUnitTestsDir = artifactsDir + Directory("UnitTests"); @@ -31,32 +25,42 @@ var artifactsForBenchmarkTestsDir = artifactsDir + Directory("BenchmarkTests"); var benchmarkTestAssemblies = @"./test/Ocelot.Benchmarks"; // packaging -var projectJson = "./src/Ocelot/project.json"; var packagesDir = artifactsDir + Directory("Packages"); var releaseNotesFile = packagesDir + File("releasenotes.md"); var artifactsFile = packagesDir + File("artifacts.txt"); -//unstable releases -var publishUnstableBuilds = true; +// unstable releases var nugetFeedUnstableKey = EnvironmentVariable("nuget-apikey-unstable"); var nugetFeedUnstableUploadUrl = "https://www.myget.org/F/ocelot-unstable/api/v2/package"; var nugetFeedUnstableSymbolsUploadUrl = "https://www.myget.org/F/ocelot-unstable/symbols/api/v2/package"; -//stable releases +// stable releases var tagsUrl = "https://api.github.com/repos/binarymash/ocelot/releases/tags/"; -var releaseTag = ""; var nugetFeedStableKey = EnvironmentVariable("nuget-apikey-stable"); var nugetFeedStableUploadUrl = "https://www.myget.org/F/ocelot-stable/api/v2/package"; var nugetFeedStableSymbolsUploadUrl = "https://www.myget.org/F/ocelot-stable/symbols/api/v2/package"; -Task("Default") - .IsDependentOn("RunTests") - .IsDependentOn("CreatePackages") - .IsDependentOn("ReleasePackagesToUnstableFeed") - .Does(() => - { - }); +// internal build variables - don't change these. +var releaseTag = ""; +var buildVersion = committedVersion; +var committedVersion = "0.0.0-dev"; +var target = Argument("target", "Default"); + +Information("target is " +target); +Information("Build configuration is " + compileConfig); + +Task("Default") + .IsDependentOn("Build"); + +Task("Build") + .IsDependentOn("RunTests") + .IsDependentOn("CreatePackages"); + +Task("BuildAndReleaseUnstable") + .IsDependentOn("Build") + .IsDependentOn("ReleasePackagesToUnstableFeed"); + Task("Clean") .Does(() => { @@ -138,7 +142,7 @@ Task("RunBenchmarkTests") DoInDirectory(benchmarkTestAssemblies, () => { - DotNetCoreRun(".", "--args", buildSettings); + DotNetCoreRun(".", "", buildSettings); }); }); diff --git a/run-acceptance-tests.bat b/run-acceptance-tests.bat deleted file mode 100755 index ba8a3489..00000000 --- a/run-acceptance-tests.bat +++ /dev/null @@ -1,8 +0,0 @@ -echo Running Ocelot.AcceptanceTests -cd test/Ocelot.AcceptanceTests/ -dotnet restore -dotnet test -cd ../../ - -echo Restoring Ocelot.ManualTest -dotnet restore test/Ocelot.ManualTest/ \ No newline at end of file diff --git a/run-acceptance-tests.ps1 b/run-acceptance-tests.ps1 new file mode 100644 index 00000000..480e1d4c --- /dev/null +++ b/run-acceptance-tests.ps1 @@ -0,0 +1 @@ +./build -target RunAcceptanceTests \ No newline at end of file diff --git a/run-benchmarks.bat b/run-benchmarks.bat deleted file mode 100644 index 1376f17a..00000000 --- a/run-benchmarks.bat +++ /dev/null @@ -1,15 +0,0 @@ -echo ------------------------- - -echo Running Ocelot.Benchmarks - -cd test/Ocelot.Benchmarks - -dotnet restore - -dotnet run - -cd ../../ - - - - diff --git a/run-benchmarks.ps1 b/run-benchmarks.ps1 new file mode 100644 index 00000000..e05490fd --- /dev/null +++ b/run-benchmarks.ps1 @@ -0,0 +1 @@ +./build.ps1 -target RunBenchmarkTests \ No newline at end of file diff --git a/run-tests.bat b/run-tests.bat deleted file mode 100755 index 39532229..00000000 --- a/run-tests.bat +++ /dev/null @@ -1,2 +0,0 @@ -./run-unit-tests.bat -./run-acceptance-tests.bat \ No newline at end of file diff --git a/run-unit-tests.bat b/run-unit-tests.bat deleted file mode 100755 index 9ad6a4f2..00000000 --- a/run-unit-tests.bat +++ /dev/null @@ -1,8 +0,0 @@ -echo ------------------------- - -echo Restoring Ocelot -dotnet restore src/Ocelot - -echo Running Ocelot.UnitTests -dotnet restore test/Ocelot.UnitTests/ -dotnet test test/Ocelot.UnitTests/ diff --git a/run-unit-tests.ps1 b/run-unit-tests.ps1 new file mode 100644 index 00000000..0e6a91bd --- /dev/null +++ b/run-unit-tests.ps1 @@ -0,0 +1 @@ +./build.ps1 -target RunUnitTests \ No newline at end of file diff --git a/test.txt b/test.txt deleted file mode 100644 index 30d74d25..00000000 --- a/test.txt +++ /dev/null @@ -1 +0,0 @@ -test \ No newline at end of file From 17dac3d3a2066fb496ada79fb81f0cdeb0a5ebdb Mon Sep 17 00:00:00 2001 From: Philip Wood Date: Sun, 29 Jan 2017 16:16:08 +0000 Subject: [PATCH 10/14] #20 - added readme for build and release process. --- build.readme.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 build.readme.md diff --git a/build.readme.md b/build.readme.md new file mode 100644 index 00000000..fccff4d5 --- /dev/null +++ b/build.readme.md @@ -0,0 +1,22 @@ +#1. Overview + +This document summarises the build and release process for the project. The build scripts are written using [Cake](http://cakebuild.net/), and are defined in `./build.cake`. The scripts have been designed to be run by either developers locally or by a build server (currently [AppVeyor](https://www.appveyor.com/)), with minimal logic defined in the build server itself. + +#2. Building + * You'll generally want to run the `./build.ps1` script. This will compile, run unit and acceptance tests and build the output packages locally. Output will got to the `./artifacts` directory. + * You can view the current commit's [SemVer](http://semver.org/) build information by running `./version.ps1`. + * The other `./*.ps1` scripts perform subsets of the build process, if you don't want to run the full build. + * The release process works best with GitFlow branching; this allows us to publish every development commit to an unstable feed with a unique SemVer version, and then choose when to release to a stable feed. + +#3. Release process +This section defines the release process for the maintainers of the project. + * Merge pull requests to the `release` branch. + * Every commit pushed to the Origin repo will kick off the [ocelot-build](https://ci.appveyor.com/project/binarymash/ocelot) project in AppVeyor. This performs the same tasks as the command line build, and in addition pushes the packages to the unstable nuget feed. + * When you're ready for a release, create a release branch. You'll probably want to update the committed `./ReleaseNotes.md` based on the contents of the equivalent file in the `./artifacts` directory. + * When the `release` branch has built successfully in Appveyor, select the build and then Deploy to the `GitHub Release` environment. This will create a new release in GitHub. + * In Github, navigate to the [release](https://github.com/binarymash/Ocelot/releases). Modify the release name and tag as desired. + * When you're ready, publish the release. This will tag the commit with the specified release number. + * The [ocelot-release](https://ci.appveyor.com/project/binarymash/ocelot-wtaj9) project will detect the newly created tag and kick off the release process. This will download the artifacts from GitHub, and publish the packages to the stable nuget feed. + * When you have a final stable release build, merge the `release` branch into `master` and `develop`. Deploy the master branch to github and following the full release process as described above. Don't forget to uncheck the "This is a pre-release" checkbox in GitHub before publishing. + * Note - because the release builds are initiated by tagging a commit, if for some reason a release build fails in AppVeyor you'll need to delete the tag from the repo and republish the release in GitHub. + From 727dbb5f7d23c26ea594cca83da3b1c2315a9125 Mon Sep 17 00:00:00 2001 From: Philip Wood Date: Sun, 29 Jan 2017 18:19:16 +0000 Subject: [PATCH 11/14] #20 - add gitversion config --- GitVersion.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 GitVersion.yml diff --git a/GitVersion.yml b/GitVersion.yml new file mode 100644 index 00000000..05e9ac41 --- /dev/null +++ b/GitVersion.yml @@ -0,0 +1,4 @@ +mode: ContinuousDelivery +branches: {} +ignore: + sha: [] From 3642aac20defade863750fd82a671544443682f3 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 1 Feb 2017 20:43:39 +0000 Subject: [PATCH 12/14] Removed push-to-nuget build script and changed cake nuget feed urls --- build.cake | 10 +++++----- push-to-nuget.bat | 11 ----------- 2 files changed, 5 insertions(+), 16 deletions(-) delete mode 100644 push-to-nuget.bat diff --git a/build.cake b/build.cake index 3fbeeaf7..1d798d74 100644 --- a/build.cake +++ b/build.cake @@ -31,14 +31,14 @@ var artifactsFile = packagesDir + File("artifacts.txt"); // unstable releases var nugetFeedUnstableKey = EnvironmentVariable("nuget-apikey-unstable"); -var nugetFeedUnstableUploadUrl = "https://www.myget.org/F/ocelot-unstable/api/v2/package"; -var nugetFeedUnstableSymbolsUploadUrl = "https://www.myget.org/F/ocelot-unstable/symbols/api/v2/package"; +var nugetFeedUnstableUploadUrl = "https://www.nuget.org/api/v2/package"; +var nugetFeedUnstableSymbolsUploadUrl = "https://www.nuget.org/api/v2/package"; // stable releases -var tagsUrl = "https://api.github.com/repos/binarymash/ocelot/releases/tags/"; +var tagsUrl = "https://api.github.com/repos/tompallister/ocelot/releases/tags/"; var nugetFeedStableKey = EnvironmentVariable("nuget-apikey-stable"); -var nugetFeedStableUploadUrl = "https://www.myget.org/F/ocelot-stable/api/v2/package"; -var nugetFeedStableSymbolsUploadUrl = "https://www.myget.org/F/ocelot-stable/symbols/api/v2/package"; +var nugetFeedStableUploadUrl = "https://www.nuget.org/api/v2/package"; +var nugetFeedStableSymbolsUploadUrl = "https://www.nuget.org/api/v2/package"; // internal build variables - don't change these. var releaseTag = ""; diff --git a/push-to-nuget.bat b/push-to-nuget.bat deleted file mode 100644 index 7200d09c..00000000 --- a/push-to-nuget.bat +++ /dev/null @@ -1,11 +0,0 @@ -echo ------------------------- - -echo Packing Ocelot Version %1 -nuget pack .\Ocelot.nuspec -version %1 - -echo Publishing Ocelot - nuget push Ocelot.%1.nupkg -ApiKey %2 -Source https://www.nuget.org/api/v2/package - - - - From 9cc5c2c9648161de54dcc12da03a8ad0dad75090 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 1 Feb 2017 20:45:27 +0000 Subject: [PATCH 13/14] Call build.ps1 from AppVeyor --- appveyor.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 83110722..6e8b16f6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,10 +3,6 @@ configuration: - Release platform: Any CPU build_script: -- build.bat -test_script: -- run-tests.bat -after_test: -- push-to-nuget.bat %appveyor_build_version% %nugetApiKey% +- build.ps1 cache: - '%USERPROFILE%\.nuget\packages' \ No newline at end of file From 92f492f0ad37d212f4f9307be96d9e25bf0dfac5 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 1 Feb 2017 20:51:59 +0000 Subject: [PATCH 14/14] Call build.ps1 in same manner as mr binary mash --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 6e8b16f6..b5cd7c0c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,6 +3,6 @@ configuration: - Release platform: Any CPU build_script: -- build.ps1 +- ./build.ps1 cache: - '%USERPROFILE%\.nuget\packages' \ No newline at end of file