From 637d93dc4bb21162d05767bab1366105524f8ff3 Mon Sep 17 00:00:00 2001 From: Marc Denman Date: Mon, 17 Apr 2017 11:23:34 +0100 Subject: [PATCH 01/35] Use DiagnosticListner for middleware logging Instead of each middleware having to log that it has started and ended, the DianosticListner package allows for capturing of these events in a lightwieght manner. This commit implements this and removes unncessary logging from most middleware. --- .../Middleware/AuthenticationMiddleware.cs | 16 +------ .../Middleware/AuthorisationMiddleware.cs | 21 +++------ .../Cache/Middleware/OutputCacheMiddleware.cs | 2 - .../Middleware/ClaimsBuilderMiddleware.cs | 7 --- .../ServiceCollectionExtensions.cs | 5 +++ .../DownstreamRouteFinderMiddleware.cs | 9 ---- .../DownstreamUrlCreatorMiddleware.cs | 6 --- .../HttpRequestHeadersBuilderMiddleware.cs | 10 +---- .../Middleware/LoadBalancingMiddleware.cs | 20 ++++----- .../Logging/OcelotDiagnosticListener.cs | 27 +++++++++++ .../Middleware/OcelotMiddlewareExtensions.cs | 45 ++++++++++++++----- src/Ocelot/Ocelot.csproj | 2 + .../QueryStringBuilderMiddleware.cs | 8 +--- .../Middleware/ClientRateLimitMiddleware.cs | 25 +++-------- .../Middleware/RequestIdMiddleware.cs | 14 ++---- .../Middleware/ResponderMiddleware.cs | 6 +-- 16 files changed, 98 insertions(+), 125 deletions(-) create mode 100644 src/Ocelot/Logging/OcelotDiagnosticListener.cs diff --git a/src/Ocelot/Authentication/Middleware/AuthenticationMiddleware.cs b/src/Ocelot/Authentication/Middleware/AuthenticationMiddleware.cs index a6eb9cc2..7a292ea0 100644 --- a/src/Ocelot/Authentication/Middleware/AuthenticationMiddleware.cs +++ b/src/Ocelot/Authentication/Middleware/AuthenticationMiddleware.cs @@ -34,8 +34,6 @@ namespace Ocelot.Authentication.Middleware public async Task Invoke(HttpContext context) { - _logger.TraceMiddlewareEntry(); - if (IsAuthenticatedRoute(DownstreamRoute.ReRoute)) { _logger.LogDebug($"{context.Request.Path} is an authenticated route. {MiddlwareName} checking if client is authenticated"); @@ -46,7 +44,6 @@ namespace Ocelot.Authentication.Middleware { _logger.LogError($"Error getting authentication handler for {context.Request.Path}. {authenticationHandler.Errors.ToErrorString()}"); SetPipelineError(authenticationHandler.Errors); - _logger.TraceMiddlewareCompleted(); return; } @@ -56,11 +53,7 @@ namespace Ocelot.Authentication.Middleware if (context.User.Identity.IsAuthenticated) { _logger.LogDebug($"Client has been authenticated for {context.Request.Path}"); - - _logger.TraceInvokeNext(); - await _next.Invoke(context); - _logger.TraceInvokeNextCompleted(); - _logger.TraceMiddlewareCompleted(); + await _next.Invoke(context); } else { @@ -72,8 +65,6 @@ namespace Ocelot.Authentication.Middleware _logger.LogError($"Client has NOT been authenticated for {context.Request.Path} and pipeline error set. {error.ToErrorString()}"); SetPipelineError(error); - - _logger.TraceMiddlewareCompleted(); return; } } @@ -81,10 +72,7 @@ namespace Ocelot.Authentication.Middleware { _logger.LogTrace($"No authentication needed for {context.Request.Path}"); - _logger.TraceInvokeNext(); - await _next.Invoke(context); - _logger.TraceInvokeNextCompleted(); - _logger.TraceMiddlewareCompleted(); + await _next.Invoke(context); } } diff --git a/src/Ocelot/Authorisation/Middleware/AuthorisationMiddleware.cs b/src/Ocelot/Authorisation/Middleware/AuthorisationMiddleware.cs index a86643a4..c52b7329 100644 --- a/src/Ocelot/Authorisation/Middleware/AuthorisationMiddleware.cs +++ b/src/Ocelot/Authorisation/Middleware/AuthorisationMiddleware.cs @@ -29,17 +29,15 @@ namespace Ocelot.Authorisation.Middleware public async Task Invoke(HttpContext context) { - _logger.LogDebug("started authorisation"); - if (DownstreamRoute.ReRoute.IsAuthorised) { - _logger.LogDebug("route is authorised"); + _logger.LogDebug($"{DownstreamRoute.ReRoute.DownstreamPathTemplate.Value} route requires user to be authorised"); var authorised = _authoriser.Authorise(context.User, DownstreamRoute.ReRoute.RouteClaimsRequirement); if (authorised.IsError) { - _logger.LogDebug("error authorising user"); + _logger.LogDebug($"Error whilst authorising {context.User.Identity.Name} for {context.User.Identity.Name}. Setting pipeline error"); SetPipelineError(authorised.Errors); return; @@ -47,30 +45,23 @@ namespace Ocelot.Authorisation.Middleware if (IsAuthorised(authorised)) { - _logger.LogDebug("user is authorised calling next middleware"); - + _logger.LogDebug($"{context.User.Identity.Name} has succesfully been authorised for {DownstreamRoute.ReRoute.UpstreamPathTemplate.Value}. Calling next middleware"); await _next.Invoke(context); - - _logger.LogDebug("succesfully called next middleware"); } else { - _logger.LogDebug("user is not authorised setting pipeline error"); + _logger.LogDebug($"{context.User.Identity.Name} is not authorised to access {DownstreamRoute.ReRoute.UpstreamPathTemplate.Value}. Setting pipeline error"); SetPipelineError(new List { - new UnauthorisedError( - $"{context.User.Identity.Name} unable to access {DownstreamRoute.ReRoute.UpstreamPathTemplate.Value}") + new UnauthorisedError($"{context.User.Identity.Name} is not authorised to access {DownstreamRoute.ReRoute.UpstreamPathTemplate.Value}") }); } } else { - _logger.LogDebug("AuthorisationMiddleware.Invoke route is not authorised calling next middleware"); - + _logger.LogDebug($"{DownstreamRoute.ReRoute.DownstreamPathTemplate.Value} route does not require user to be authorised"); await _next.Invoke(context); - - _logger.LogDebug("succesfully called next middleware"); } } diff --git a/src/Ocelot/Cache/Middleware/OutputCacheMiddleware.cs b/src/Ocelot/Cache/Middleware/OutputCacheMiddleware.cs index 948a7397..2c2aceaa 100644 --- a/src/Ocelot/Cache/Middleware/OutputCacheMiddleware.cs +++ b/src/Ocelot/Cache/Middleware/OutputCacheMiddleware.cs @@ -54,8 +54,6 @@ namespace Ocelot.Cache.Middleware await _next.Invoke(context); - _logger.LogDebug("succesfully called next middleware"); - if (PipelineError) { _logger.LogDebug("there was a pipeline error for {downstreamUrlKey}", downstreamUrlKey); diff --git a/src/Ocelot/Claims/Middleware/ClaimsBuilderMiddleware.cs b/src/Ocelot/Claims/Middleware/ClaimsBuilderMiddleware.cs index 1b1745e2..9a2e4239 100644 --- a/src/Ocelot/Claims/Middleware/ClaimsBuilderMiddleware.cs +++ b/src/Ocelot/Claims/Middleware/ClaimsBuilderMiddleware.cs @@ -26,8 +26,6 @@ namespace Ocelot.Claims.Middleware public async Task Invoke(HttpContext context) { - _logger.LogDebug("started claims middleware"); - if (DownstreamRoute.ReRoute.ClaimsToClaims.Any()) { _logger.LogDebug("this route has instructions to convert claims to other claims"); @@ -42,12 +40,7 @@ namespace Ocelot.Claims.Middleware return; } } - - _logger.LogDebug("calling next middleware"); - await _next.Invoke(context); - - _logger.LogDebug("succesfully called next middleware"); } } } diff --git a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs index e975dcb6..66af481e 100644 --- a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs @@ -166,6 +166,11 @@ namespace Ocelot.DependencyInjection services.TryAddSingleton(); services.TryAddScoped(); services.AddMemoryCache(); + + //Used to log the the start and ending of middleware + services.TryAddSingleton(); + services.AddMiddlewareAnalysis(); + return services; } } diff --git a/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs b/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs index c107a2f5..8fdd2a54 100644 --- a/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs +++ b/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs @@ -30,8 +30,6 @@ namespace Ocelot.DownstreamRouteFinder.Middleware public async Task Invoke(HttpContext context) { - _logger.TraceMiddlewareEntry(); - var upstreamUrlPath = context.Request.Path.ToString().SetLastCharacterAs('/'); _logger.LogDebug("upstream url path is {upstreamUrlPath}", upstreamUrlPath); @@ -43,8 +41,6 @@ namespace Ocelot.DownstreamRouteFinder.Middleware _logger.LogError($"{MiddlwareName} setting pipeline errors. IDownstreamRouteFinder returned {downstreamRoute.Errors.ToErrorString()}"); SetPipelineError(downstreamRoute.Errors); - - _logger.TraceMiddlewareCompleted(); return; } @@ -52,12 +48,7 @@ namespace Ocelot.DownstreamRouteFinder.Middleware SetDownstreamRouteForThisRequest(downstreamRoute.Data); - _logger.TraceInvokeNext(); - await _next.Invoke(context); - - _logger.TraceInvokeNextCompleted(); - _logger.TraceMiddlewareCompleted(); } } } \ No newline at end of file diff --git a/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs b/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs index 631e278a..bd364b5e 100644 --- a/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs +++ b/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs @@ -29,8 +29,6 @@ namespace Ocelot.DownstreamUrlCreator.Middleware public async Task Invoke(HttpContext context) { - _logger.LogDebug("started calling downstream url creator middleware"); - var dsPath = _replacer .Replace(DownstreamRoute.ReRoute.DownstreamPathTemplate, DownstreamRoute.TemplatePlaceholderNameAndValues); @@ -60,11 +58,7 @@ namespace Ocelot.DownstreamUrlCreator.Middleware SetDownstreamUrlForThisRequest(dsUrl.Data.Value); - _logger.LogDebug("calling next middleware"); - await _next.Invoke(context); - - _logger.LogDebug("succesfully called next middleware"); } } } \ No newline at end of file diff --git a/src/Ocelot/Headers/Middleware/HttpRequestHeadersBuilderMiddleware.cs b/src/Ocelot/Headers/Middleware/HttpRequestHeadersBuilderMiddleware.cs index a89d2ec2..8ad155b1 100644 --- a/src/Ocelot/Headers/Middleware/HttpRequestHeadersBuilderMiddleware.cs +++ b/src/Ocelot/Headers/Middleware/HttpRequestHeadersBuilderMiddleware.cs @@ -26,17 +26,15 @@ namespace Ocelot.Headers.Middleware public async Task Invoke(HttpContext context) { - _logger.LogDebug("started calling headers builder middleware"); - if (DownstreamRoute.ReRoute.ClaimsToHeaders.Any()) { - _logger.LogDebug("this route has instructions to convert claims to headers"); + _logger.LogDebug($"{ DownstreamRoute.ReRoute.DownstreamPathTemplate.Value} has instructions to convert claims to headers"); var response = _addHeadersToRequest.SetHeadersOnContext(DownstreamRoute.ReRoute.ClaimsToHeaders, context); if (response.IsError) { - _logger.LogDebug("there was an error setting headers on context, setting pipeline error"); + _logger.LogDebug("Error setting headers on context, setting pipeline error"); SetPipelineError(response.Errors); return; @@ -45,11 +43,7 @@ namespace Ocelot.Headers.Middleware _logger.LogDebug("headers have been set on context"); } - _logger.LogDebug("calling next middleware"); - await _next.Invoke(context); - - _logger.LogDebug("succesfully called next middleware"); } } } diff --git a/src/Ocelot/LoadBalancer/Middleware/LoadBalancingMiddleware.cs b/src/Ocelot/LoadBalancer/Middleware/LoadBalancingMiddleware.cs index 8e26cbf2..e432b21f 100644 --- a/src/Ocelot/LoadBalancer/Middleware/LoadBalancingMiddleware.cs +++ b/src/Ocelot/LoadBalancer/Middleware/LoadBalancingMiddleware.cs @@ -28,41 +28,37 @@ namespace Ocelot.LoadBalancer.Middleware public async Task Invoke(HttpContext context) { - _logger.LogDebug("started calling load balancing middleware"); - var loadBalancer = _loadBalancerHouse.Get(DownstreamRoute.ReRoute.ReRouteKey); if(loadBalancer.IsError) { + _logger.LogDebug("there was an error retriving the loadbalancer, setting pipeline error"); SetPipelineError(loadBalancer.Errors); return; } var hostAndPort = await loadBalancer.Data.Lease(); if(hostAndPort.IsError) - { + { + _logger.LogDebug("there was an error leasing the loadbalancer, setting pipeline error"); SetPipelineError(hostAndPort.Errors); return; } SetHostAndPortForThisRequest(hostAndPort.Data); - _logger.LogDebug("calling next middleware"); - try { await _next.Invoke(context); - - loadBalancer.Data.Release(hostAndPort.Data); } catch (Exception) { - loadBalancer.Data.Release(hostAndPort.Data); - - _logger.LogDebug("error calling next middleware, exception will be thrown to global handler"); + _logger.LogDebug("Exception calling next middleware, exception will be thrown to global handler"); throw; } - - _logger.LogDebug("succesfully called next middleware"); + finally + { + loadBalancer.Data.Release(hostAndPort.Data); + } } } } diff --git a/src/Ocelot/Logging/OcelotDiagnosticListener.cs b/src/Ocelot/Logging/OcelotDiagnosticListener.cs new file mode 100644 index 00000000..06933834 --- /dev/null +++ b/src/Ocelot/Logging/OcelotDiagnosticListener.cs @@ -0,0 +1,27 @@ +using System; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DiagnosticAdapter; + +namespace Ocelot.Logging +{ + public class OcelotDiagnosticListener + { + [DiagnosticName("Microsoft.AspNetCore.MiddlewareAnalysis.MiddlewareStarting")] + public virtual void OnMiddlewareStarting(HttpContext httpContext, string name) + { + Console.WriteLine($"MiddlewareStarting: {name}; {httpContext.Request.Path}"); + } + + [DiagnosticName("Microsoft.AspNetCore.MiddlewareAnalysis.MiddlewareException")] + public virtual void OnMiddlewareException(Exception exception, string name) + { + Console.WriteLine($"MiddlewareException: {name}; {exception.Message}"); + } + + [DiagnosticName("Microsoft.AspNetCore.MiddlewareAnalysis.MiddlewareFinished")] + public virtual void OnMiddlewareFinished(HttpContext httpContext, string name) + { + Console.WriteLine($"MiddlewareFinished: {name}; {httpContext.Response.StatusCode}"); + } + } +} diff --git a/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs b/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs index 457c2448..faf2f648 100644 --- a/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs +++ b/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; +using System.Diagnostics; using IdentityServer4.AccessTokenValidation; using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; using Ocelot.Authentication.Middleware; using Ocelot.Cache.Middleware; using Ocelot.Claims.Middleware; @@ -8,6 +10,7 @@ using Ocelot.DownstreamRouteFinder.Middleware; using Ocelot.DownstreamUrlCreator.Middleware; using Ocelot.Errors.Middleware; using Ocelot.Headers.Middleware; +using Ocelot.Logging; using Ocelot.QueryStrings.Middleware; using Ocelot.Request.Middleware; using Ocelot.Requester.Middleware; @@ -49,10 +52,12 @@ namespace Ocelot.Middleware /// /// /// - public static async Task UseOcelot(this IApplicationBuilder builder, OcelotMiddlewareConfiguration middlewareConfiguration) - { + public static async Task UseOcelot(this IApplicationBuilder builder, OcelotMiddlewareConfiguration middlewareConfiguration) + { await CreateAdministrationArea(builder); + ConfigureDiagnosticListener(builder); + // This is registered to catch any global exceptions that are not handled builder.UseExceptionHandlerMiddleware(); @@ -135,10 +140,10 @@ namespace Ocelot.Middleware private static async Task CreateConfiguration(IApplicationBuilder builder) { - var fileConfig = (IOptions)builder.ApplicationServices.GetService(typeof(IOptions)); - - var configSetter = (IFileConfigurationSetter)builder.ApplicationServices.GetService(typeof(IFileConfigurationSetter)); - + var fileConfig = (IOptions)builder.ApplicationServices.GetService(typeof(IOptions)); + + var configSetter = (IFileConfigurationSetter)builder.ApplicationServices.GetService(typeof(IFileConfigurationSetter)); + var configProvider = (IOcelotConfigurationProvider)builder.ApplicationServices.GetService(typeof(IOcelotConfigurationProvider)); var ocelotConfiguration = await configProvider.Get(); @@ -155,7 +160,7 @@ namespace Ocelot.Middleware ocelotConfiguration = await configProvider.Get(); - if(ocelotConfiguration == null || ocelotConfiguration.Data == null || ocelotConfiguration.IsError) + if (ocelotConfiguration == null || ocelotConfiguration.Data == null || ocelotConfiguration.IsError) { throw new Exception("Unable to start Ocelot: ocelot configuration was not returned by provider."); } @@ -169,15 +174,15 @@ namespace Ocelot.Middleware var identityServerConfiguration = (IIdentityServerConfiguration)builder.ApplicationServices.GetService(typeof(IIdentityServerConfiguration)); - if(!string.IsNullOrEmpty(configuration.AdministrationPath) && identityServerConfiguration != null) + if (!string.IsNullOrEmpty(configuration.AdministrationPath) && identityServerConfiguration != null) { var urlFinder = (IBaseUrlFinder)builder.ApplicationServices.GetService(typeof(IBaseUrlFinder)); - var baseSchemeUrlAndPort = urlFinder.Find(); - + var baseSchemeUrlAndPort = urlFinder.Find(); + builder.Map(configuration.AdministrationPath, app => { - var identityServerUrl = $"{baseSchemeUrlAndPort}/{configuration.AdministrationPath.Remove(0,1)}"; + var identityServerUrl = $"{baseSchemeUrlAndPort}/{configuration.AdministrationPath.Remove(0, 1)}"; app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions { @@ -195,7 +200,23 @@ namespace Ocelot.Middleware }); } } - + + /// + /// Configure a DiagnosticListener to listen for diagnostic events when the middleware starts and ends + /// + /// + private static void ConfigureDiagnosticListener(IApplicationBuilder builder) + { + + var env = builder.ApplicationServices.GetService(); + if (!env.IsProduction()) + { + var listener = builder.ApplicationServices.GetService(); + var diagnosticListener = builder.ApplicationServices.GetService(); + diagnosticListener.SubscribeWithAdapter(listener); + } + } + private static void UseIfNotNull(this IApplicationBuilder builder, Func, Task> middleware) { if (middleware != null) diff --git a/src/Ocelot/Ocelot.csproj b/src/Ocelot/Ocelot.csproj index 8fdb917d..554570ad 100644 --- a/src/Ocelot/Ocelot.csproj +++ b/src/Ocelot/Ocelot.csproj @@ -21,10 +21,12 @@ + + diff --git a/src/Ocelot/QueryStrings/Middleware/QueryStringBuilderMiddleware.cs b/src/Ocelot/QueryStrings/Middleware/QueryStringBuilderMiddleware.cs index edeee51c..355692ec 100644 --- a/src/Ocelot/QueryStrings/Middleware/QueryStringBuilderMiddleware.cs +++ b/src/Ocelot/QueryStrings/Middleware/QueryStringBuilderMiddleware.cs @@ -26,11 +26,9 @@ namespace Ocelot.QueryStrings.Middleware public async Task Invoke(HttpContext context) { - _logger.LogDebug("started calling query string builder middleware"); - if (DownstreamRoute.ReRoute.ClaimsToQueries.Any()) { - _logger.LogDebug("this route has instructions to convert claims to queries"); + _logger.LogDebug($"{DownstreamRoute.ReRoute.DownstreamPathTemplate.Value} has instructions to convert claims to queries"); var response = _addQueriesToRequest.SetQueriesOnContext(DownstreamRoute.ReRoute.ClaimsToQueries, context); @@ -43,11 +41,7 @@ namespace Ocelot.QueryStrings.Middleware } } - _logger.LogDebug("calling next middleware"); - await _next.Invoke(context); - - _logger.LogDebug("succesfully called next middleware"); } } } diff --git a/src/Ocelot/RateLimit/Middleware/ClientRateLimitMiddleware.cs b/src/Ocelot/RateLimit/Middleware/ClientRateLimitMiddleware.cs index dffc6448..819bbf1d 100644 --- a/src/Ocelot/RateLimit/Middleware/ClientRateLimitMiddleware.cs +++ b/src/Ocelot/RateLimit/Middleware/ClientRateLimitMiddleware.cs @@ -31,18 +31,13 @@ namespace Ocelot.RateLimit.Middleware public async Task Invoke(HttpContext context) { - _logger.TraceMiddlewareEntry(); - var options = DownstreamRoute.ReRoute.RateLimitOptions; // check if rate limiting is enabled if (!DownstreamRoute.ReRoute.EnableEndpointEndpointRateLimiting) { _logger.LogDebug($"EndpointRateLimiting is not enabled for {DownstreamRoute.ReRoute.DownstreamPathTemplate}"); + await _next.Invoke(context); - _logger.TraceInvokeNext(); - await _next.Invoke(context); - _logger.TraceInvokeNextCompleted(); - _logger.TraceMiddlewareCompleted(); return; } // compute identity from request @@ -52,11 +47,8 @@ namespace Ocelot.RateLimit.Middleware if (IsWhitelisted(identity, options)) { _logger.LogDebug($"{DownstreamRoute.ReRoute.DownstreamPathTemplate} is white listed from rate limiting"); + await _next.Invoke(context); - _logger.TraceInvokeNext(); - await _next.Invoke(context); - _logger.TraceInvokeNextCompleted(); - _logger.TraceMiddlewareCompleted(); return; } @@ -77,21 +69,18 @@ namespace Ocelot.RateLimit.Middleware // break execution await ReturnQuotaExceededResponse(context, options, retryAfter); - _logger.TraceMiddlewareCompleted(); return; } } //set X-Rate-Limit headers for the longest period if (!options.DisableRateLimitHeaders) { - var headers = _processor.GetRateLimitHeaders( context,identity, options); + var headers = _processor.GetRateLimitHeaders(context, identity, options); context.Response.OnStarting(SetRateLimitHeaders, state: headers); } - _logger.TraceInvokeNext(); - await _next.Invoke(context); - _logger.TraceInvokeNextCompleted(); - _logger.TraceMiddlewareCompleted(); + await _next.Invoke(context); + } public virtual ClientRequestIdentity SetIdentity(HttpContext httpContext, RateLimitOptions option) @@ -104,10 +93,10 @@ namespace Ocelot.RateLimit.Middleware return new ClientRequestIdentity( clientId, - httpContext.Request.Path.ToString().ToLowerInvariant(), + httpContext.Request.Path.ToString().ToLowerInvariant(), httpContext.Request.Method.ToLowerInvariant() ); - } + } public bool IsWhitelisted(ClientRequestIdentity requestIdentity, RateLimitOptions option) { diff --git a/src/Ocelot/RequestId/Middleware/RequestIdMiddleware.cs b/src/Ocelot/RequestId/Middleware/RequestIdMiddleware.cs index 1e1a955c..37ed6d0c 100644 --- a/src/Ocelot/RequestId/Middleware/RequestIdMiddleware.cs +++ b/src/Ocelot/RequestId/Middleware/RequestIdMiddleware.cs @@ -17,7 +17,7 @@ namespace Ocelot.RequestId.Middleware public RequestIdMiddleware(RequestDelegate next, IOcelotLoggerFactory loggerFactory, IRequestScopedDataRepository requestScopedDataRepository) - :base(requestScopedDataRepository) + : base(requestScopedDataRepository) { _next = next; _logger = loggerFactory.CreateLogger(); @@ -25,17 +25,11 @@ namespace Ocelot.RequestId.Middleware } public async Task Invoke(HttpContext context) - { - _logger.TraceMiddlewareEntry(); - + { SetOcelotRequestId(context); - _logger.LogDebug("set requestId"); - - _logger.TraceInvokeNext(); - await _next.Invoke(context); - _logger.TraceInvokeNextCompleted(); - _logger.TraceMiddlewareCompleted(); + _logger.LogDebug("set requestId"); + await _next.Invoke(context); } private void SetOcelotRequestId(HttpContext context) diff --git a/src/Ocelot/Responder/Middleware/ResponderMiddleware.cs b/src/Ocelot/Responder/Middleware/ResponderMiddleware.cs index 7e843486..2b6f52f1 100644 --- a/src/Ocelot/Responder/Middleware/ResponderMiddleware.cs +++ b/src/Ocelot/Responder/Middleware/ResponderMiddleware.cs @@ -34,10 +34,7 @@ namespace Ocelot.Responder.Middleware public async Task Invoke(HttpContext context) { - _logger.TraceMiddlewareEntry(); - _logger.TraceInvokeNext(); - await _next.Invoke(context); - _logger.TraceInvokeNextCompleted(); + await _next.Invoke(context); if (PipelineError) { @@ -51,7 +48,6 @@ namespace Ocelot.Responder.Middleware _logger.LogDebug("no pipeline errors, setting and returning completed response"); await _responder.SetResponseOnHttpContext(context, HttpResponseMessage); } - _logger.TraceMiddlewareCompleted(); } private void SetErrorResponse(HttpContext context, List errors) From 518c0a9129e3aa37d5a74041c0292941a3479282 Mon Sep 17 00:00:00 2001 From: "tom.pallister" Date: Fri, 16 Jun 2017 15:55:31 +0100 Subject: [PATCH 02/35] removed release notes to get a build? --- build.cake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.cake b/build.cake index 184b1faa..6cacb0f0 100644 --- a/build.cake +++ b/build.cake @@ -229,11 +229,11 @@ Task("CreatePackages") EnsureDirectoryExists(packagesDir); CopyFiles("./src/**/Ocelot.*.nupkg", packagesDir); - GenerateReleaseNotes(releaseNotesFile); + //GenerateReleaseNotes(releaseNotesFile); System.IO.File.WriteAllLines(artifactsFile, new[]{ "nuget:Ocelot." + buildVersion + ".nupkg", - "releaseNotes:releasenotes.md" + //"releaseNotes:releasenotes.md" }); if (AppVeyor.IsRunningOnAppVeyor) From 5aa1596db48eb824ae6760d5d787eac7cfb56c84 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Sat, 17 Jun 2017 14:23:54 +0100 Subject: [PATCH 03/35] Revert "removed release notes to get a build?" This reverts commit 518c0a9129e3aa37d5a74041c0292941a3479282. --- build.cake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.cake b/build.cake index 6cacb0f0..184b1faa 100644 --- a/build.cake +++ b/build.cake @@ -229,11 +229,11 @@ Task("CreatePackages") EnsureDirectoryExists(packagesDir); CopyFiles("./src/**/Ocelot.*.nupkg", packagesDir); - //GenerateReleaseNotes(releaseNotesFile); + GenerateReleaseNotes(releaseNotesFile); System.IO.File.WriteAllLines(artifactsFile, new[]{ "nuget:Ocelot." + buildVersion + ".nupkg", - //"releaseNotes:releasenotes.md" + "releaseNotes:releasenotes.md" }); if (AppVeyor.IsRunningOnAppVeyor) From 6786b5b0afa4fc6b9ad1253e76f1e8ad02f19703 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Sat, 17 Jun 2017 14:24:13 +0100 Subject: [PATCH 04/35] Revert "Fixes to get build running again on macOS. Basically, re-applying changes from #41" This reverts commit f452e8ea86c893090d5a700fa109279891765171. --- build.cake | 46 +++++++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/build.cake b/build.cake index 184b1faa..eddaffc0 100644 --- a/build.cake +++ b/build.cake @@ -92,7 +92,7 @@ Task("Version") if (AppVeyor.IsRunningOnAppVeyor) { Information("Persisting version number..."); - PersistVersion(committedVersion, nugetVersion); + PersistVersion(nugetVersion); buildVersion = nugetVersion; } else @@ -229,7 +229,7 @@ Task("CreatePackages") EnsureDirectoryExists(packagesDir); CopyFiles("./src/**/Ocelot.*.nupkg", packagesDir); - GenerateReleaseNotes(releaseNotesFile); + GenerateReleaseNotes(); System.IO.File.WriteAllLines(artifactsFile, new[]{ "nuget:Ocelot." + buildVersion + ".nupkg", @@ -251,9 +251,9 @@ Task("ReleasePackagesToUnstableFeed") .IsDependentOn("CreatePackages") .Does(() => { - if (ShouldPublishToUnstableFeed(nugetFeedUnstableBranchFilter, versioning.BranchName)) + if (ShouldPublishToUnstableFeed()) { - PublishPackages(packagesDir, artifactsFile, nugetFeedUnstableKey, nugetFeedUnstableUploadUrl, nugetFeedUnstableSymbolsUploadUrl); + PublishPackages(nugetFeedUnstableKey, nugetFeedUnstableUploadUrl, nugetFeedUnstableSymbolsUploadUrl); } }); @@ -306,7 +306,7 @@ Task("ReleasePackagesToStableFeed") .IsDependentOn("DownloadGitHubReleaseArtifacts") .Does(() => { - PublishPackages(packagesDir, artifactsFile, nugetFeedStableKey, nugetFeedStableUploadUrl, nugetFeedStableSymbolsUploadUrl); + PublishPackages(nugetFeedStableKey, nugetFeedStableUploadUrl, nugetFeedStableSymbolsUploadUrl); }); Task("Release") @@ -326,9 +326,9 @@ private GitVersion GetNuGetVersionForCommit() } /// Updates project version in all of our projects -private void PersistVersion(string committedVersion, string newVersion) +private void PersistVersion(string version) { - Information(string.Format("We'll search all csproj files for {0} and replace with {1}...", committedVersion, newVersion)); + Information(string.Format("We'll search all csproj files for {0} and replace with {1}...", committedVersion, version)); var projectFiles = GetFiles("./**/*.csproj"); @@ -339,30 +339,24 @@ private void PersistVersion(string committedVersion, string newVersion) Information(string.Format("Updating {0}...", file)); var updatedProjectFile = System.IO.File.ReadAllText(file) - .Replace(committedVersion, newVersion); + .Replace(committedVersion, version); System.IO.File.WriteAllText(file, updatedProjectFile); } } /// generates release notes based on issues closed in GitHub since the last release -private void GenerateReleaseNotes(ConvertableFilePath file) +private void GenerateReleaseNotes() { - if(!IsRunningOnWindows()) - { - Warning("We are not running on Windows so we cannot generate release notes."); - return; - } - - Information("Generating release notes at " + file); + Information("Generating release notes at " + releaseNotesFile); var releaseNotesExitCode = StartProcess( @"tools/GitReleaseNotes/tools/gitreleasenotes.exe", - new ProcessSettings { Arguments = ". /o " + file }); + new ProcessSettings { Arguments = ". /o " + releaseNotesFile }); - if (string.IsNullOrEmpty(System.IO.File.ReadAllText(file))) + if (string.IsNullOrEmpty(System.IO.File.ReadAllText(releaseNotesFile))) { - System.IO.File.WriteAllText(file, "No issues closed since last release"); + System.IO.File.WriteAllText(releaseNotesFile, "No issues closed since last release"); } if (releaseNotesExitCode != 0) @@ -372,7 +366,7 @@ private void GenerateReleaseNotes(ConvertableFilePath file) } /// Publishes code and symbols packages to nuget feed, based on contents of artifacts file -private void PublishPackages(ConvertableDirectoryPath packagesDir, ConvertableFilePath artifactsFile, string feedApiKey, string codeFeedUrl, string symbolFeedUrl) +private void PublishPackages(string feedApiKey, string codeFeedUrl, string symbolFeedUrl) { var artifacts = System.IO.File .ReadAllLines(artifactsFile) @@ -381,8 +375,6 @@ private void PublishPackages(ConvertableDirectoryPath packagesDir, ConvertableFi var codePackage = packagesDir + File(artifacts["nuget"]); - Information("Pushing package " + codePackage); - NuGetPush( codePackage, new NuGetPushSettings { @@ -409,17 +401,17 @@ private string GetResource(string url) } } -private bool ShouldPublishToUnstableFeed(string filter, string branchName) +private bool ShouldPublishToUnstableFeed() { - var regex = new System.Text.RegularExpressions.Regex(filter); - var publish = regex.IsMatch(branchName); + var regex = new System.Text.RegularExpressions.Regex(nugetFeedUnstableBranchFilter); + var publish = regex.IsMatch(versioning.BranchName); if (publish) { - Information("Branch " + branchName + " will be published to the unstable feed"); + Information("Branch " + versioning.BranchName + " will be published to the unstable feed"); } else { - Information("Branch " + branchName + " will not be published to the unstable feed"); + Information("Branch " + versioning.BranchName + " will not be published to the unstable feed"); } return publish; } \ No newline at end of file From af9e31e2b1f7e14c507b52c4c14da55126e55de1 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Sat, 17 Jun 2017 14:41:55 +0100 Subject: [PATCH 05/35] Revert "Revert "Fixes to get build running again on macOS. Basically, re-applying changes from #41"" This reverts commit 6786b5b0afa4fc6b9ad1253e76f1e8ad02f19703. --- build.cake | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/build.cake b/build.cake index eddaffc0..184b1faa 100644 --- a/build.cake +++ b/build.cake @@ -92,7 +92,7 @@ Task("Version") if (AppVeyor.IsRunningOnAppVeyor) { Information("Persisting version number..."); - PersistVersion(nugetVersion); + PersistVersion(committedVersion, nugetVersion); buildVersion = nugetVersion; } else @@ -229,7 +229,7 @@ Task("CreatePackages") EnsureDirectoryExists(packagesDir); CopyFiles("./src/**/Ocelot.*.nupkg", packagesDir); - GenerateReleaseNotes(); + GenerateReleaseNotes(releaseNotesFile); System.IO.File.WriteAllLines(artifactsFile, new[]{ "nuget:Ocelot." + buildVersion + ".nupkg", @@ -251,9 +251,9 @@ Task("ReleasePackagesToUnstableFeed") .IsDependentOn("CreatePackages") .Does(() => { - if (ShouldPublishToUnstableFeed()) + if (ShouldPublishToUnstableFeed(nugetFeedUnstableBranchFilter, versioning.BranchName)) { - PublishPackages(nugetFeedUnstableKey, nugetFeedUnstableUploadUrl, nugetFeedUnstableSymbolsUploadUrl); + PublishPackages(packagesDir, artifactsFile, nugetFeedUnstableKey, nugetFeedUnstableUploadUrl, nugetFeedUnstableSymbolsUploadUrl); } }); @@ -306,7 +306,7 @@ Task("ReleasePackagesToStableFeed") .IsDependentOn("DownloadGitHubReleaseArtifacts") .Does(() => { - PublishPackages(nugetFeedStableKey, nugetFeedStableUploadUrl, nugetFeedStableSymbolsUploadUrl); + PublishPackages(packagesDir, artifactsFile, nugetFeedStableKey, nugetFeedStableUploadUrl, nugetFeedStableSymbolsUploadUrl); }); Task("Release") @@ -326,9 +326,9 @@ private GitVersion GetNuGetVersionForCommit() } /// Updates project version in all of our projects -private void PersistVersion(string version) +private void PersistVersion(string committedVersion, string newVersion) { - Information(string.Format("We'll search all csproj files for {0} and replace with {1}...", committedVersion, version)); + Information(string.Format("We'll search all csproj files for {0} and replace with {1}...", committedVersion, newVersion)); var projectFiles = GetFiles("./**/*.csproj"); @@ -339,24 +339,30 @@ private void PersistVersion(string version) Information(string.Format("Updating {0}...", file)); var updatedProjectFile = System.IO.File.ReadAllText(file) - .Replace(committedVersion, version); + .Replace(committedVersion, newVersion); System.IO.File.WriteAllText(file, updatedProjectFile); } } /// generates release notes based on issues closed in GitHub since the last release -private void GenerateReleaseNotes() +private void GenerateReleaseNotes(ConvertableFilePath file) { - Information("Generating release notes at " + releaseNotesFile); + if(!IsRunningOnWindows()) + { + Warning("We are not running on Windows so we cannot generate release notes."); + return; + } + + Information("Generating release notes at " + file); var releaseNotesExitCode = StartProcess( @"tools/GitReleaseNotes/tools/gitreleasenotes.exe", - new ProcessSettings { Arguments = ". /o " + releaseNotesFile }); + new ProcessSettings { Arguments = ". /o " + file }); - if (string.IsNullOrEmpty(System.IO.File.ReadAllText(releaseNotesFile))) + if (string.IsNullOrEmpty(System.IO.File.ReadAllText(file))) { - System.IO.File.WriteAllText(releaseNotesFile, "No issues closed since last release"); + System.IO.File.WriteAllText(file, "No issues closed since last release"); } if (releaseNotesExitCode != 0) @@ -366,7 +372,7 @@ private void GenerateReleaseNotes() } /// Publishes code and symbols packages to nuget feed, based on contents of artifacts file -private void PublishPackages(string feedApiKey, string codeFeedUrl, string symbolFeedUrl) +private void PublishPackages(ConvertableDirectoryPath packagesDir, ConvertableFilePath artifactsFile, string feedApiKey, string codeFeedUrl, string symbolFeedUrl) { var artifacts = System.IO.File .ReadAllLines(artifactsFile) @@ -375,6 +381,8 @@ private void PublishPackages(string feedApiKey, string codeFeedUrl, string symbo var codePackage = packagesDir + File(artifacts["nuget"]); + Information("Pushing package " + codePackage); + NuGetPush( codePackage, new NuGetPushSettings { @@ -401,17 +409,17 @@ private string GetResource(string url) } } -private bool ShouldPublishToUnstableFeed() +private bool ShouldPublishToUnstableFeed(string filter, string branchName) { - var regex = new System.Text.RegularExpressions.Regex(nugetFeedUnstableBranchFilter); - var publish = regex.IsMatch(versioning.BranchName); + var regex = new System.Text.RegularExpressions.Regex(filter); + var publish = regex.IsMatch(branchName); if (publish) { - Information("Branch " + versioning.BranchName + " will be published to the unstable feed"); + Information("Branch " + branchName + " will be published to the unstable feed"); } else { - Information("Branch " + versioning.BranchName + " will not be published to the unstable feed"); + Information("Branch " + branchName + " will not be published to the unstable feed"); } return publish; } \ No newline at end of file From bc7bfc8917a4c2a29a05dfea22cd8c38d4ad28a3 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Sat, 17 Jun 2017 14:42:05 +0100 Subject: [PATCH 06/35] Revert "Revert "removed release notes to get a build?"" This reverts commit 5aa1596db48eb824ae6760d5d787eac7cfb56c84. --- build.cake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.cake b/build.cake index 184b1faa..6cacb0f0 100644 --- a/build.cake +++ b/build.cake @@ -229,11 +229,11 @@ Task("CreatePackages") EnsureDirectoryExists(packagesDir); CopyFiles("./src/**/Ocelot.*.nupkg", packagesDir); - GenerateReleaseNotes(releaseNotesFile); + //GenerateReleaseNotes(releaseNotesFile); System.IO.File.WriteAllLines(artifactsFile, new[]{ "nuget:Ocelot." + buildVersion + ".nupkg", - "releaseNotes:releasenotes.md" + //"releaseNotes:releasenotes.md" }); if (AppVeyor.IsRunningOnAppVeyor) From 2d94884c6f6ac35e3bec13a0a729995fde983303 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Fri, 23 Jun 2017 11:25:23 +0100 Subject: [PATCH 07/35] trying to get cluster working --- .../IdentityServerConfigurationCreator.cs | 6 ++- .../Provider/IIdentityServerConfiguration.cs | 2 + .../Provider/IdentityServerConfiguration.cs | 6 ++- .../ServiceCollectionExtensions.cs | 15 +++++- .../Ocelot.AcceptanceTests.csproj | 2 +- .../AdministrationTests.cs | 48 +++++++++++++++++++ .../Ocelot.IntegrationTests.csproj | 2 +- 7 files changed, 75 insertions(+), 6 deletions(-) diff --git a/src/Ocelot/Configuration/Creator/IdentityServerConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/IdentityServerConfigurationCreator.cs index 48819608..6ed3b6c0 100644 --- a/src/Ocelot/Configuration/Creator/IdentityServerConfigurationCreator.cs +++ b/src/Ocelot/Configuration/Creator/IdentityServerConfigurationCreator.cs @@ -13,6 +13,8 @@ namespace Ocelot.Configuration.Creator var username = Environment.GetEnvironmentVariable("OCELOT_USERNAME"); var hash = Environment.GetEnvironmentVariable("OCELOT_HASH"); var salt = Environment.GetEnvironmentVariable("OCELOT_SALT"); + var credentialsSigningCertificateLocation = Environment.GetEnvironmentVariable("OCELOT_CERTIFICATE"); + var credentialsSigningCertificatePassword = Environment.GetEnvironmentVariable("OCELOT_CERTIFICATE_PASSWORD"); return new IdentityServerConfiguration( "admin", @@ -28,7 +30,9 @@ namespace Ocelot.Configuration.Creator new List { new User("admin", username, hash, salt) - } + }, + credentialsSigningCertificateLocation, + credentialsSigningCertificatePassword ); } } diff --git a/src/Ocelot/Configuration/Provider/IIdentityServerConfiguration.cs b/src/Ocelot/Configuration/Provider/IIdentityServerConfiguration.cs index bb66265f..0a388abb 100644 --- a/src/Ocelot/Configuration/Provider/IIdentityServerConfiguration.cs +++ b/src/Ocelot/Configuration/Provider/IIdentityServerConfiguration.cs @@ -17,5 +17,7 @@ namespace Ocelot.Configuration.Provider AccessTokenType AccessTokenType {get;} bool RequireClientSecret {get;} List Users {get;} + string CredentialsSigningCertificateLocation { get; } + string CredentialsSigningCertificatePassword { get; } } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/Provider/IdentityServerConfiguration.cs b/src/Ocelot/Configuration/Provider/IdentityServerConfiguration.cs index f0f6897d..881d6f5a 100644 --- a/src/Ocelot/Configuration/Provider/IdentityServerConfiguration.cs +++ b/src/Ocelot/Configuration/Provider/IdentityServerConfiguration.cs @@ -17,7 +17,7 @@ namespace Ocelot.Configuration.Provider IEnumerable grantType, AccessTokenType accessTokenType, bool requireClientSecret, - List users) + List users, string credentialsSigningCertificateLocation, string credentialsSigningCertificatePassword) { ApiName = apiName; RequireHttps = requireHttps; @@ -30,6 +30,8 @@ namespace Ocelot.Configuration.Provider AccessTokenType = accessTokenType; RequireClientSecret = requireClientSecret; Users = users; + CredentialsSigningCertificateLocation = credentialsSigningCertificateLocation; + CredentialsSigningCertificatePassword = credentialsSigningCertificatePassword; } public string ApiName { get; private set; } @@ -43,5 +45,7 @@ namespace Ocelot.Configuration.Provider public AccessTokenType AccessTokenType {get;private set;} public bool RequireClientSecret {get;private set;} public List Users {get;private set;} + public string CredentialsSigningCertificateLocation { get; private set; } + public string CredentialsSigningCertificatePassword { get; private set; } } } \ No newline at end of file diff --git a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs index d52341fe..6b33f5c7 100644 --- a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs @@ -41,6 +41,8 @@ using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Reflection; +using System.Security.Cryptography.X509Certificates; +using Microsoft.IdentityModel.Tokens; using Ocelot.Configuration; using FileConfigurationProvider = Ocelot.Configuration.Provider.FileConfigurationProvider; @@ -87,8 +89,7 @@ namespace Ocelot.DependencyInjection { services.TryAddSingleton(identityServerConfiguration); services.TryAddSingleton(); - services.AddIdentityServer() - .AddTemporarySigningCredential() + var identityServerBuilder = services.AddIdentityServer() .AddInMemoryApiResources(new List { new ApiResource @@ -120,6 +121,16 @@ namespace Ocelot.DependencyInjection RequireClientSecret = identityServerConfiguration.RequireClientSecret } }).AddResourceOwnerValidator(); + + if (string.IsNullOrEmpty(identityServerConfiguration.CredentialsSigningCertificateLocation) || string.IsNullOrEmpty(identityServerConfiguration.CredentialsSigningCertificatePassword)) + { + identityServerBuilder.AddTemporarySigningCredential(); + } + else + { + var cert = new X509Certificate2(identityServerConfiguration.CredentialsSigningCertificateLocation, identityServerConfiguration.CredentialsSigningCertificatePassword); + identityServerBuilder.AddSigningCredential(cert); + } } var assembly = typeof(FileConfigurationController).GetTypeInfo().Assembly; diff --git a/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj b/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj index 0faafe84..94e30391 100644 --- a/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj +++ b/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj @@ -15,7 +15,7 @@ - + PreserveNewest diff --git a/test/Ocelot.IntegrationTests/AdministrationTests.cs b/test/Ocelot.IntegrationTests/AdministrationTests.cs index 2fa2c05c..3f7ea18a 100644 --- a/test/Ocelot.IntegrationTests/AdministrationTests.cs +++ b/test/Ocelot.IntegrationTests/AdministrationTests.cs @@ -19,15 +19,19 @@ namespace Ocelot.IntegrationTests public class AdministrationTests : IDisposable { private readonly HttpClient _httpClient; + private readonly HttpClient _httpClientTwo; private HttpResponseMessage _response; private IWebHost _builder; private IWebHostBuilder _webHostBuilder; private readonly string _ocelotBaseUrl; private BearerToken _token; + private IWebHostBuilder _webHostBuilderTwo; + private IWebHost _builderTwo; public AdministrationTests() { _httpClient = new HttpClient(); + _httpClientTwo = new HttpClient(); _ocelotBaseUrl = "http://localhost:5000"; _httpClient.BaseAddress = new Uri(_ocelotBaseUrl); } @@ -70,6 +74,27 @@ namespace Ocelot.IntegrationTests .BDDfy(); } + [Fact] + public void should_be_able_to_use_token_from_ocelot_a_on_ocelot_b() + { + var configuration = new FileConfiguration + { + GlobalConfiguration = new FileGlobalConfiguration + { + AdministrationPath = "/administration" + } + }; + + this.Given(x => GivenThereIsAConfiguration(configuration)) + .And(x => GivenOcelotIsRunning()) + .And(x => GivenIHaveAnOcelotToken("/administration")) + .And(x => GivenIHaveAddedATokenToMyRequest()) + .And(x => GivenAnotherOcelotIsRunning("http://localhost:5007")) + .When(x => WhenIGetUrlOnTheSecondOcelot("/administration/configuration")) + .Then(x => ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .BDDfy(); + } + [Fact] public void should_return_file_configuration() { @@ -193,6 +218,29 @@ namespace Ocelot.IntegrationTests .BDDfy(); } + private void GivenAnotherOcelotIsRunning(string baseUrl) + { + _httpClientTwo.BaseAddress = new Uri(baseUrl); + + _webHostBuilderTwo = new WebHostBuilder() + .UseUrls(baseUrl) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .ConfigureServices(x => { + x.AddSingleton(_webHostBuilder); + }) + .UseStartup(); + + _builderTwo = _webHostBuilderTwo.Build(); + + _builderTwo.Start(); + } + + private void WhenIGetUrlOnTheSecondOcelot(string url) + { + _response = _httpClientTwo.GetAsync(url).Result; + } + private void WhenIPostOnTheApiGateway(string url, FileConfiguration updatedConfiguration) { var json = JsonConvert.SerializeObject(updatedConfiguration); diff --git a/test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.csproj b/test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.csproj index db4b23d2..59513b38 100644 --- a/test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.csproj +++ b/test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.csproj @@ -15,7 +15,7 @@ - + PreserveNewest From 6cdf4e67df417bc514da9b445f9053e662f7b525 Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Fri, 23 Jun 2017 15:17:40 +0100 Subject: [PATCH 08/35] can now use tokens from ocelot a on ocelot b when using admin area --- .gitignore | 1 + .../ServiceCollectionExtensions.cs | 5 ++++- .../Middleware/OcelotMiddlewareExtensions.cs | 1 - .../Ocelot.AcceptanceTests.csproj | 2 +- test/Ocelot.AcceptanceTests/appsettings.json | 10 ++++++++++ .../AdministrationTests.cs | 13 +++++++++++-- test/Ocelot.IntegrationTests/appsettings.json | 4 ++-- test/Ocelot.IntegrationTests/idsrv3test.pfx | Bin 0 -> 3395 bytes 8 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 test/Ocelot.AcceptanceTests/appsettings.json create mode 100644 test/Ocelot.IntegrationTests/idsrv3test.pfx diff --git a/.gitignore b/.gitignore index a2902800..f5dfbc4d 100644 --- a/.gitignore +++ b/.gitignore @@ -183,6 +183,7 @@ ClientBin/ *.dbmdl *.dbproj.schemaview *.pfx +!idsrv3test.pfx *.publishsettings node_modules/ orleans.codegen.cs diff --git a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs index 6b33f5c7..ae0e35de 100644 --- a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs @@ -89,7 +89,10 @@ namespace Ocelot.DependencyInjection { services.TryAddSingleton(identityServerConfiguration); services.TryAddSingleton(); - var identityServerBuilder = services.AddIdentityServer() + var identityServerBuilder = services + .AddIdentityServer(options => { + options.IssuerUri = "Ocelot"; + }) .AddInMemoryApiResources(new List { new ApiResource diff --git a/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs b/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs index 3f98f959..d2e91c6d 100644 --- a/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs +++ b/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs @@ -181,7 +181,6 @@ namespace Ocelot.Middleware builder.Map(configuration.AdministrationPath, app => { var identityServerUrl = $"{baseSchemeUrlAndPort}/{configuration.AdministrationPath.Remove(0,1)}"; - app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions { Authority = identityServerUrl, diff --git a/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj b/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj index 94e30391..08bbf527 100644 --- a/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj +++ b/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj @@ -15,7 +15,7 @@ - + PreserveNewest diff --git a/test/Ocelot.AcceptanceTests/appsettings.json b/test/Ocelot.AcceptanceTests/appsettings.json new file mode 100644 index 00000000..df0788de --- /dev/null +++ b/test/Ocelot.AcceptanceTests/appsettings.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "IncludeScopes": true, + "LogLevel": { + "Default": "Error", + "System": "Error", + "Microsoft": "Error" + } + } +} diff --git a/test/Ocelot.IntegrationTests/AdministrationTests.cs b/test/Ocelot.IntegrationTests/AdministrationTests.cs index 3f7ea18a..b03d587e 100644 --- a/test/Ocelot.IntegrationTests/AdministrationTests.cs +++ b/test/Ocelot.IntegrationTests/AdministrationTests.cs @@ -86,9 +86,9 @@ namespace Ocelot.IntegrationTests }; this.Given(x => GivenThereIsAConfiguration(configuration)) + .And(x => GivenIdentityServerSigningEnvironmentalVariablesAreSet()) .And(x => GivenOcelotIsRunning()) .And(x => GivenIHaveAnOcelotToken("/administration")) - .And(x => GivenIHaveAddedATokenToMyRequest()) .And(x => GivenAnotherOcelotIsRunning("http://localhost:5007")) .When(x => WhenIGetUrlOnTheSecondOcelot("/administration/configuration")) .Then(x => ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) @@ -227,7 +227,7 @@ namespace Ocelot.IntegrationTests .UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) .ConfigureServices(x => { - x.AddSingleton(_webHostBuilder); + x.AddSingleton(_webHostBuilderTwo); }) .UseStartup(); @@ -236,8 +236,15 @@ namespace Ocelot.IntegrationTests _builderTwo.Start(); } + private void GivenIdentityServerSigningEnvironmentalVariablesAreSet() + { + Environment.SetEnvironmentVariable("OCELOT_CERTIFICATE", "idsrv3test.pfx"); + Environment.SetEnvironmentVariable("OCELOT_CERTIFICATE_PASSWORD", "idsrv3test"); + } + private void WhenIGetUrlOnTheSecondOcelot(string url) { + _httpClientTwo.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _token.AccessToken); _response = _httpClientTwo.GetAsync(url).Result; } @@ -353,6 +360,8 @@ namespace Ocelot.IntegrationTests public void Dispose() { + Environment.SetEnvironmentVariable("OCELOT_CERTIFICATE", ""); + Environment.SetEnvironmentVariable("OCELOT_CERTIFICATE_PASSWORD", ""); _builder?.Dispose(); _httpClient?.Dispose(); } diff --git a/test/Ocelot.IntegrationTests/appsettings.json b/test/Ocelot.IntegrationTests/appsettings.json index 503cc778..df0788de 100644 --- a/test/Ocelot.IntegrationTests/appsettings.json +++ b/test/Ocelot.IntegrationTests/appsettings.json @@ -3,8 +3,8 @@ "IncludeScopes": true, "LogLevel": { "Default": "Error", - "System": "Information", - "Microsoft": "Information" + "System": "Error", + "Microsoft": "Error" } } } diff --git a/test/Ocelot.IntegrationTests/idsrv3test.pfx b/test/Ocelot.IntegrationTests/idsrv3test.pfx new file mode 100644 index 0000000000000000000000000000000000000000..0247dea03f0cc23694291f21310f3ae88880e2bb GIT binary patch literal 3395 zcmY*ac{tQ<7yiu{V_$|rA%;e>y=E+9O_nU#g|hFBC`-tmWsqeoSyGW9LYA!AlQm0d zlqs?cuRUcMvVK$7_r34+{c)aipZh-Nxy~QY_1q{N(`7J-3WZ}lgwlyV(0Q=O1fl`u z;TYE;IL2iPy@0|&nf_0rK7rt<4^TL2G9|X44F8>Cqz8fXaF7!e4sw9vh0_0zrd-Yp zq5aB`c0pwf*#!pE3`1~`u};|qLmAL66%SqGD&c1ok7w*g=3CPGVk4GBqUnz5R$^lb z8Dv(rRpfX7yvJ$AZ8B=IukK|?oWq7THPW9AE8<%>%oONtPAOw&x8_?KHa0J|WVwA0 zIe9iq|#j@0h-r2z9#p>N7n4=mGfXBZdZv zm>}$|9($ZRdyt-g#VGBa?>B!qNzif-i+FE)kucwfM0uQ_?eH5E22H7{O&W(b9&xxe z%p<>vWCX)-exQO)Be=&=gf&-c#+j`(NUetfn}WVXG{= z^!3S{N|*XdJW@10Ikf3}LcuN>qA~Ixlg<}c;VO{NzpbcV)gX{XXMvCF$|Bihu8%Mj`v7 z@JI#bMy0mL?ntjDyu>tItFCrcM?2T4qxi{DAYXF4re+jt!0KM!4AX1-`m6J2B-j7$ ztQmXW9+nsyVA76pGD!SNDBJX7<=P3^TAtMP*S&|$8V_zcInNp6F})=P6L9WM3skx( zrU*k+zF?-S=hmjpL4Q3zv>!AS5ZdH` zP7@1%4o~2pGsTCkqHI#fTE9t6L}0I0RV#X80*5W8dQ!d^3i!EAcx!{g?Ymhx9_uH| z%5-;5L5^5@FPajHS9ShoBMyy!p(c{qxOAL#hI6ENh505_rZ0?SGHg>G?cH-JcX$bP zvvcygKZ|q33xcOvl0F>Lq;-3oT1}&U{+hFQhdrnZ&f3Cd?*G~+e;NZj-CLQ#d7u*d z-zLck*=~$_*oTD=7glD2s_n4ZBbndKCJM<*Y#U_RIHLGB-|y!WU`T^)1|P6xbeP|G zVeM+?bDY~u1~eh71YCS>5m|2W++)$^^VxHSdmxwhWqlh$#}_R*QJIE}!YhyC22(}y z-pGi)Mp$4isupi_SdyK1kwa|ypqYxDZM%%-W8XLUrq=uHuIVLfoLXn0Ft*+*&7DasMmP3gdi3$so3cjv zU3_I_!HIUJ-KLn$?yVs^q%Nt?{K4vH$8|KG-fP7I-JGh){ZkukKp&IeTFS zofK|@;`zesc<{wV&~=^Lpxwgq@1SZU!pFuL4xnXwJhXzpFXWPHqe5C^&F$XOKSyA*?hARwF^42%X)?En0pbR1|X1Ofs80A>9z2}c|9=>s8v zEFceP0#bk)B`W|LfCL~z!7_mQA0!RPQ8WpPf}*g$)hhsoqDlYhLQ^z_KfESzA7%UR z0wA<8pCMoXxBgEJg#e8I z^!ZaN7vLt~Loo#6Kiktl^Kj613iSpI0w}5OUj_7kE&%=Q0@7Z?>>U#@$=@yzfrG{o ztFTv(L~LX}xO!x0^EITtLxl@_o6uy5gghAR{hz9rAUI9X6qKa_Nw%q za~SdO27));Ss1O7WmAmU?z>@+sX7%|EH>F*@OZUVn!`%vFPjg13@;Tl|_JIFJuO?ibe+@(=CitY0KN zmhw8P&DGlJBqvEH_i~51(xCCqvU$O5a^w(gap!{;x$=mI;>(I{4_^3{xSVlt0*&Z-y38aD8;?f`*U1VzA?{YPa$fn^V7$cGLd)&c%khfmt-qvZ_d8X! z7hHsG8{dHEPrBwl**uN9qgJ5pDa-DS;*TkBvMr}WsGRp(tl&q zOLj#>q5fr!g3h>N*4Lo!^2f&yedb9`Kc@UII#(J*#=~mQpg7_^@Qad_`7&Rw^Q13P zmkj26C2^Lfg&(Un^M{l&&Z~Al#>~&po-IRgbH;zV|EZU6sq2W4r<`>`jAnHJX0F#X zoYLuTJJ&S__HOHM}CU)!}{mUnHM4&H-PJ zDgU|rTaFE6VJ^#8$-7}h}^b=$AFm^Ju%|Irt#Xm@y!x8ht)nP}yX zak6LD=XrWjz}YIk=NKi;Oyzuyhr4N#>$;BIHeVmO7CwR&BH~$h($R>lxm#|jH)hMo z7Cl?fME$4w@i!`TUwnfzepq`tb2MXQ>vjOez4DO&G+ zwbxqf;c;Lz7e^2GJN4&pn)*n036&#X{M)L}3jNt9WQoG#Ltw0 zBSd@4uASn_19~vFMd|jhEOlmOnzg#t-W`Y8`{ihls#Ej*@-YyvQR5@XB{Zgn*UU@bPjBb)ma-dM*TyAY#Qr-I?}ssTqWiQUU~9nVL8urj8g zB=?6~(E%Bt>5<*!OPB%-9y0pkl!uu8}JyuP^C{VwK-!6&8CcOsFR z#AD|e+mNE9i#41w#l(h}rbw&h^*Xp8>93ZTvg}r-DJps1W6hRpeV*HGw|(EWnX7>t zi;7~9X)yDN{8DJzLpxCoH*tL3SHK!$Z}tQc<%NTk$t)S*4<=4>wFvMd!y)pV_liw) z7Z+8=AXg^QgwL(&DRsQU5*({(LDt{G-4Rx#dhx6AP+_msH%Jue6QCy=B0w?y#4k$7;> z=5ttmpV&vFVv}ZY>6NE%#+W))M)nU;WMS%-mtLT!)&4oAMhnY2Hb@dJUGXLb^4wIex}=co7n{7tD1N!| zw63xzN%ImPTf3iZ?X@yq6*F$jX5my$Q%SSyOrlD)y}jkyw`e{y&l34ahp)821A!iS z4-;-p@j6Gn!f>FJQ2ZzwD76?f6_^_WN5dA?3G%E0bF79+L#MT|(Yv~t5ct?-mV0Fj V%$88{h~I%@Xjg7x^oQR@_8&Ry9S;Bi literal 0 HcmV?d00001 From e96d66139f58ea94352b1d2b85d9b0e5bd4025b1 Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Sat, 24 Jun 2017 13:04:25 +0100 Subject: [PATCH 09/35] boost test coverage --- .../Creator/AuthenticationHandlerCreator.cs | 1 + ...IdentityServerConfigurationCreatorTests.cs | 16 +++ .../Errors/ExceptionHandlerMiddlewareTests.cs | 125 ++++++++++++++++++ 3 files changed, 142 insertions(+) create mode 100644 test/Ocelot.UnitTests/Configuration/IdentityServerConfigurationCreatorTests.cs create mode 100644 test/Ocelot.UnitTests/Errors/ExceptionHandlerMiddlewareTests.cs diff --git a/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs b/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs index 96713fb0..1fcc50fb 100644 --- a/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs +++ b/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs @@ -1,3 +1,4 @@ +using System; using IdentityServer4.AccessTokenValidation; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; diff --git a/test/Ocelot.UnitTests/Configuration/IdentityServerConfigurationCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/IdentityServerConfigurationCreatorTests.cs new file mode 100644 index 00000000..8d100e10 --- /dev/null +++ b/test/Ocelot.UnitTests/Configuration/IdentityServerConfigurationCreatorTests.cs @@ -0,0 +1,16 @@ +using Ocelot.Configuration.Creator; +using Shouldly; +using Xunit; + +namespace Ocelot.UnitTests.Configuration +{ + public class IdentityServerConfigurationCreatorTests + { + [Fact] + public void happy_path_only_exists_for_test_coverage_even_uncle_bob_probably_wouldnt_test_this() + { + var result = IdentityServerConfigurationCreator.GetIdentityServerConfiguration(); + result.ApiName.ShouldBe("admin"); + } + } +} \ No newline at end of file diff --git a/test/Ocelot.UnitTests/Errors/ExceptionHandlerMiddlewareTests.cs b/test/Ocelot.UnitTests/Errors/ExceptionHandlerMiddlewareTests.cs new file mode 100644 index 00000000..41beffdc --- /dev/null +++ b/test/Ocelot.UnitTests/Errors/ExceptionHandlerMiddlewareTests.cs @@ -0,0 +1,125 @@ +using System; +using System.IO; +using System.Net; +using System.Net.Http; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Moq; +using Ocelot.DownstreamRouteFinder; +using Ocelot.DownstreamUrlCreator; +using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer; +using Ocelot.Errors.Middleware; +using Ocelot.Infrastructure.RequestData; +using Ocelot.Logging; +using Ocelot.Responses; +using Ocelot.Values; +using Shouldly; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests.Errors +{ + public class ExceptionHandlerMiddlewareTests + { + private readonly Mock _scopedRepository; + private readonly string _url; + private TestServer _server; + private HttpClient _client; + private HttpResponseMessage _result; + + public ExceptionHandlerMiddlewareTests() + { + _url = "http://localhost:52879"; + _scopedRepository = new Mock(); + } + + [Fact] + public void should_call_next_middleware() + { + this.Given(_ => GivenASuccessfulRequest()) + .When(_ => WhenIMakeTheRequest()) + .Then(_ => ThenTheResponseIsOk()) + .BDDfy(); + } + + [Fact] + public void should_call_return_error() + { + this.Given(_ => GivenAnError()) + .When(_ => WhenIMakeTheRequest()) + .Then(_ => ThenTheResponseIsError()) + .BDDfy(); + } + + private void ThenTheResponseIsOk() + { + _result.StatusCode.ShouldBe(HttpStatusCode.OK); + } + + private void ThenTheResponseIsError() + { + _result.StatusCode.ShouldBe(HttpStatusCode.InternalServerError); + } + + private void WhenIMakeTheRequest() + { + _result = _client.GetAsync("/").Result; + } + + private void GivenASuccessfulRequest() + { + var builder = new WebHostBuilder() + .ConfigureServices(x => + { + x.AddSingleton(); + x.AddLogging(); + x.AddSingleton(_scopedRepository.Object); + }) + .UseUrls(_url) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseUrls(_url) + .Configure(app => + { + app.UseExceptionHandlerMiddleware(); + app.Run(async context => + { + context.Response.StatusCode = 200; + }); + }); + + _server = new TestServer(builder); + _client = _server.CreateClient(); + } + + private void GivenAnError() + { + var builder = new WebHostBuilder() + .ConfigureServices(x => + { + x.AddSingleton(); + x.AddLogging(); + x.AddSingleton(_scopedRepository.Object); + }) + .UseUrls(_url) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseUrls(_url) + .Configure(app => + { + app.UseExceptionHandlerMiddleware(); + app.Use(async (context, next) => + { + throw new Exception("BOOM"); + }); + }); + + _server = new TestServer(builder); + _client = _server.CreateClient(); + } + } +} \ No newline at end of file From 26e7621798ed81d1f51abfee96879066b2f5742a Mon Sep 17 00:00:00 2001 From: TomPallister Date: Sun, 25 Jun 2017 22:07:19 +0100 Subject: [PATCH 10/35] fixed stupid double request bug from bad merge --- src/Ocelot/RateLimit/Middleware/ClientRateLimitMiddleware.cs | 4 ---- test/Ocelot.ManualTest/appsettings.json | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Ocelot/RateLimit/Middleware/ClientRateLimitMiddleware.cs b/src/Ocelot/RateLimit/Middleware/ClientRateLimitMiddleware.cs index 2997504a..e8dbaeef 100644 --- a/src/Ocelot/RateLimit/Middleware/ClientRateLimitMiddleware.cs +++ b/src/Ocelot/RateLimit/Middleware/ClientRateLimitMiddleware.cs @@ -36,8 +36,6 @@ namespace Ocelot.RateLimit.Middleware if (!DownstreamRoute.ReRoute.EnableEndpointEndpointRateLimiting) { _logger.LogDebug($"EndpointRateLimiting is not enabled for {DownstreamRoute.ReRoute.DownstreamPathTemplate}"); - await _next.Invoke(context); - await _next.Invoke(context); return; } @@ -48,8 +46,6 @@ namespace Ocelot.RateLimit.Middleware if (IsWhitelisted(identity, options)) { _logger.LogDebug($"{DownstreamRoute.ReRoute.DownstreamPathTemplate} is white listed from rate limiting"); - await _next.Invoke(context); - await _next.Invoke(context); return; } diff --git a/test/Ocelot.ManualTest/appsettings.json b/test/Ocelot.ManualTest/appsettings.json index cb4c8665..7327a7b9 100644 --- a/test/Ocelot.ManualTest/appsettings.json +++ b/test/Ocelot.ManualTest/appsettings.json @@ -2,7 +2,7 @@ "Logging": { "IncludeScopes": true, "LogLevel": { - "Default": "Information", + "Default": "Trace", "System": "Information", "Microsoft": "Information" } From 6209681b2c15caac8dcb01a27420c3943bdf4f07 Mon Sep 17 00:00:00 2001 From: Nick Sharp Date: Mon, 26 Jun 2017 11:50:58 +0100 Subject: [PATCH 11/35] Adding code ##BROKEN TESTS## --- .../Creator/AuthenticationHandlerCreator.cs | 12 +- .../Configuration/AuthenticationOptions.cs | 32 +- .../Builder/AuthenticationOptionsBuilder.cs | 78 +-- .../Creator/AuthenticationOptionsCreator.cs | 25 +- .../File/FileAuthenticationOptions.cs | 9 +- .../AuthenticationTests.cs | 446 +++++++++--------- .../AuthorisationTests.cs | 364 +++++++------- .../ClaimsToHeadersForwardingTests.cs | 118 ++--- .../ClaimsToQueryStringForwardingTests.cs | 118 ++--- .../AuthenticationOptionsCreatorTests.cs | 74 +-- .../FileConfigurationCreatorTests.cs | 266 +++++------ 11 files changed, 799 insertions(+), 743 deletions(-) diff --git a/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs b/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs index 96713fb0..ea2515f9 100644 --- a/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs +++ b/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs @@ -5,6 +5,8 @@ using Ocelot.Responses; namespace Ocelot.Authentication.Handler.Creator { + using Ocelot.Configuration; + using AuthenticationOptions = Configuration.AuthenticationOptions; /// @@ -16,14 +18,16 @@ namespace Ocelot.Authentication.Handler.Creator { var builder = app.New(); + var authenticationConfig = authOptions.Config as IdentityServerConfig; + builder.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions { - Authority = authOptions.ProviderRootUrl, - ApiName = authOptions.ApiName, - RequireHttpsMetadata = authOptions.RequireHttps, + Authority = authenticationConfig.ProviderRootUrl, + ApiName = authenticationConfig.ApiName, + RequireHttpsMetadata = authenticationConfig.RequireHttps, AllowedScopes = authOptions.AllowedScopes, SupportedTokens = SupportedTokens.Both, - ApiSecret = authOptions.ApiSecret + ApiSecret = authenticationConfig.ApiSecret }); var authenticationNext = builder.Build(); diff --git a/src/Ocelot/Configuration/AuthenticationOptions.cs b/src/Ocelot/Configuration/AuthenticationOptions.cs index 223491b2..cfb76fe4 100644 --- a/src/Ocelot/Configuration/AuthenticationOptions.cs +++ b/src/Ocelot/Configuration/AuthenticationOptions.cs @@ -4,22 +4,38 @@ namespace Ocelot.Configuration { public class AuthenticationOptions { - public AuthenticationOptions(string provider, string providerRootUrl, string apiName, bool requireHttps, List allowedScopes, string apiSecret) + public AuthenticationOptions(string provider, List allowedScopes, IAuthenticationConfig config) { Provider = provider; - ProviderRootUrl = providerRootUrl; - ApiName = apiName; - RequireHttps = requireHttps; - AllowedScopes = allowedScopes; - ApiSecret = apiSecret; + AllowedScopes = allowedScopes; + Config = config; } public string Provider { get; private set; } + + public List AllowedScopes { get; private set; } + + public IAuthenticationConfig Config { get; } + } + + + public interface IAuthenticationConfig + { + } + + public class IdentityServerConfig : IAuthenticationConfig + { + public IdentityServerConfig(string providerRootUrl, string apiName, bool requireHttps, string apiSecret) + { + ProviderRootUrl = providerRootUrl; + ApiName = apiName; + RequireHttps = requireHttps; + ApiSecret = apiSecret; + } + public string ProviderRootUrl { get; private set; } public string ApiName { get; private set; } public string ApiSecret { get; private set; } public bool RequireHttps { get; private set; } - public List AllowedScopes { get; private set; } - } } diff --git a/src/Ocelot/Configuration/Builder/AuthenticationOptionsBuilder.cs b/src/Ocelot/Configuration/Builder/AuthenticationOptionsBuilder.cs index 0c648489..bd20717c 100644 --- a/src/Ocelot/Configuration/Builder/AuthenticationOptionsBuilder.cs +++ b/src/Ocelot/Configuration/Builder/AuthenticationOptionsBuilder.cs @@ -6,51 +6,71 @@ namespace Ocelot.Configuration.Builder { private string _provider; - private string _providerRootUrl; - private string _apiName; - private string _apiSecret; - private bool _requireHttps; + private List _allowedScopes; + private IAuthenticationConfig _config; + public AuthenticationOptionsBuilder WithProvider(string provider) { _provider = provider; return this; } - public AuthenticationOptionsBuilder WithProviderRootUrl(string providerRootUrl) - { - _providerRootUrl = providerRootUrl; - return this; - } - - public AuthenticationOptionsBuilder WithApiName(string apiName) - { - _apiName = apiName; - return this; - } - - public AuthenticationOptionsBuilder WithApiSecret(string apiSecret) - { - _apiSecret = apiSecret; - return this; - } - - public AuthenticationOptionsBuilder WithRequireHttps(bool requireHttps) - { - _requireHttps = requireHttps; - return this; - } - public AuthenticationOptionsBuilder WithAllowedScopes(List allowedScopes) { _allowedScopes = allowedScopes; return this; } + public AuthenticationOptionsBuilder WithConfiguration(IAuthenticationConfig config) + { + _config = config; + return this; + } + public AuthenticationOptions Build() { - return new AuthenticationOptions(_provider, _providerRootUrl, _apiName, _requireHttps, _allowedScopes, _apiSecret); + return new AuthenticationOptions(_provider, _allowedScopes, _config); + } + } + + public class IdentityServerConfigBuilder + { + private string _providerRootUrl; + private string _apiName; + private string _apiSecret; + private bool _requireHttps; + + public IdentityServerConfigBuilder WithProviderRootUrl(string providerRootUrl) + { + _providerRootUrl = providerRootUrl; + return this; + } + + public IdentityServerConfigBuilder WithApiName(string apiName) + { + _apiName = apiName; + return this; + } + + public IdentityServerConfigBuilder WithApiSecret(string apiSecret) + { + _apiSecret = apiSecret; + return this; + } + + public IdentityServerConfigBuilder WithRequireHttps(bool requireHttps) + { + _requireHttps = requireHttps; + return this; + } + + + + public IdentityServerConfig Build() + { + return new IdentityServerConfig(_providerRootUrl, _apiName, _requireHttps, _apiSecret); } } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/Creator/AuthenticationOptionsCreator.cs b/src/Ocelot/Configuration/Creator/AuthenticationOptionsCreator.cs index 583748e1..ac185cdf 100644 --- a/src/Ocelot/Configuration/Creator/AuthenticationOptionsCreator.cs +++ b/src/Ocelot/Configuration/Creator/AuthenticationOptionsCreator.cs @@ -7,14 +7,25 @@ namespace Ocelot.Configuration.Creator { public AuthenticationOptions Create(FileReRoute fileReRoute) { + var authenticationConfig = new AuthenticationConfigCreator().Create(fileReRoute.AuthenticationOptions); + return new AuthenticationOptionsBuilder() - .WithProvider(fileReRoute.AuthenticationOptions?.Provider) - .WithProviderRootUrl(fileReRoute.AuthenticationOptions?.ProviderRootUrl) - .WithApiName(fileReRoute.AuthenticationOptions?.ApiName) - .WithRequireHttps(fileReRoute.AuthenticationOptions.RequireHttps) - .WithAllowedScopes(fileReRoute.AuthenticationOptions?.AllowedScopes) - .WithApiSecret(fileReRoute.AuthenticationOptions?.ApiSecret) - .Build(); + .WithProvider(fileReRoute.AuthenticationOptions?.Provider) + .WithAllowedScopes(fileReRoute.AuthenticationOptions?.AllowedScopes) + .WithConfiguration(authenticationConfig) + .Build(); + } + } + + public class AuthenticationConfigCreator + { + public IAuthenticationConfig Create(FileAuthenticationOptions authenticationOptions) + { + return new IdentityServerConfigBuilder() + .WithApiName(authenticationOptions.IdentityServerConfig?.ApiName) + .WithApiSecret(authenticationOptions.IdentityServerConfig?.ApiSecret) + .WithProviderRootUrl(authenticationOptions.IdentityServerConfig?.ProviderRootUrl) + .WithRequireHttps(authenticationOptions.IdentityServerConfig.RequireHttps).Build(); } } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/File/FileAuthenticationOptions.cs b/src/Ocelot/Configuration/File/FileAuthenticationOptions.cs index 63e6347c..9f2de967 100644 --- a/src/Ocelot/Configuration/File/FileAuthenticationOptions.cs +++ b/src/Ocelot/Configuration/File/FileAuthenticationOptions.cs @@ -6,14 +6,19 @@ namespace Ocelot.Configuration.File { public FileAuthenticationOptions() { - AllowedScopes = new List(); + AllowedScopes = new List(); } public string Provider { get; set; } + public List AllowedScopes { get; set; } + public FileIdentityServerConfig IdentityServerConfig { get; set; } + } + + public class FileIdentityServerConfig + { public string ProviderRootUrl { get; set; } public string ApiName { get; set; } public bool RequireHttps { get; set; } - public List AllowedScopes { get; set; } public string ApiSecret { get; set; } } } diff --git a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs index c0d143b9..060cb5bd 100644 --- a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs @@ -34,241 +34,241 @@ namespace Ocelot.AcceptanceTests _steps = new Steps(); } - [Fact] - public void should_return_401_using_identity_server_access_token() - { - var configuration = new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - DownstreamPathTemplate = _downstreamServicePath, - DownstreamPort = _downstreamServicePort, - DownstreamHost = _downstreamServiceHost, - DownstreamScheme = _downstreamServiceScheme, - UpstreamPathTemplate = "/", - UpstreamHttpMethod = new List { "Post" }, - AuthenticationOptions = new FileAuthenticationOptions - { - AllowedScopes = new List(), - Provider = "IdentityServer", - ProviderRootUrl = _identityServerRootUrl, - RequireHttps = false, - ApiName = "api", - ApiSecret = "secret" - } - } - } - }; + //[Fact] + //public void should_return_401_using_identity_server_access_token() + //{ + // var configuration = new FileConfiguration + // { + // ReRoutes = new List + // { + // new FileReRoute + // { + // DownstreamPathTemplate = _downstreamServicePath, + // DownstreamPort = _downstreamServicePort, + // DownstreamHost = _downstreamServiceHost, + // DownstreamScheme = _downstreamServiceScheme, + // UpstreamPathTemplate = "/", + // UpstreamHttpMethod = new List { "Post" }, + // AuthenticationOptions = new FileAuthenticationOptions + // { + // AllowedScopes = new List(), + // Provider = "IdentityServer", + // ProviderRootUrl = _identityServerRootUrl, + // RequireHttps = false, + // ApiName = "api", + // ApiSecret = "secret" + // } + // } + // } + // }; - this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) - .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) - .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) - .And(x => _steps.GivenThePostHasContent("postContent")) - .When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) - .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized)) - .BDDfy(); - } + // this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) + // .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) + // .And(x => _steps.GivenThereIsAConfiguration(configuration)) + // .And(x => _steps.GivenOcelotIsRunning()) + // .And(x => _steps.GivenThePostHasContent("postContent")) + // .When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) + // .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized)) + // .BDDfy(); + //} - [Fact] - public void should_return_401_using_identity_server_reference_token() - { - var configuration = new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - DownstreamPathTemplate = _downstreamServicePath, - DownstreamPort = _downstreamServicePort, - DownstreamHost = _downstreamServiceHost, - DownstreamScheme = _downstreamServiceScheme, - UpstreamPathTemplate = "/", - UpstreamHttpMethod = new List { "Post" }, - AuthenticationOptions = new FileAuthenticationOptions - { - AllowedScopes = new List(), - Provider = "IdentityServer", - ProviderRootUrl = _identityServerRootUrl, - RequireHttps = false, - ApiName = "api", - ApiSecret = "secret" - } - } - } - }; + //[Fact] + //public void should_return_401_using_identity_server_reference_token() + //{ + // var configuration = new FileConfiguration + // { + // ReRoutes = new List + // { + // new FileReRoute + // { + // DownstreamPathTemplate = _downstreamServicePath, + // DownstreamPort = _downstreamServicePort, + // DownstreamHost = _downstreamServiceHost, + // DownstreamScheme = _downstreamServiceScheme, + // UpstreamPathTemplate = "/", + // UpstreamHttpMethod = new List { "Post" }, + // AuthenticationOptions = new FileAuthenticationOptions + // { + // AllowedScopes = new List(), + // Provider = "IdentityServer", + // ProviderRootUrl = _identityServerRootUrl, + // RequireHttps = false, + // ApiName = "api", + // ApiSecret = "secret" + // } + // } + // } + // }; - this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Reference)) - .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) - .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) - .And(x => _steps.GivenThePostHasContent("postContent")) - .When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) - .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized)) - .BDDfy(); - } + // this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Reference)) + // .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) + // .And(x => _steps.GivenThereIsAConfiguration(configuration)) + // .And(x => _steps.GivenOcelotIsRunning()) + // .And(x => _steps.GivenThePostHasContent("postContent")) + // .When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) + // .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized)) + // .BDDfy(); + //} - [Fact] - public void should_return_response_200_using_identity_server() - { - var configuration = new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - DownstreamPathTemplate = _downstreamServicePath, - DownstreamPort = _downstreamServicePort, - DownstreamHost = _downstreamServiceHost, - DownstreamScheme = _downstreamServiceScheme, - UpstreamPathTemplate = "/", - UpstreamHttpMethod = new List { "Get" }, - AuthenticationOptions = new FileAuthenticationOptions - { - AllowedScopes = new List(), - Provider = "IdentityServer", - ProviderRootUrl = _identityServerRootUrl, - RequireHttps = false, - ApiName = "api", - ApiSecret = "secret" - } - } - } - }; + //[Fact] + //public void should_return_response_200_using_identity_server() + //{ + // var configuration = new FileConfiguration + // { + // ReRoutes = new List + // { + // new FileReRoute + // { + // DownstreamPathTemplate = _downstreamServicePath, + // DownstreamPort = _downstreamServicePort, + // DownstreamHost = _downstreamServiceHost, + // DownstreamScheme = _downstreamServiceScheme, + // UpstreamPathTemplate = "/", + // UpstreamHttpMethod = new List { "Get" }, + // AuthenticationOptions = new FileAuthenticationOptions + // { + // AllowedScopes = new List(), + // Provider = "IdentityServer", + // ProviderRootUrl = _identityServerRootUrl, + // RequireHttps = false, + // ApiName = "api", + // ApiSecret = "secret" + // } + // } + // } + // }; - this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) - .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 200, "Hello from Laura")) - .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) - .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) - .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) - .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) - .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) - .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) - .BDDfy(); - } + // this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) + // .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 200, "Hello from Laura")) + // .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) + // .And(x => _steps.GivenThereIsAConfiguration(configuration)) + // .And(x => _steps.GivenOcelotIsRunning()) + // .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + // .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + // .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + // .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) + // .BDDfy(); + //} - [Fact] - public void should_return_response_401_using_identity_server_with_token_requested_for_other_api() - { - var configuration = new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - DownstreamPathTemplate = _downstreamServicePath, - DownstreamPort = _downstreamServicePort, - DownstreamHost = _downstreamServiceHost, - DownstreamScheme = _downstreamServiceScheme, - UpstreamPathTemplate = "/", - UpstreamHttpMethod = new List { "Get" }, - AuthenticationOptions = new FileAuthenticationOptions - { - AllowedScopes = new List(), - Provider = "IdentityServer", - ProviderRootUrl = _identityServerRootUrl, - RequireHttps = false, - ApiName = "api", - ApiSecret = "secret" - } - } - } - }; + //[Fact] + //public void should_return_response_401_using_identity_server_with_token_requested_for_other_api() + //{ + // var configuration = new FileConfiguration + // { + // ReRoutes = new List + // { + // new FileReRoute + // { + // DownstreamPathTemplate = _downstreamServicePath, + // DownstreamPort = _downstreamServicePort, + // DownstreamHost = _downstreamServiceHost, + // DownstreamScheme = _downstreamServiceScheme, + // UpstreamPathTemplate = "/", + // UpstreamHttpMethod = new List { "Get" }, + // AuthenticationOptions = new FileAuthenticationOptions + // { + // AllowedScopes = new List(), + // Provider = "IdentityServer", + // ProviderRootUrl = _identityServerRootUrl, + // RequireHttps = false, + // ApiName = "api", + // ApiSecret = "secret" + // } + // } + // } + // }; - this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) - .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 200, "Hello from Laura")) - .And(x => _steps.GivenIHaveATokenForApi2(_identityServerRootUrl)) - .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) - .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) - .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) - .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized)) - .BDDfy(); - } + // this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) + // .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 200, "Hello from Laura")) + // .And(x => _steps.GivenIHaveATokenForApi2(_identityServerRootUrl)) + // .And(x => _steps.GivenThereIsAConfiguration(configuration)) + // .And(x => _steps.GivenOcelotIsRunning()) + // .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + // .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + // .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized)) + // .BDDfy(); + //} - [Fact] - public void should_return_201_using_identity_server_access_token() - { - var configuration = new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - DownstreamPathTemplate = _downstreamServicePath, - DownstreamPort = _downstreamServicePort, - DownstreamHost = _downstreamServiceHost, - DownstreamScheme = _downstreamServiceScheme, - UpstreamPathTemplate = "/", - UpstreamHttpMethod = new List { "Post" }, + //[Fact] + //public void should_return_201_using_identity_server_access_token() + //{ + // var configuration = new FileConfiguration + // { + // ReRoutes = new List + // { + // new FileReRoute + // { + // DownstreamPathTemplate = _downstreamServicePath, + // DownstreamPort = _downstreamServicePort, + // DownstreamHost = _downstreamServiceHost, + // DownstreamScheme = _downstreamServiceScheme, + // UpstreamPathTemplate = "/", + // UpstreamHttpMethod = new List { "Post" }, - AuthenticationOptions = new FileAuthenticationOptions - { - AllowedScopes = new List(), - Provider = "IdentityServer", - ProviderRootUrl = _identityServerRootUrl, - RequireHttps = false, - ApiName = "api", - ApiSecret = "secret" - } - } - } - }; + // AuthenticationOptions = new FileAuthenticationOptions + // { + // AllowedScopes = new List(), + // Provider = "IdentityServer", + // ProviderRootUrl = _identityServerRootUrl, + // RequireHttps = false, + // ApiName = "api", + // ApiSecret = "secret" + // } + // } + // } + // }; - this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) - .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) - .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) - .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) - .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) - .And(x => _steps.GivenThePostHasContent("postContent")) - .When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) - .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Created)) - .BDDfy(); - } + // this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) + // .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) + // .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) + // .And(x => _steps.GivenThereIsAConfiguration(configuration)) + // .And(x => _steps.GivenOcelotIsRunning()) + // .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + // .And(x => _steps.GivenThePostHasContent("postContent")) + // .When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) + // .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Created)) + // .BDDfy(); + //} - [Fact] - public void should_return_201_using_identity_server_reference_token() - { - var configuration = new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - DownstreamPathTemplate = _downstreamServicePath, - DownstreamPort = _downstreamServicePort, - DownstreamHost = _downstreamServiceHost, - DownstreamScheme = _downstreamServiceScheme, - UpstreamPathTemplate = "/", - UpstreamHttpMethod = new List { "Post" }, - AuthenticationOptions = new FileAuthenticationOptions - { - AllowedScopes = new List(), - Provider = "IdentityServer", - ProviderRootUrl = _identityServerRootUrl, - RequireHttps = false, - ApiName = "api", - ApiSecret = "secret" - } - } - } - }; + //[Fact] + //public void should_return_201_using_identity_server_reference_token() + //{ + // var configuration = new FileConfiguration + // { + // ReRoutes = new List + // { + // new FileReRoute + // { + // DownstreamPathTemplate = _downstreamServicePath, + // DownstreamPort = _downstreamServicePort, + // DownstreamHost = _downstreamServiceHost, + // DownstreamScheme = _downstreamServiceScheme, + // UpstreamPathTemplate = "/", + // UpstreamHttpMethod = new List { "Post" }, + // AuthenticationOptions = new FileAuthenticationOptions + // { + // AllowedScopes = new List(), + // Provider = "IdentityServer", + // ProviderRootUrl = _identityServerRootUrl, + // RequireHttps = false, + // ApiName = "api", + // ApiSecret = "secret" + // } + // } + // } + // }; - this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Reference)) - .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) - .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) - .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) - .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) - .And(x => _steps.GivenThePostHasContent("postContent")) - .When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) - .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Created)) - .BDDfy(); - } + // this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Reference)) + // .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) + // .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) + // .And(x => _steps.GivenThereIsAConfiguration(configuration)) + // .And(x => _steps.GivenOcelotIsRunning()) + // .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + // .And(x => _steps.GivenThePostHasContent("postContent")) + // .When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) + // .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Created)) + // .BDDfy(); + //} private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody) { diff --git a/test/Ocelot.AcceptanceTests/AuthorisationTests.cs b/test/Ocelot.AcceptanceTests/AuthorisationTests.cs index 011bb679..30dc636f 100644 --- a/test/Ocelot.AcceptanceTests/AuthorisationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthorisationTests.cs @@ -28,195 +28,195 @@ namespace Ocelot.AcceptanceTests _steps = new Steps(); } - [Fact] - public void should_return_response_200_authorising_route() - { - var configuration = new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - DownstreamPathTemplate = "/", - DownstreamPort = 51876, - DownstreamScheme = "http", - DownstreamHost = "localhost", - UpstreamPathTemplate = "/", - UpstreamHttpMethod = new List { "Get" }, - AuthenticationOptions = new FileAuthenticationOptions - { - AllowedScopes = new List(), - Provider = "IdentityServer", - ProviderRootUrl = "http://localhost:51888", - RequireHttps = false, - ApiName = "api", - ApiSecret = "secret" - }, - AddHeadersToRequest = - { - {"CustomerId", "Claims[CustomerId] > value"}, - {"LocationId", "Claims[LocationId] > value"}, - {"UserType", "Claims[sub] > value[0] > |"}, - {"UserId", "Claims[sub] > value[1] > |"} - }, - AddClaimsToRequest = - { - {"CustomerId", "Claims[CustomerId] > value"}, - {"UserType", "Claims[sub] > value[0] > |"}, - {"UserId", "Claims[sub] > value[1] > |"} - }, - RouteClaimsRequirement = - { - {"UserType", "registered"} - } - } - } - }; + //[Fact] + //public void should_return_response_200_authorising_route() + //{ + // var configuration = new FileConfiguration + // { + // ReRoutes = new List + // { + // new FileReRoute + // { + // DownstreamPathTemplate = "/", + // DownstreamPort = 51876, + // DownstreamScheme = "http", + // DownstreamHost = "localhost", + // UpstreamPathTemplate = "/", + // UpstreamHttpMethod = new List { "Get" }, + // AuthenticationOptions = new FileAuthenticationOptions + // { + //AllowedScopes = new List(), + // Provider = "IdentityServer", + // ProviderRootUrl = "http://localhost:51888", + // RequireHttps = false, + //ApiName = "api", + // ApiSecret = "secret" + // }, + // AddHeadersToRequest = + // { + // {"CustomerId", "Claims[CustomerId] > value"}, + // {"LocationId", "Claims[LocationId] > value"}, + // {"UserType", "Claims[sub] > value[0] > |"}, + // {"UserId", "Claims[sub] > value[1] > |"} + // }, + // AddClaimsToRequest = + // { + // {"CustomerId", "Claims[CustomerId] > value"}, + // {"UserType", "Claims[sub] > value[0] > |"}, + // {"UserId", "Claims[sub] > value[1] > |"} + // }, + // RouteClaimsRequirement = + // { + // {"UserType", "registered"} + // } + // } + // } + // }; - this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) - .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) - .And(x => _steps.GivenIHaveAToken("http://localhost:51888")) - .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) - .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) - .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) - .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) - .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) - .BDDfy(); - } + // this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) + // .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) + // .And(x => _steps.GivenIHaveAToken("http://localhost:51888")) + // .And(x => _steps.GivenThereIsAConfiguration(configuration)) + // .And(x => _steps.GivenOcelotIsRunning()) + // .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + // .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + // .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + // .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) + // .BDDfy(); + //} - [Fact] - public void should_return_response_403_authorising_route() - { - var configuration = new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - DownstreamPathTemplate = "/", - DownstreamPort = 51876, - DownstreamScheme = "http", - DownstreamHost = "localhost", - UpstreamPathTemplate = "/", - UpstreamHttpMethod = new List { "Get" }, - AuthenticationOptions = new FileAuthenticationOptions - { - AllowedScopes = new List(), - Provider = "IdentityServer", - ProviderRootUrl = "http://localhost:51888", - RequireHttps = false, - ApiName = "api", - ApiSecret = "secret" - }, - AddHeadersToRequest = - { - {"CustomerId", "Claims[CustomerId] > value"}, - {"LocationId", "Claims[LocationId] > value"}, - {"UserType", "Claims[sub] > value[0] > |"}, - {"UserId", "Claims[sub] > value[1] > |"} - }, - AddClaimsToRequest = - { - {"CustomerId", "Claims[CustomerId] > value"}, - {"UserId", "Claims[sub] > value[1] > |"} - }, - RouteClaimsRequirement = - { - {"UserType", "registered"} - } - } - } - }; + //[Fact] + //public void should_return_response_403_authorising_route() + //{ + // var configuration = new FileConfiguration + // { + // ReRoutes = new List + // { + // new FileReRoute + // { + // DownstreamPathTemplate = "/", + // DownstreamPort = 51876, + // DownstreamScheme = "http", + // DownstreamHost = "localhost", + // UpstreamPathTemplate = "/", + // UpstreamHttpMethod = new List { "Get" }, + // AuthenticationOptions = new FileAuthenticationOptions + // { + //AllowedScopes = new List(), + // Provider = "IdentityServer", + // ProviderRootUrl = "http://localhost:51888", + // RequireHttps = false, + //ApiName = "api", + // ApiSecret = "secret" + // }, + // AddHeadersToRequest = + // { + // {"CustomerId", "Claims[CustomerId] > value"}, + // {"LocationId", "Claims[LocationId] > value"}, + // {"UserType", "Claims[sub] > value[0] > |"}, + // {"UserId", "Claims[sub] > value[1] > |"} + // }, + // AddClaimsToRequest = + // { + // {"CustomerId", "Claims[CustomerId] > value"}, + // {"UserId", "Claims[sub] > value[1] > |"} + // }, + // RouteClaimsRequirement = + // { + // {"UserType", "registered"} + // } + // } + // } + // }; - this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) - .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) - .And(x => _steps.GivenIHaveAToken("http://localhost:51888")) - .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) - .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) - .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) - .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Forbidden)) - .BDDfy(); - } + // this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) + // .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) + // .And(x => _steps.GivenIHaveAToken("http://localhost:51888")) + // .And(x => _steps.GivenThereIsAConfiguration(configuration)) + // .And(x => _steps.GivenOcelotIsRunning()) + // .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + // .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + // .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Forbidden)) + // .BDDfy(); + //} - [Fact] - public void should_return_response_200_using_identity_server_with_allowed_scope() - { - var configuration = new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - DownstreamPathTemplate = "/", - DownstreamPort = 51876, - DownstreamHost = "localhost", - DownstreamScheme = "http", - UpstreamPathTemplate = "/", - UpstreamHttpMethod = new List { "Get" }, - AuthenticationOptions = new FileAuthenticationOptions - { - AllowedScopes = new List{ "api", "api.readOnly", "openid", "offline_access" }, - Provider = "IdentityServer", - ProviderRootUrl = "http://localhost:51888", - RequireHttps = false, - ApiName = "api", - ApiSecret = "secret" - } - } - } - }; + //[Fact] + //public void should_return_response_200_using_identity_server_with_allowed_scope() + //{ + // var configuration = new FileConfiguration + // { + // ReRoutes = new List + // { + // new FileReRoute + // { + // DownstreamPathTemplate = "/", + // DownstreamPort = 51876, + // DownstreamHost = "localhost", + // DownstreamScheme = "http", + // UpstreamPathTemplate = "/", + // UpstreamHttpMethod = new List { "Get" }, + // AuthenticationOptions = new FileAuthenticationOptions + // { + // AllowedScopes = new List{ "api", "api.readOnly", "openid", "offline_access" }, + // Provider = "IdentityServer", + // ProviderRootUrl = "http://localhost:51888", + // RequireHttps = false, + // ApiName = "api", + // ApiSecret = "secret" + // } + // } + // } + // }; - this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) - .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) - .And(x => _steps.GivenIHaveATokenForApiReadOnlyScope("http://localhost:51888")) - .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) - .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) - .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) - .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) - .BDDfy(); - } + // this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) + // .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) + // .And(x => _steps.GivenIHaveATokenForApiReadOnlyScope("http://localhost:51888")) + // .And(x => _steps.GivenThereIsAConfiguration(configuration)) + // .And(x => _steps.GivenOcelotIsRunning()) + // .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + // .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + // .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + // .BDDfy(); + //} - [Fact] - public void should_return_response_403_using_identity_server_with_scope_not_allowed() - { - var configuration = new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - DownstreamPathTemplate = "/", - DownstreamPort = 51876, - DownstreamHost = "localhost", - DownstreamScheme = "http", - UpstreamPathTemplate = "/", - UpstreamHttpMethod = new List { "Get" }, - AuthenticationOptions = new FileAuthenticationOptions - { - AllowedScopes = new List{ "api", "openid", "offline_access" }, - Provider = "IdentityServer", - ProviderRootUrl = "http://localhost:51888", - RequireHttps = false, - ApiName = "api", - ApiSecret = "secret" - } - } - } - }; + //[Fact] + //public void should_return_response_403_using_identity_server_with_scope_not_allowed() + //{ + // var configuration = new FileConfiguration + // { + // ReRoutes = new List + // { + // new FileReRoute + // { + // DownstreamPathTemplate = "/", + // DownstreamPort = 51876, + // DownstreamHost = "localhost", + // DownstreamScheme = "http", + // UpstreamPathTemplate = "/", + // UpstreamHttpMethod = new List { "Get" }, + // AuthenticationOptions = new FileAuthenticationOptions + // { + // AllowedScopes = new List{ "api", "openid", "offline_access" }, + // Provider = "IdentityServer", + // ProviderRootUrl = "http://localhost:51888", + // RequireHttps = false, + // ApiName = "api", + // ApiSecret = "secret" + // } + // } + // } + // }; - this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) - .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) - .And(x => _steps.GivenIHaveATokenForApiReadOnlyScope("http://localhost:51888")) - .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) - .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) - .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) - .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Forbidden)) - .BDDfy(); - } + // this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) + // .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) + // .And(x => _steps.GivenIHaveATokenForApiReadOnlyScope("http://localhost:51888")) + // .And(x => _steps.GivenThereIsAConfiguration(configuration)) + // .And(x => _steps.GivenOcelotIsRunning()) + // .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + // .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + // .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Forbidden)) + // .BDDfy(); + //} private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody) { diff --git a/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs b/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs index 88a294a0..80f9144f 100644 --- a/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs +++ b/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs @@ -30,67 +30,67 @@ namespace Ocelot.AcceptanceTests _steps = new Steps(); } - [Fact] - public void should_return_response_200_and_foward_claim_as_header() - { - var user = new TestUser() - { - Username = "test", - Password = "test", - SubjectId = "registered|1231231", - Claims = new List - { - new Claim("CustomerId", "123"), - new Claim("LocationId", "1") - } - }; + //[Fact] + //public void should_return_response_200_and_foward_claim_as_header() + //{ + // var user = new TestUser() + // { + // Username = "test", + // Password = "test", + // SubjectId = "registered|1231231", + // Claims = new List + // { + // new Claim("CustomerId", "123"), + // new Claim("LocationId", "1") + // } + // }; - var configuration = new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - DownstreamPathTemplate = "/", - DownstreamPort = 52876, - DownstreamScheme = "http", - DownstreamHost = "localhost", - UpstreamPathTemplate = "/", - UpstreamHttpMethod = new List { "Get" }, - AuthenticationOptions = new FileAuthenticationOptions - { - AllowedScopes = new List - { - "openid", "offline_access", "api" - }, - Provider = "IdentityServer", - ProviderRootUrl = "http://localhost:52888", - RequireHttps = false, - ApiName = "api", - ApiSecret = "secret", - }, - AddHeadersToRequest = - { - {"CustomerId", "Claims[CustomerId] > value"}, - {"LocationId", "Claims[LocationId] > value"}, - {"UserType", "Claims[sub] > value[0] > |"}, - {"UserId", "Claims[sub] > value[1] > |"} - } - } - } - }; + // var configuration = new FileConfiguration + // { + // ReRoutes = new List + // { + // new FileReRoute + // { + // DownstreamPathTemplate = "/", + // DownstreamPort = 52876, + // DownstreamScheme = "http", + // DownstreamHost = "localhost", + // UpstreamPathTemplate = "/", + // UpstreamHttpMethod = new List { "Get" }, + // AuthenticationOptions = new FileAuthenticationOptions + // { + //AllowedScopes = new List + // { + // "openid", "offline_access", "api" + // }, + // Provider = "IdentityServer", + // ProviderRootUrl = "http://localhost:52888", + // RequireHttps = false, + //ApiName = "api", + // ApiSecret = "secret", + // }, + // AddHeadersToRequest = + // { + // {"CustomerId", "Claims[CustomerId] > value"}, + // {"LocationId", "Claims[LocationId] > value"}, + // {"UserType", "Claims[sub] > value[0] > |"}, + // {"UserId", "Claims[sub] > value[1] > |"} + // } + // } + // } + // }; - this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:52888", "api", AccessTokenType.Jwt, user)) - .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:52876", 200)) - .And(x => _steps.GivenIHaveAToken("http://localhost:52888")) - .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) - .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) - .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) - .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) - .And(x => _steps.ThenTheResponseBodyShouldBe("CustomerId: 123 LocationId: 1 UserType: registered UserId: 1231231")) - .BDDfy(); - } + // this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:52888", "api", AccessTokenType.Jwt, user)) + // .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:52876", 200)) + // .And(x => _steps.GivenIHaveAToken("http://localhost:52888")) + // .And(x => _steps.GivenThereIsAConfiguration(configuration)) + // .And(x => _steps.GivenOcelotIsRunning()) + // .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + // .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + // .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + // .And(x => _steps.ThenTheResponseBodyShouldBe("CustomerId: 123 LocationId: 1 UserType: registered UserId: 1231231")) + // .BDDfy(); + //} private void GivenThereIsAServiceRunningOn(string url, int statusCode) { diff --git a/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs b/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs index a6162c5f..32b9dc8b 100644 --- a/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs +++ b/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs @@ -30,67 +30,67 @@ namespace Ocelot.AcceptanceTests _steps = new Steps(); } - [Fact] - public void should_return_response_200_and_foward_claim_as_query_string() - { - var user = new TestUser() - { - Username = "test", - Password = "test", - SubjectId = "registered|1231231", - Claims = new List - { - new Claim("CustomerId", "123"), - new Claim("LocationId", "1") - } - }; + //[Fact] + //public void should_return_response_200_and_foward_claim_as_query_string() + //{ + // var user = new TestUser() + // { + // Username = "test", + // Password = "test", + // SubjectId = "registered|1231231", + // Claims = new List + // { + // new Claim("CustomerId", "123"), + // new Claim("LocationId", "1") + // } + // }; - var configuration = new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - DownstreamPathTemplate = "/", - DownstreamPort = 57876, - DownstreamScheme = "http", - DownstreamHost = "localhost", - UpstreamPathTemplate = "/", - UpstreamHttpMethod = new List { "Get" }, - AuthenticationOptions = new FileAuthenticationOptions - { - AllowedScopes = new List - { - "openid", "offline_access", "api" - }, - Provider = "IdentityServer", - ProviderRootUrl = "http://localhost:57888", - RequireHttps = false, - ApiName = "api", - ApiSecret = "secret", - }, - AddQueriesToRequest = - { - {"CustomerId", "Claims[CustomerId] > value"}, - {"LocationId", "Claims[LocationId] > value"}, - {"UserType", "Claims[sub] > value[0] > |"}, - {"UserId", "Claims[sub] > value[1] > |"} - } - } - } - }; + // var configuration = new FileConfiguration + // { + // ReRoutes = new List + // { + // new FileReRoute + // { + // DownstreamPathTemplate = "/", + // DownstreamPort = 57876, + // DownstreamScheme = "http", + // DownstreamHost = "localhost", + // UpstreamPathTemplate = "/", + // UpstreamHttpMethod = new List { "Get" }, + // AuthenticationOptions = new FileAuthenticationOptions + // { + //AllowedScopes = new List + // { + // "openid", "offline_access", "api" + // }, + // Provider = "IdentityServer", + // ProviderRootUrl = "http://localhost:57888", + // RequireHttps = false, + //ApiName = "api", + // ApiSecret = "secret", + // }, + // AddQueriesToRequest = + // { + // {"CustomerId", "Claims[CustomerId] > value"}, + // {"LocationId", "Claims[LocationId] > value"}, + // {"UserType", "Claims[sub] > value[0] > |"}, + // {"UserId", "Claims[sub] > value[1] > |"} + // } + // } + // } + // }; - this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:57888", "api", AccessTokenType.Jwt, user)) - .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:57876", 200)) - .And(x => _steps.GivenIHaveAToken("http://localhost:57888")) - .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) - .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) - .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) - .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) - .And(x => _steps.ThenTheResponseBodyShouldBe("CustomerId: 123 LocationId: 1 UserType: registered UserId: 1231231")) - .BDDfy(); - } + // this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:57888", "api", AccessTokenType.Jwt, user)) + // .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:57876", 200)) + // .And(x => _steps.GivenIHaveAToken("http://localhost:57888")) + // .And(x => _steps.GivenThereIsAConfiguration(configuration)) + // .And(x => _steps.GivenOcelotIsRunning()) + // .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + // .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + // .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + // .And(x => _steps.ThenTheResponseBodyShouldBe("CustomerId: 123 LocationId: 1 UserType: registered UserId: 1231231")) + // .BDDfy(); + //} private void GivenThereIsAServiceRunningOn(string url, int statusCode) { diff --git a/test/Ocelot.UnitTests/Configuration/AuthenticationOptionsCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/AuthenticationOptionsCreatorTests.cs index ee1292aa..575b62b7 100644 --- a/test/Ocelot.UnitTests/Configuration/AuthenticationOptionsCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/AuthenticationOptionsCreatorTests.cs @@ -20,36 +20,36 @@ namespace Ocelot.UnitTests.Configuration _authOptionsCreator = new AuthenticationOptionsCreator(); } - [Fact] - public void should_return_auth_options() - { - var fileReRoute = new FileReRoute() - { - AuthenticationOptions = new FileAuthenticationOptions - { - Provider = "Geoff", - ProviderRootUrl = "http://www.bbc.co.uk/", - ApiName = "Laura", - RequireHttps = true, - AllowedScopes = new List {"cheese"}, - ApiSecret = "secret" - } - }; + // [Fact] + // public void should_return_auth_options() + // { + // var fileReRoute = new FileReRoute() + // { + // AuthenticationOptions = new FileAuthenticationOptions + // { + // Provider = "Geoff", + // ProviderRootUrl = "http://www.bbc.co.uk/", + //ApiName = "Laura", + // RequireHttps = true, + //AllowedScopes = new List {"cheese"}, + // ApiSecret = "secret" + // } + // }; - var expected = new AuthenticationOptionsBuilder() - .WithProvider(fileReRoute.AuthenticationOptions?.Provider) - .WithProviderRootUrl(fileReRoute.AuthenticationOptions?.ProviderRootUrl) - .WithApiName(fileReRoute.AuthenticationOptions?.ApiName) - .WithRequireHttps(fileReRoute.AuthenticationOptions.RequireHttps) - .WithAllowedScopes(fileReRoute.AuthenticationOptions?.AllowedScopes) - .WithApiSecret(fileReRoute.AuthenticationOptions?.ApiSecret) - .Build(); + // var expected = new AuthenticationOptionsBuilder() + // .WithProvider(fileReRoute.AuthenticationOptions?.Provider) + // .WithProviderRootUrl(fileReRoute.AuthenticationOptions?.ProviderRootUrl) + // .WithApiName(fileReRoute.AuthenticationOptions?.ApiName) + // .WithRequireHttps(fileReRoute.AuthenticationOptions.RequireHttps) + // .WithAllowedScopes(fileReRoute.AuthenticationOptions?.AllowedScopes) + // .WithApiSecret(fileReRoute.AuthenticationOptions?.ApiSecret) + // .Build(); - this.Given(x => x.GivenTheFollowing(fileReRoute)) - .When(x => x.WhenICreateTheAuthenticationOptions()) - .Then(x => x.ThenTheFollowingIsReturned(expected)) - .BDDfy(); - } + // this.Given(x => x.GivenTheFollowing(fileReRoute)) + // .When(x => x.WhenICreateTheAuthenticationOptions()) + // .Then(x => x.ThenTheFollowingIsReturned(expected)) + // .BDDfy(); + // } private void GivenTheFollowing(FileReRoute fileReRoute) { @@ -61,14 +61,14 @@ namespace Ocelot.UnitTests.Configuration _result = _authOptionsCreator.Create(_fileReRoute); } - private void ThenTheFollowingIsReturned(AuthenticationOptions expected) - { - _result.AllowedScopes.ShouldBe(expected.AllowedScopes); - _result.Provider.ShouldBe(expected.Provider); - _result.ProviderRootUrl.ShouldBe(expected.ProviderRootUrl); - _result.RequireHttps.ShouldBe(expected.RequireHttps); - _result.ApiName.ShouldBe(expected.ApiName); - _result.ApiSecret.ShouldBe(expected.ApiSecret); - } + //private void ThenTheFollowingIsReturned(AuthenticationOptions expected) + //{ + // _result.AllowedScopes.ShouldBe(expected.AllowedScopes); + // _result.Provider.ShouldBe(expected.Provider); + // _result.ProviderRootUrl.ShouldBe(expected.ProviderRootUrl); + // _result.RequireHttps.ShouldBe(expected.RequireHttps); + // _result.ApiName.ShouldBe(expected.ApiName); + // _result.ApiSecret.ShouldBe(expected.ApiSecret); + //} } } \ No newline at end of file diff --git a/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs index bd8c46d3..8a701f31 100644 --- a/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs @@ -393,132 +393,132 @@ namespace Ocelot.UnitTests.Configuration .BDDfy(); } - [Fact] - public void should_create_with_headers_to_extract() - { - var reRouteOptions = new ReRouteOptionsBuilder() - .WithIsAuthenticated(true) - .Build(); + //[Fact] + //public void should_create_with_headers_to_extract() + //{ + // var reRouteOptions = new ReRouteOptionsBuilder() + // .WithIsAuthenticated(true) + // .Build(); - var authenticationOptions = new AuthenticationOptionsBuilder() - .WithProvider("IdentityServer") - .WithProviderRootUrl("http://localhost:51888") - .WithRequireHttps(false) - .WithApiSecret("secret") - .WithApiName("api") - .WithAllowedScopes(new List()) - .Build(); + // var authenticationOptions = new AuthenticationOptionsBuilder() + // .WithProvider("IdentityServer") + // .WithProviderRootUrl("http://localhost:51888") + // .WithRequireHttps(false) + // .WithApiSecret("secret") + // .WithApiName("api") + // .WithAllowedScopes(new List()) + // .Build(); - var expected = new List - { - new ReRouteBuilder() - .WithDownstreamPathTemplate("/products/{productId}") - .WithUpstreamPathTemplate("/api/products/{productId}") - .WithUpstreamHttpMethod(new List { "Get" }) - .WithAuthenticationOptions(authenticationOptions) - .WithClaimsToHeaders(new List - { - new ClaimToThing("CustomerId", "CustomerId", "", 0), - }) - .Build() - }; + // var expected = new List + // { + // new ReRouteBuilder() + // .WithDownstreamPathTemplate("/products/{productId}") + // .WithUpstreamPathTemplate("/api/products/{productId}") + // .WithUpstreamHttpMethod(new List { "Get" }) + // .WithAuthenticationOptions(authenticationOptions) + // .WithClaimsToHeaders(new List + // { + // new ClaimToThing("CustomerId", "CustomerId", "", 0), + // }) + // .Build() + // }; - this.Given(x => x.GivenTheConfigIs(new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - UpstreamPathTemplate = "/api/products/{productId}", - DownstreamPathTemplate = "/products/{productId}", - UpstreamHttpMethod = new List { "Get" }, - ReRouteIsCaseSensitive = true, - AuthenticationOptions = new FileAuthenticationOptions - { - AllowedScopes= new List(), - Provider = "IdentityServer", - ProviderRootUrl = "http://localhost:51888", - RequireHttps = false, - ApiName= "api", - ApiSecret = "secret" - }, - AddHeadersToRequest = - { - {"CustomerId", "Claims[CustomerId] > value"}, - } - } - } - })) - .And(x => x.GivenTheConfigIsValid()) - .And(x => x.GivenTheAuthOptionsCreatorReturns(authenticationOptions)) - .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions)) - .And(x => x.GivenTheClaimsToThingCreatorReturns(new List{new ClaimToThing("CustomerId", "CustomerId", "", 0)})) - .And(x => x.GivenTheLoadBalancerFactoryReturns()) - .When(x => x.WhenICreateTheConfig()) - .Then(x => x.ThenTheReRoutesAre(expected)) - .And(x => x.ThenTheAuthenticationOptionsAre(expected)) - .And(x => x.ThenTheAuthOptionsCreatorIsCalledCorrectly()) - .BDDfy(); - } + // this.Given(x => x.GivenTheConfigIs(new FileConfiguration + // { + // ReRoutes = new List + // { + // new FileReRoute + // { + // UpstreamPathTemplate = "/api/products/{productId}", + // DownstreamPathTemplate = "/products/{productId}", + // UpstreamHttpMethod = new List { "Get" }, + // ReRouteIsCaseSensitive = true, + // AuthenticationOptions = new FileAuthenticationOptions + // { + //AllowedScopes= new List(), + // Provider = "IdentityServer", + // ProviderRootUrl = "http://localhost:51888", + // RequireHttps = false, + //ApiName= "api", + // ApiSecret = "secret" + // }, + // AddHeadersToRequest = + // { + // {"CustomerId", "Claims[CustomerId] > value"}, + // } + // } + // } + // })) + // .And(x => x.GivenTheConfigIsValid()) + // .And(x => x.GivenTheAuthOptionsCreatorReturns(authenticationOptions)) + // .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions)) + // .And(x => x.GivenTheClaimsToThingCreatorReturns(new List{new ClaimToThing("CustomerId", "CustomerId", "", 0)})) + // .And(x => x.GivenTheLoadBalancerFactoryReturns()) + // .When(x => x.WhenICreateTheConfig()) + // .Then(x => x.ThenTheReRoutesAre(expected)) + // .And(x => x.ThenTheAuthenticationOptionsAre(expected)) + // .And(x => x.ThenTheAuthOptionsCreatorIsCalledCorrectly()) + // .BDDfy(); + //} - [Fact] - public void should_create_with_authentication_properties() - { - var reRouteOptions = new ReRouteOptionsBuilder() - .WithIsAuthenticated(true) - .Build(); + //[Fact] + //public void should_create_with_authentication_properties() + //{ + // var reRouteOptions = new ReRouteOptionsBuilder() + // .WithIsAuthenticated(true) + // .Build(); - var authenticationOptions = new AuthenticationOptionsBuilder() - .WithProvider("IdentityServer") - .WithProviderRootUrl("http://localhost:51888") - .WithRequireHttps(false) - .WithApiSecret("secret") - .WithApiName("api") - .WithAllowedScopes(new List()) - .Build(); + // var authenticationOptions = new AuthenticationOptionsBuilder() + // .WithProvider("IdentityServer") + // .WithProviderRootUrl("http://localhost:51888") + // .WithRequireHttps(false) + // .WithApiSecret("secret") + // .WithApiName("api") + // .WithAllowedScopes(new List()) + // .Build(); - var expected = new List - { - new ReRouteBuilder() - .WithDownstreamPathTemplate("/products/{productId}") - .WithUpstreamPathTemplate("/api/products/{productId}") - .WithUpstreamHttpMethod(new List { "Get" }) - .WithAuthenticationOptions(authenticationOptions) - .Build() - }; + // var expected = new List + // { + // new ReRouteBuilder() + // .WithDownstreamPathTemplate("/products/{productId}") + // .WithUpstreamPathTemplate("/api/products/{productId}") + // .WithUpstreamHttpMethod(new List { "Get" }) + // .WithAuthenticationOptions(authenticationOptions) + // .Build() + // }; - this.Given(x => x.GivenTheConfigIs(new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - UpstreamPathTemplate = "/api/products/{productId}", - DownstreamPathTemplate = "/products/{productId}", - UpstreamHttpMethod = new List { "Get" }, - ReRouteIsCaseSensitive = true, - AuthenticationOptions = new FileAuthenticationOptions - { - AllowedScopes = new List(), - Provider = "IdentityServer", - ProviderRootUrl = "http://localhost:51888", - RequireHttps = false, - ApiName= "api", - ApiSecret = "secret" - } - } - } - })) - .And(x => x.GivenTheConfigIsValid()) - .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions)) - .And(x => x.GivenTheAuthOptionsCreatorReturns(authenticationOptions)) - .And(x => x.GivenTheLoadBalancerFactoryReturns()) - .When(x => x.WhenICreateTheConfig()) - .Then(x => x.ThenTheReRoutesAre(expected)) - .And(x => x.ThenTheAuthenticationOptionsAre(expected)) - .And(x => x.ThenTheAuthOptionsCreatorIsCalledCorrectly()) - .BDDfy(); - } + // this.Given(x => x.GivenTheConfigIs(new FileConfiguration + // { + // ReRoutes = new List + // { + // new FileReRoute + // { + // UpstreamPathTemplate = "/api/products/{productId}", + // DownstreamPathTemplate = "/products/{productId}", + // UpstreamHttpMethod = new List { "Get" }, + // ReRouteIsCaseSensitive = true, + // AuthenticationOptions = new FileAuthenticationOptions + // { + //AllowedScopes = new List(), + // Provider = "IdentityServer", + // ProviderRootUrl = "http://localhost:51888", + // RequireHttps = false, + //ApiName= "api", + // ApiSecret = "secret" + // } + // } + // } + // })) + // .And(x => x.GivenTheConfigIsValid()) + // .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions)) + // .And(x => x.GivenTheAuthOptionsCreatorReturns(authenticationOptions)) + // .And(x => x.GivenTheLoadBalancerFactoryReturns()) + // .When(x => x.WhenICreateTheConfig()) + // .Then(x => x.ThenTheReRoutesAre(expected)) + // .And(x => x.ThenTheAuthenticationOptionsAre(expected)) + // .And(x => x.ThenTheAuthOptionsCreatorIsCalledCorrectly()) + // .BDDfy(); + //} private void GivenTheFollowingOptionsAreReturned(ReRouteOptions fileReRouteOptions) { @@ -586,22 +586,22 @@ namespace Ocelot.UnitTests.Configuration } } - private void ThenTheAuthenticationOptionsAre(List expectedReRoutes) - { - for (int i = 0; i < _config.Data.ReRoutes.Count; i++) - { - var result = _config.Data.ReRoutes[i].AuthenticationOptions; - var expected = expectedReRoutes[i].AuthenticationOptions; + //private void ThenTheAuthenticationOptionsAre(List expectedReRoutes) + //{ + // for (int i = 0; i < _config.Data.ReRoutes.Count; i++) + // { + // var result = _config.Data.ReRoutes[i].AuthenticationOptions; + // var expected = expectedReRoutes[i].AuthenticationOptions; - result.AllowedScopes.ShouldBe(expected.AllowedScopes); - result.Provider.ShouldBe(expected.Provider); - result.ProviderRootUrl.ShouldBe(expected.ProviderRootUrl); - result.RequireHttps.ShouldBe(expected.RequireHttps); - result.ApiName.ShouldBe(expected.ApiName); - result.ApiSecret.ShouldBe(expected.ApiSecret); + // result.AllowedScopes.ShouldBe(expected.AllowedScopes); + // result.Provider.ShouldBe(expected.Provider); + // result.ProviderRootUrl.ShouldBe(expected.ProviderRootUrl); + // result.RequireHttps.ShouldBe(expected.RequireHttps); + // result.ApiName.ShouldBe(expected.ApiName); + // result.ApiSecret.ShouldBe(expected.ApiSecret); - } - } + // } + //} private void GivenTheLoadBalancerFactoryReturns() { From 239dcfb6bd1734c1a18f6e26650b10109f9fc757 Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Mon, 26 Jun 2017 19:10:20 +0100 Subject: [PATCH 12/35] working on region clearing cache, if using cachemanager back plance this would clear all servers in cluster --- src/Ocelot/Cache/IOcelotCache.cs | 6 +- .../Cache/Middleware/OutputCacheMiddleware.cs | 4 +- src/Ocelot/Cache/OcelotCacheManagerCache.cs | 18 +++-- .../ConsulOcelotConfigurationRepository.cs | 2 +- .../Controllers/OutputCacheController.cs | 33 +++++++++ .../Cache/CacheManagerCacheTests.cs | 32 ++++++++- .../Cache/OutputCacheMiddlewareTests.cs | 2 +- .../Controllers/OutputCacheControllerTests.cs | 70 +++++++++++++++++++ 8 files changed, 155 insertions(+), 12 deletions(-) create mode 100644 src/Ocelot/Controllers/OutputCacheController.cs create mode 100644 test/Ocelot.UnitTests/Controllers/OutputCacheControllerTests.cs diff --git a/src/Ocelot/Cache/IOcelotCache.cs b/src/Ocelot/Cache/IOcelotCache.cs index 9ac26d8f..9d7ead9b 100644 --- a/src/Ocelot/Cache/IOcelotCache.cs +++ b/src/Ocelot/Cache/IOcelotCache.cs @@ -1,11 +1,13 @@ using System; +using System.Collections.Generic; namespace Ocelot.Cache { public interface IOcelotCache { - void Add(string key, T value, TimeSpan ttl); - void AddAndDelete(string key, T value, TimeSpan ttl); + void Add(string key, T value, TimeSpan ttl, string region); + void AddAndDelete(string key, T value, TimeSpan ttl, string region); T Get(string key); + void ClearRegion(string region); } } diff --git a/src/Ocelot/Cache/Middleware/OutputCacheMiddleware.cs b/src/Ocelot/Cache/Middleware/OutputCacheMiddleware.cs index c2cb019e..fb1ebce5 100644 --- a/src/Ocelot/Cache/Middleware/OutputCacheMiddleware.cs +++ b/src/Ocelot/Cache/Middleware/OutputCacheMiddleware.cs @@ -63,7 +63,9 @@ namespace Ocelot.Cache.Middleware var response = HttpResponseMessage; - _outputCache.Add(downstreamUrlKey, response, TimeSpan.FromSeconds(DownstreamRoute.ReRoute.FileCacheOptions.TtlSeconds)); + var region = $"{DownstreamRoute.ReRoute.UpstreamHttpMethod}-{DownstreamRoute.ReRoute.UpstreamPathTemplate.Value}"; + + _outputCache.Add(downstreamUrlKey, response, TimeSpan.FromSeconds(DownstreamRoute.ReRoute.FileCacheOptions.TtlSeconds), region); _logger.LogDebug("finished response added to cache for {downstreamUrlKey}", downstreamUrlKey); } diff --git a/src/Ocelot/Cache/OcelotCacheManagerCache.cs b/src/Ocelot/Cache/OcelotCacheManagerCache.cs index e92d678d..4edfdaad 100644 --- a/src/Ocelot/Cache/OcelotCacheManagerCache.cs +++ b/src/Ocelot/Cache/OcelotCacheManagerCache.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; using CacheManager.Core; namespace Ocelot.Cache @@ -6,18 +8,21 @@ namespace Ocelot.Cache public class OcelotCacheManagerCache : IOcelotCache { private readonly ICacheManager _cacheManager; + private HashSet _keys; public OcelotCacheManagerCache(ICacheManager cacheManager) { _cacheManager = cacheManager; + _keys = new HashSet(); } - public void Add(string key, T value, TimeSpan ttl) + public void Add(string key, T value, TimeSpan ttl, string region) { - _cacheManager.Add(new CacheItem(key, value, ExpirationMode.Absolute, ttl)); + _cacheManager.Add(new CacheItem(key, region, value, ExpirationMode.Absolute, ttl)); + _keys.Add(key); } - public void AddAndDelete(string key, T value, TimeSpan ttl) + public void AddAndDelete(string key, T value, TimeSpan ttl, string region) { var exists = _cacheManager.Get(key); @@ -26,12 +31,17 @@ namespace Ocelot.Cache _cacheManager.Remove(key); } - _cacheManager.Add(new CacheItem(key, value, ExpirationMode.Absolute, ttl)); + Add(key, value, ttl, region); } public T Get(string key) { return _cacheManager.Get(key); } + + public void ClearRegion(string region) + { + _cacheManager.ClearRegion(region); + } } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/Repository/ConsulOcelotConfigurationRepository.cs b/src/Ocelot/Configuration/Repository/ConsulOcelotConfigurationRepository.cs index 703d039b..d7929aaa 100644 --- a/src/Ocelot/Configuration/Repository/ConsulOcelotConfigurationRepository.cs +++ b/src/Ocelot/Configuration/Repository/ConsulOcelotConfigurationRepository.cs @@ -68,7 +68,7 @@ namespace Ocelot.Configuration.Repository if (result.Response) { - _cache.AddAndDelete(_ocelotConfiguration, ocelotConfiguration, TimeSpan.FromSeconds(3)); + _cache.AddAndDelete(_ocelotConfiguration, ocelotConfiguration, TimeSpan.FromSeconds(3), "OcelotConfiguration"); return new OkResponse(); } diff --git a/src/Ocelot/Controllers/OutputCacheController.cs b/src/Ocelot/Controllers/OutputCacheController.cs new file mode 100644 index 00000000..2f56bf8d --- /dev/null +++ b/src/Ocelot/Controllers/OutputCacheController.cs @@ -0,0 +1,33 @@ +using System.Net.Http; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Ocelot.Cache; + +namespace Ocelot.Controllers +{ + [Authorize] + [Route("cache")] + public class OutputCacheController : Controller + { + private IOcelotCache _cache; + + public OutputCacheController(IOcelotCache cache) + { + _cache = cache; + } + + [HttpGet] + public IActionResult Get() + { + return new NotFoundResult(); + } + + [HttpDelete] + [Route("{region}")] + public IActionResult Delete(string region) + { + _cache.ClearRegion(region); + return new NoContentResult(); + } + } +} \ No newline at end of file diff --git a/test/Ocelot.UnitTests/Cache/CacheManagerCacheTests.cs b/test/Ocelot.UnitTests/Cache/CacheManagerCacheTests.cs index 87752a52..5780cff2 100644 --- a/test/Ocelot.UnitTests/Cache/CacheManagerCacheTests.cs +++ b/test/Ocelot.UnitTests/Cache/CacheManagerCacheTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using CacheManager.Core; using Moq; using Ocelot.Cache; @@ -16,12 +17,14 @@ namespace Ocelot.UnitTests.Cache private string _value; private string _resultGet; private TimeSpan _ttlSeconds; + private List _resultKeys; public CacheManagerCacheTests() { _mockCacheManager = new Mock>(); _ocelotOcelotCacheManager = new OcelotCacheManagerCache(_mockCacheManager.Object); } + [Fact] public void should_get_from_cache() { @@ -29,7 +32,6 @@ namespace Ocelot.UnitTests.Cache .When(x => x.WhenIGetFromTheCache()) .Then(x => x.ThenTheResultIs("someValue")) .BDDfy(); - } [Fact] @@ -40,13 +42,37 @@ namespace Ocelot.UnitTests.Cache .BDDfy(); } + [Fact] + public void should_delete_key_from_cache() + { + this.Given(_ => GivenTheFollowingRegion("fookey")) + .When(_ => WhenIDeleteTheRegion("fookey")) + .Then(_ => ThenTheRegionIsDeleted("fookey")) + .BDDfy(); + } + + private void WhenIDeleteTheRegion(string region) + { + _ocelotOcelotCacheManager.ClearRegion(region); + } + + private void ThenTheRegionIsDeleted(string region) + { + _mockCacheManager + .Verify(x => x.ClearRegion(region), Times.Once); + } + + private void GivenTheFollowingRegion(string key) + { + _ocelotOcelotCacheManager.Add(key, "doesnt matter", TimeSpan.FromSeconds(10), "region"); + } + private void WhenIAddToTheCache(string key, string value, TimeSpan ttlSeconds) { _key = key; _value = value; _ttlSeconds = ttlSeconds; - - _ocelotOcelotCacheManager.Add(_key, _value, _ttlSeconds); + _ocelotOcelotCacheManager.Add(_key, _value, _ttlSeconds, "region"); } private void ThenTheCacheIsCalledCorrectly() diff --git a/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs b/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs index dfc0220f..ab063b61 100644 --- a/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs @@ -124,7 +124,7 @@ namespace Ocelot.UnitTests.Cache private void ThenTheCacheAddIsCalledCorrectly() { _cacheManager - .Verify(x => x.Add(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + .Verify(x => x.Add(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); } private void GivenResponseIsNotCached() diff --git a/test/Ocelot.UnitTests/Controllers/OutputCacheControllerTests.cs b/test/Ocelot.UnitTests/Controllers/OutputCacheControllerTests.cs new file mode 100644 index 00000000..5e2268af --- /dev/null +++ b/test/Ocelot.UnitTests/Controllers/OutputCacheControllerTests.cs @@ -0,0 +1,70 @@ +using Xunit; +using Shouldly; +using TestStack.BDDfy; +using Ocelot.Controllers; +using System; +using Moq; +using Ocelot.Cache; +using System.Net.Http; +using System.Collections.Generic; +using Microsoft.AspNetCore.Mvc; + +namespace Ocelot.UnitTests.Controllers +{ + public class OutputCacheControllerTests + { + private OutputCacheController _controller; + private Mock> _cache; + private IActionResult _result; + + public OutputCacheControllerTests() + { + _cache = new Mock>(); + _controller = new OutputCacheController(_cache.Object); + } + + [Fact] + public void should_get_all_keys_from_server() + { + this.Given(_ => GivenTheFollowingKeys(new List{"b", "a"})) + .When(_ => WhenIGetTheKeys()) + .Then(_ => ThenTheKeysAreReturned()) + .BDDfy(); + } + + [Fact] + public void should_delete_key() + { + this.When(_ => WhenIDeleteTheKey("a")) + .Then(_ => ThenTheKeyIsDeleted("a")) + .BDDfy(); + } + + private void ThenTheKeyIsDeleted(string key) + { + _result.ShouldBeOfType(); + _cache + .Verify(x => x.ClearRegion(key), Times.Once); + } + + private void WhenIDeleteTheKey(string key) + { + _result = _controller.Delete(key); + } + + private void GivenTheFollowingKeys(List keys) + { + + } + + private void WhenIGetTheKeys() + { + _result = _controller.Get(); + } + + private void ThenTheKeysAreReturned() + { + _result.ShouldBeOfType(); + } + } +} \ No newline at end of file From 20f6ebac2f50f9e8714303820c60bbda08701e04 Mon Sep 17 00:00:00 2001 From: nicksharp Date: Mon, 26 Jun 2017 21:08:47 +0100 Subject: [PATCH 13/35] Fixing tests --- .../File/FileAuthenticationOptions.cs | 1 + .../AuthenticationTests.cs | 422 ++++++++---------- .../AuthorisationTests.cs | 372 +++++++-------- .../ClaimsToHeadersForwardingTests.cs | 120 ++--- .../ClaimsToQueryStringForwardingTests.cs | 120 ++--- 5 files changed, 510 insertions(+), 525 deletions(-) diff --git a/src/Ocelot/Configuration/File/FileAuthenticationOptions.cs b/src/Ocelot/Configuration/File/FileAuthenticationOptions.cs index 9f2de967..8216aa8d 100644 --- a/src/Ocelot/Configuration/File/FileAuthenticationOptions.cs +++ b/src/Ocelot/Configuration/File/FileAuthenticationOptions.cs @@ -7,6 +7,7 @@ namespace Ocelot.Configuration.File public FileAuthenticationOptions() { AllowedScopes = new List(); + IdentityServerConfig = new FileIdentityServerConfig(); } public string Provider { get; set; } diff --git a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs index 060cb5bd..64116034 100644 --- a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs @@ -34,241 +34,213 @@ namespace Ocelot.AcceptanceTests _steps = new Steps(); } - //[Fact] - //public void should_return_401_using_identity_server_access_token() - //{ - // var configuration = new FileConfiguration - // { - // ReRoutes = new List - // { - // new FileReRoute - // { - // DownstreamPathTemplate = _downstreamServicePath, - // DownstreamPort = _downstreamServicePort, - // DownstreamHost = _downstreamServiceHost, - // DownstreamScheme = _downstreamServiceScheme, - // UpstreamPathTemplate = "/", - // UpstreamHttpMethod = new List { "Post" }, - // AuthenticationOptions = new FileAuthenticationOptions - // { - // AllowedScopes = new List(), - // Provider = "IdentityServer", - // ProviderRootUrl = _identityServerRootUrl, - // RequireHttps = false, - // ApiName = "api", - // ApiSecret = "secret" - // } - // } - // } - // }; + [Fact] + public void should_return_401_using_identity_server_access_token() + { + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = _downstreamServicePath, + DownstreamPort = _downstreamServicePort, + DownstreamHost = _downstreamServiceHost, + DownstreamScheme = _downstreamServiceScheme, + UpstreamPathTemplate = "/", + UpstreamHttpMethod = new List { "Post" }, + AuthenticationOptions = new FileAuthenticationOptions + { + AllowedScopes = new List(), + Provider = "IdentityServer", + IdentityServerConfig = new FileIdentityServerConfig{ + ProviderRootUrl = _identityServerRootUrl, + RequireHttps = false, + ApiName = "api", + ApiSecret = "secret" + } + } + } + } + }; - // this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) - // .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) - // .And(x => _steps.GivenThereIsAConfiguration(configuration)) - // .And(x => _steps.GivenOcelotIsRunning()) - // .And(x => _steps.GivenThePostHasContent("postContent")) - // .When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) - // .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized)) - // .BDDfy(); - //} + this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) + .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) + .And(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenThePostHasContent("postContent")) + .When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized)) + .BDDfy(); + } - //[Fact] - //public void should_return_401_using_identity_server_reference_token() - //{ - // var configuration = new FileConfiguration - // { - // ReRoutes = new List - // { - // new FileReRoute - // { - // DownstreamPathTemplate = _downstreamServicePath, - // DownstreamPort = _downstreamServicePort, - // DownstreamHost = _downstreamServiceHost, - // DownstreamScheme = _downstreamServiceScheme, - // UpstreamPathTemplate = "/", - // UpstreamHttpMethod = new List { "Post" }, - // AuthenticationOptions = new FileAuthenticationOptions - // { - // AllowedScopes = new List(), - // Provider = "IdentityServer", - // ProviderRootUrl = _identityServerRootUrl, - // RequireHttps = false, - // ApiName = "api", - // ApiSecret = "secret" - // } - // } - // } - // }; + [Fact] + public void should_return_response_200_using_identity_server() + { + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = _downstreamServicePath, + DownstreamPort = _downstreamServicePort, + DownstreamHost = _downstreamServiceHost, + DownstreamScheme = _downstreamServiceScheme, + UpstreamPathTemplate = "/", + UpstreamHttpMethod = new List { "Get" }, + AuthenticationOptions = new FileAuthenticationOptions + { + AllowedScopes = new List(), + Provider = "IdentityServer", + IdentityServerConfig = new FileIdentityServerConfig{ + ProviderRootUrl = _identityServerRootUrl, + RequireHttps = false, + ApiName = "api", + ApiSecret = "secret" + } + } + } + } + }; - // this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Reference)) - // .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) - // .And(x => _steps.GivenThereIsAConfiguration(configuration)) - // .And(x => _steps.GivenOcelotIsRunning()) - // .And(x => _steps.GivenThePostHasContent("postContent")) - // .When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) - // .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized)) - // .BDDfy(); - //} + this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) + .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 200, "Hello from Laura")) + .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) + .And(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + .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_using_identity_server() - //{ - // var configuration = new FileConfiguration - // { - // ReRoutes = new List - // { - // new FileReRoute - // { - // DownstreamPathTemplate = _downstreamServicePath, - // DownstreamPort = _downstreamServicePort, - // DownstreamHost = _downstreamServiceHost, - // DownstreamScheme = _downstreamServiceScheme, - // UpstreamPathTemplate = "/", - // UpstreamHttpMethod = new List { "Get" }, - // AuthenticationOptions = new FileAuthenticationOptions - // { - // AllowedScopes = new List(), - // Provider = "IdentityServer", - // ProviderRootUrl = _identityServerRootUrl, - // RequireHttps = false, - // ApiName = "api", - // ApiSecret = "secret" - // } - // } - // } - // }; + [Fact] + public void should_return_response_401_using_identity_server_with_token_requested_for_other_api() + { + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = _downstreamServicePath, + DownstreamPort = _downstreamServicePort, + DownstreamHost = _downstreamServiceHost, + DownstreamScheme = _downstreamServiceScheme, + UpstreamPathTemplate = "/", + UpstreamHttpMethod = new List { "Get" }, + AuthenticationOptions = new FileAuthenticationOptions + { + AllowedScopes = new List(), + Provider = "IdentityServer", + IdentityServerConfig = new FileIdentityServerConfig{ + ProviderRootUrl = _identityServerRootUrl, + RequireHttps = false, + ApiName = "api", + ApiSecret = "secret" + } + } + } + } + }; - // this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) - // .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 200, "Hello from Laura")) - // .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) - // .And(x => _steps.GivenThereIsAConfiguration(configuration)) - // .And(x => _steps.GivenOcelotIsRunning()) - // .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) - // .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) - // .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) - // .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) - // .BDDfy(); - //} + this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) + .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 200, "Hello from Laura")) + .And(x => _steps.GivenIHaveATokenForApi2(_identityServerRootUrl)) + .And(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized)) + .BDDfy(); + } - //[Fact] - //public void should_return_response_401_using_identity_server_with_token_requested_for_other_api() - //{ - // var configuration = new FileConfiguration - // { - // ReRoutes = new List - // { - // new FileReRoute - // { - // DownstreamPathTemplate = _downstreamServicePath, - // DownstreamPort = _downstreamServicePort, - // DownstreamHost = _downstreamServiceHost, - // DownstreamScheme = _downstreamServiceScheme, - // UpstreamPathTemplate = "/", - // UpstreamHttpMethod = new List { "Get" }, - // AuthenticationOptions = new FileAuthenticationOptions - // { - // AllowedScopes = new List(), - // Provider = "IdentityServer", - // ProviderRootUrl = _identityServerRootUrl, - // RequireHttps = false, - // ApiName = "api", - // ApiSecret = "secret" - // } - // } - // } - // }; + [Fact] + public void should_return_201_using_identity_server_access_token() + { + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = _downstreamServicePath, + DownstreamPort = _downstreamServicePort, + DownstreamHost = _downstreamServiceHost, + DownstreamScheme = _downstreamServiceScheme, + UpstreamPathTemplate = "/", + UpstreamHttpMethod = new List { "Post" }, - // this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) - // .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 200, "Hello from Laura")) - // .And(x => _steps.GivenIHaveATokenForApi2(_identityServerRootUrl)) - // .And(x => _steps.GivenThereIsAConfiguration(configuration)) - // .And(x => _steps.GivenOcelotIsRunning()) - // .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) - // .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) - // .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized)) - // .BDDfy(); - //} + AuthenticationOptions = new FileAuthenticationOptions + { + AllowedScopes = new List(), + Provider = "IdentityServer", + IdentityServerConfig = new FileIdentityServerConfig{ + ProviderRootUrl = _identityServerRootUrl, + RequireHttps = false, + ApiName = "api", + ApiSecret = "secret" + } + } + } + } + }; - //[Fact] - //public void should_return_201_using_identity_server_access_token() - //{ - // var configuration = new FileConfiguration - // { - // ReRoutes = new List - // { - // new FileReRoute - // { - // DownstreamPathTemplate = _downstreamServicePath, - // DownstreamPort = _downstreamServicePort, - // DownstreamHost = _downstreamServiceHost, - // DownstreamScheme = _downstreamServiceScheme, - // UpstreamPathTemplate = "/", - // UpstreamHttpMethod = new List { "Post" }, + this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) + .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) + .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) + .And(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + .And(x => _steps.GivenThePostHasContent("postContent")) + .When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Created)) + .BDDfy(); + } - // AuthenticationOptions = new FileAuthenticationOptions - // { - // AllowedScopes = new List(), - // Provider = "IdentityServer", - // ProviderRootUrl = _identityServerRootUrl, - // RequireHttps = false, - // ApiName = "api", - // ApiSecret = "secret" - // } - // } - // } - // }; + [Fact] + public void should_return_201_using_identity_server_reference_token() + { + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = _downstreamServicePath, + DownstreamPort = _downstreamServicePort, + DownstreamHost = _downstreamServiceHost, + DownstreamScheme = _downstreamServiceScheme, + UpstreamPathTemplate = "/", + UpstreamHttpMethod = new List { "Post" }, + AuthenticationOptions = new FileAuthenticationOptions + { + AllowedScopes = new List(), + Provider = "IdentityServer", + IdentityServerConfig = new FileIdentityServerConfig{ + ProviderRootUrl = _identityServerRootUrl, + RequireHttps = false, + ApiName = "api", + ApiSecret = "secret" + } + } + } + } + }; - // this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Jwt)) - // .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) - // .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) - // .And(x => _steps.GivenThereIsAConfiguration(configuration)) - // .And(x => _steps.GivenOcelotIsRunning()) - // .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) - // .And(x => _steps.GivenThePostHasContent("postContent")) - // .When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) - // .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Created)) - // .BDDfy(); - //} - - //[Fact] - //public void should_return_201_using_identity_server_reference_token() - //{ - // var configuration = new FileConfiguration - // { - // ReRoutes = new List - // { - // new FileReRoute - // { - // DownstreamPathTemplate = _downstreamServicePath, - // DownstreamPort = _downstreamServicePort, - // DownstreamHost = _downstreamServiceHost, - // DownstreamScheme = _downstreamServiceScheme, - // UpstreamPathTemplate = "/", - // UpstreamHttpMethod = new List { "Post" }, - // AuthenticationOptions = new FileAuthenticationOptions - // { - // AllowedScopes = new List(), - // Provider = "IdentityServer", - // ProviderRootUrl = _identityServerRootUrl, - // RequireHttps = false, - // ApiName = "api", - // ApiSecret = "secret" - // } - // } - // } - // }; - - // this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Reference)) - // .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) - // .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) - // .And(x => _steps.GivenThereIsAConfiguration(configuration)) - // .And(x => _steps.GivenOcelotIsRunning()) - // .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) - // .And(x => _steps.GivenThePostHasContent("postContent")) - // .When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) - // .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Created)) - // .BDDfy(); - //} + this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", "api2", AccessTokenType.Reference)) + .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceUrl, 201, string.Empty)) + .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) + .And(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + .And(x => _steps.GivenThePostHasContent("postContent")) + .When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Created)) + .BDDfy(); + } private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody) { diff --git a/test/Ocelot.AcceptanceTests/AuthorisationTests.cs b/test/Ocelot.AcceptanceTests/AuthorisationTests.cs index 30dc636f..3eebd000 100644 --- a/test/Ocelot.AcceptanceTests/AuthorisationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthorisationTests.cs @@ -28,195 +28,203 @@ namespace Ocelot.AcceptanceTests _steps = new Steps(); } - //[Fact] - //public void should_return_response_200_authorising_route() - //{ - // var configuration = new FileConfiguration - // { - // ReRoutes = new List - // { - // new FileReRoute - // { - // DownstreamPathTemplate = "/", - // DownstreamPort = 51876, - // DownstreamScheme = "http", - // DownstreamHost = "localhost", - // UpstreamPathTemplate = "/", - // UpstreamHttpMethod = new List { "Get" }, - // AuthenticationOptions = new FileAuthenticationOptions - // { - //AllowedScopes = new List(), - // Provider = "IdentityServer", - // ProviderRootUrl = "http://localhost:51888", - // RequireHttps = false, - //ApiName = "api", - // ApiSecret = "secret" - // }, - // AddHeadersToRequest = - // { - // {"CustomerId", "Claims[CustomerId] > value"}, - // {"LocationId", "Claims[LocationId] > value"}, - // {"UserType", "Claims[sub] > value[0] > |"}, - // {"UserId", "Claims[sub] > value[1] > |"} - // }, - // AddClaimsToRequest = - // { - // {"CustomerId", "Claims[CustomerId] > value"}, - // {"UserType", "Claims[sub] > value[0] > |"}, - // {"UserId", "Claims[sub] > value[1] > |"} - // }, - // RouteClaimsRequirement = - // { - // {"UserType", "registered"} - // } - // } - // } - // }; + [Fact] + public void should_return_response_200_authorising_route() + { + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = "/", + DownstreamPort = 51876, + DownstreamScheme = "http", + DownstreamHost = "localhost", + UpstreamPathTemplate = "/", + UpstreamHttpMethod = new List { "Get" }, + AuthenticationOptions = new FileAuthenticationOptions + { + AllowedScopes = new List(), + Provider = "IdentityServer", + IdentityServerConfig = new FileIdentityServerConfig{ + ProviderRootUrl = "http://localhost:51888", + RequireHttps = false, + ApiName = "api", + ApiSecret = "secret" + } + }, + AddHeadersToRequest = + { + {"CustomerId", "Claims[CustomerId] > value"}, + {"LocationId", "Claims[LocationId] > value"}, + {"UserType", "Claims[sub] > value[0] > |"}, + {"UserId", "Claims[sub] > value[1] > |"} + }, + AddClaimsToRequest = + { + {"CustomerId", "Claims[CustomerId] > value"}, + {"UserType", "Claims[sub] > value[0] > |"}, + {"UserId", "Claims[sub] > value[1] > |"} + }, + RouteClaimsRequirement = + { + {"UserType", "registered"} + } + } + } + }; - // this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) - // .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) - // .And(x => _steps.GivenIHaveAToken("http://localhost:51888")) - // .And(x => _steps.GivenThereIsAConfiguration(configuration)) - // .And(x => _steps.GivenOcelotIsRunning()) - // .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) - // .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) - // .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) - // .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) - // .BDDfy(); - //} + this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) + .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) + .And(x => _steps.GivenIHaveAToken("http://localhost:51888")) + .And(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) + .BDDfy(); + } - //[Fact] - //public void should_return_response_403_authorising_route() - //{ - // var configuration = new FileConfiguration - // { - // ReRoutes = new List - // { - // new FileReRoute - // { - // DownstreamPathTemplate = "/", - // DownstreamPort = 51876, - // DownstreamScheme = "http", - // DownstreamHost = "localhost", - // UpstreamPathTemplate = "/", - // UpstreamHttpMethod = new List { "Get" }, - // AuthenticationOptions = new FileAuthenticationOptions - // { - //AllowedScopes = new List(), - // Provider = "IdentityServer", - // ProviderRootUrl = "http://localhost:51888", - // RequireHttps = false, - //ApiName = "api", - // ApiSecret = "secret" - // }, - // AddHeadersToRequest = - // { - // {"CustomerId", "Claims[CustomerId] > value"}, - // {"LocationId", "Claims[LocationId] > value"}, - // {"UserType", "Claims[sub] > value[0] > |"}, - // {"UserId", "Claims[sub] > value[1] > |"} - // }, - // AddClaimsToRequest = - // { - // {"CustomerId", "Claims[CustomerId] > value"}, - // {"UserId", "Claims[sub] > value[1] > |"} - // }, - // RouteClaimsRequirement = - // { - // {"UserType", "registered"} - // } - // } - // } - // }; + [Fact] + public void should_return_response_403_authorising_route() + { + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = "/", + DownstreamPort = 51876, + DownstreamScheme = "http", + DownstreamHost = "localhost", + UpstreamPathTemplate = "/", + UpstreamHttpMethod = new List { "Get" }, + AuthenticationOptions = new FileAuthenticationOptions + { + AllowedScopes = new List(), + Provider = "IdentityServer", + IdentityServerConfig = new FileIdentityServerConfig{ + ProviderRootUrl = "http://localhost:51888", + RequireHttps = false, + ApiName = "api", + ApiSecret = "secret" + } + }, + AddHeadersToRequest = + { + {"CustomerId", "Claims[CustomerId] > value"}, + {"LocationId", "Claims[LocationId] > value"}, + {"UserType", "Claims[sub] > value[0] > |"}, + {"UserId", "Claims[sub] > value[1] > |"} + }, + AddClaimsToRequest = + { + {"CustomerId", "Claims[CustomerId] > value"}, + {"UserId", "Claims[sub] > value[1] > |"} + }, + RouteClaimsRequirement = + { + {"UserType", "registered"} + } + } + } + }; - // this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) - // .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) - // .And(x => _steps.GivenIHaveAToken("http://localhost:51888")) - // .And(x => _steps.GivenThereIsAConfiguration(configuration)) - // .And(x => _steps.GivenOcelotIsRunning()) - // .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) - // .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) - // .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Forbidden)) - // .BDDfy(); - //} + this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) + .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) + .And(x => _steps.GivenIHaveAToken("http://localhost:51888")) + .And(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Forbidden)) + .BDDfy(); + } - //[Fact] - //public void should_return_response_200_using_identity_server_with_allowed_scope() - //{ - // var configuration = new FileConfiguration - // { - // ReRoutes = new List - // { - // new FileReRoute - // { - // DownstreamPathTemplate = "/", - // DownstreamPort = 51876, - // DownstreamHost = "localhost", - // DownstreamScheme = "http", - // UpstreamPathTemplate = "/", - // UpstreamHttpMethod = new List { "Get" }, - // AuthenticationOptions = new FileAuthenticationOptions - // { - // AllowedScopes = new List{ "api", "api.readOnly", "openid", "offline_access" }, - // Provider = "IdentityServer", - // ProviderRootUrl = "http://localhost:51888", - // RequireHttps = false, - // ApiName = "api", - // ApiSecret = "secret" - // } - // } - // } - // }; + [Fact] + public void should_return_response_200_using_identity_server_with_allowed_scope() + { + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = "/", + DownstreamPort = 51876, + DownstreamHost = "localhost", + DownstreamScheme = "http", + UpstreamPathTemplate = "/", + UpstreamHttpMethod = new List { "Get" }, + AuthenticationOptions = new FileAuthenticationOptions + { + AllowedScopes = new List{ "api", "api.readOnly", "openid", "offline_access" }, + Provider = "IdentityServer", + IdentityServerConfig = new FileIdentityServerConfig{ + ProviderRootUrl = "http://localhost:51888", + RequireHttps = false, + ApiName = "api", + ApiSecret = "secret" + } + } + } + } + }; - // this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) - // .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) - // .And(x => _steps.GivenIHaveATokenForApiReadOnlyScope("http://localhost:51888")) - // .And(x => _steps.GivenThereIsAConfiguration(configuration)) - // .And(x => _steps.GivenOcelotIsRunning()) - // .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) - // .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) - // .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) - // .BDDfy(); - //} + this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) + .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) + .And(x => _steps.GivenIHaveATokenForApiReadOnlyScope("http://localhost:51888")) + .And(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .BDDfy(); + } - //[Fact] - //public void should_return_response_403_using_identity_server_with_scope_not_allowed() - //{ - // var configuration = new FileConfiguration - // { - // ReRoutes = new List - // { - // new FileReRoute - // { - // DownstreamPathTemplate = "/", - // DownstreamPort = 51876, - // DownstreamHost = "localhost", - // DownstreamScheme = "http", - // UpstreamPathTemplate = "/", - // UpstreamHttpMethod = new List { "Get" }, - // AuthenticationOptions = new FileAuthenticationOptions - // { - // AllowedScopes = new List{ "api", "openid", "offline_access" }, - // Provider = "IdentityServer", - // ProviderRootUrl = "http://localhost:51888", - // RequireHttps = false, - // ApiName = "api", - // ApiSecret = "secret" - // } - // } - // } - // }; + [Fact] + public void should_return_response_403_using_identity_server_with_scope_not_allowed() + { + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = "/", + DownstreamPort = 51876, + DownstreamHost = "localhost", + DownstreamScheme = "http", + UpstreamPathTemplate = "/", + UpstreamHttpMethod = new List { "Get" }, + AuthenticationOptions = new FileAuthenticationOptions + { + AllowedScopes = new List{ "api", "openid", "offline_access" }, + Provider = "IdentityServer", + IdentityServerConfig = new FileIdentityServerConfig{ + ProviderRootUrl = "http://localhost:51888", + RequireHttps = false, + ApiName = "api", + ApiSecret = "secret" + } + } + } + } + }; - // this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) - // .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) - // .And(x => _steps.GivenIHaveATokenForApiReadOnlyScope("http://localhost:51888")) - // .And(x => _steps.GivenThereIsAConfiguration(configuration)) - // .And(x => _steps.GivenOcelotIsRunning()) - // .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) - // .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) - // .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Forbidden)) - // .BDDfy(); - //} + this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) + .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) + .And(x => _steps.GivenIHaveATokenForApiReadOnlyScope("http://localhost:51888")) + .And(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Forbidden)) + .BDDfy(); + } private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody) { diff --git a/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs b/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs index 80f9144f..babb520e 100644 --- a/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs +++ b/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs @@ -30,67 +30,69 @@ namespace Ocelot.AcceptanceTests _steps = new Steps(); } - //[Fact] - //public void should_return_response_200_and_foward_claim_as_header() - //{ - // var user = new TestUser() - // { - // Username = "test", - // Password = "test", - // SubjectId = "registered|1231231", - // Claims = new List - // { - // new Claim("CustomerId", "123"), - // new Claim("LocationId", "1") - // } - // }; + [Fact] + public void should_return_response_200_and_foward_claim_as_header() + { + var user = new TestUser() + { + Username = "test", + Password = "test", + SubjectId = "registered|1231231", + Claims = new List + { + new Claim("CustomerId", "123"), + new Claim("LocationId", "1") + } + }; - // var configuration = new FileConfiguration - // { - // ReRoutes = new List - // { - // new FileReRoute - // { - // DownstreamPathTemplate = "/", - // DownstreamPort = 52876, - // DownstreamScheme = "http", - // DownstreamHost = "localhost", - // UpstreamPathTemplate = "/", - // UpstreamHttpMethod = new List { "Get" }, - // AuthenticationOptions = new FileAuthenticationOptions - // { - //AllowedScopes = new List - // { - // "openid", "offline_access", "api" - // }, - // Provider = "IdentityServer", - // ProviderRootUrl = "http://localhost:52888", - // RequireHttps = false, - //ApiName = "api", - // ApiSecret = "secret", - // }, - // AddHeadersToRequest = - // { - // {"CustomerId", "Claims[CustomerId] > value"}, - // {"LocationId", "Claims[LocationId] > value"}, - // {"UserType", "Claims[sub] > value[0] > |"}, - // {"UserId", "Claims[sub] > value[1] > |"} - // } - // } - // } - // }; + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = "/", + DownstreamPort = 52876, + DownstreamScheme = "http", + DownstreamHost = "localhost", + UpstreamPathTemplate = "/", + UpstreamHttpMethod = new List { "Get" }, + AuthenticationOptions = new FileAuthenticationOptions + { + AllowedScopes = new List + { + "openid", "offline_access", "api" + }, + Provider = "IdentityServer", + IdentityServerConfig = new FileIdentityServerConfig{ + ProviderRootUrl = "http://localhost:52888", + RequireHttps = false, + ApiName = "api", + ApiSecret = "secret" + } + }, + AddHeadersToRequest = + { + {"CustomerId", "Claims[CustomerId] > value"}, + {"LocationId", "Claims[LocationId] > value"}, + {"UserType", "Claims[sub] > value[0] > |"}, + {"UserId", "Claims[sub] > value[1] > |"} + } + } + } + }; - // this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:52888", "api", AccessTokenType.Jwt, user)) - // .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:52876", 200)) - // .And(x => _steps.GivenIHaveAToken("http://localhost:52888")) - // .And(x => _steps.GivenThereIsAConfiguration(configuration)) - // .And(x => _steps.GivenOcelotIsRunning()) - // .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) - // .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) - // .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) - // .And(x => _steps.ThenTheResponseBodyShouldBe("CustomerId: 123 LocationId: 1 UserType: registered UserId: 1231231")) - // .BDDfy(); - //} + this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:52888", "api", AccessTokenType.Jwt, user)) + .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:52876", 200)) + .And(x => _steps.GivenIHaveAToken("http://localhost:52888")) + .And(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .And(x => _steps.ThenTheResponseBodyShouldBe("CustomerId: 123 LocationId: 1 UserType: registered UserId: 1231231")) + .BDDfy(); + } private void GivenThereIsAServiceRunningOn(string url, int statusCode) { diff --git a/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs b/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs index 32b9dc8b..744cfab2 100644 --- a/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs +++ b/test/Ocelot.AcceptanceTests/ClaimsToQueryStringForwardingTests.cs @@ -30,67 +30,69 @@ namespace Ocelot.AcceptanceTests _steps = new Steps(); } - //[Fact] - //public void should_return_response_200_and_foward_claim_as_query_string() - //{ - // var user = new TestUser() - // { - // Username = "test", - // Password = "test", - // SubjectId = "registered|1231231", - // Claims = new List - // { - // new Claim("CustomerId", "123"), - // new Claim("LocationId", "1") - // } - // }; + [Fact] + public void should_return_response_200_and_foward_claim_as_query_string() + { + var user = new TestUser() + { + Username = "test", + Password = "test", + SubjectId = "registered|1231231", + Claims = new List + { + new Claim("CustomerId", "123"), + new Claim("LocationId", "1") + } + }; - // var configuration = new FileConfiguration - // { - // ReRoutes = new List - // { - // new FileReRoute - // { - // DownstreamPathTemplate = "/", - // DownstreamPort = 57876, - // DownstreamScheme = "http", - // DownstreamHost = "localhost", - // UpstreamPathTemplate = "/", - // UpstreamHttpMethod = new List { "Get" }, - // AuthenticationOptions = new FileAuthenticationOptions - // { - //AllowedScopes = new List - // { - // "openid", "offline_access", "api" - // }, - // Provider = "IdentityServer", - // ProviderRootUrl = "http://localhost:57888", - // RequireHttps = false, - //ApiName = "api", - // ApiSecret = "secret", - // }, - // AddQueriesToRequest = - // { - // {"CustomerId", "Claims[CustomerId] > value"}, - // {"LocationId", "Claims[LocationId] > value"}, - // {"UserType", "Claims[sub] > value[0] > |"}, - // {"UserId", "Claims[sub] > value[1] > |"} - // } - // } - // } - // }; + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = "/", + DownstreamPort = 57876, + DownstreamScheme = "http", + DownstreamHost = "localhost", + UpstreamPathTemplate = "/", + UpstreamHttpMethod = new List { "Get" }, + AuthenticationOptions = new FileAuthenticationOptions + { + AllowedScopes = new List + { + "openid", "offline_access", "api" + }, + Provider = "IdentityServer", + IdentityServerConfig = new FileIdentityServerConfig{ + ProviderRootUrl = "http://localhost:57888", + RequireHttps = false, + ApiName = "api", + ApiSecret = "secret" + } + }, + AddQueriesToRequest = + { + {"CustomerId", "Claims[CustomerId] > value"}, + {"LocationId", "Claims[LocationId] > value"}, + {"UserType", "Claims[sub] > value[0] > |"}, + {"UserId", "Claims[sub] > value[1] > |"} + } + } + } + }; - // this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:57888", "api", AccessTokenType.Jwt, user)) - // .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:57876", 200)) - // .And(x => _steps.GivenIHaveAToken("http://localhost:57888")) - // .And(x => _steps.GivenThereIsAConfiguration(configuration)) - // .And(x => _steps.GivenOcelotIsRunning()) - // .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) - // .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) - // .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) - // .And(x => _steps.ThenTheResponseBodyShouldBe("CustomerId: 123 LocationId: 1 UserType: registered UserId: 1231231")) - // .BDDfy(); - //} + this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:57888", "api", AccessTokenType.Jwt, user)) + .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:57876", 200)) + .And(x => _steps.GivenIHaveAToken("http://localhost:57888")) + .And(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .And(x => _steps.ThenTheResponseBodyShouldBe("CustomerId: 123 LocationId: 1 UserType: registered UserId: 1231231")) + .BDDfy(); + } private void GivenThereIsAServiceRunningOn(string url, int statusCode) { From a7eeadb4c62e7c2fbe30d85845ce42087bb0e1ac Mon Sep 17 00:00:00 2001 From: Nick Sharp Date: Mon, 26 Jun 2017 21:32:44 +0100 Subject: [PATCH 14/35] fixing tests --- .../Handler/Creator/AuthenticationHandlerCreator.cs | 2 +- src/Ocelot/Configuration/AuthenticationOptions.cs | 13 +++++-------- .../Builder/AuthenticationOptionsBuilder.cs | 8 ++++---- .../Creator/AuthenticationOptionsCreator.cs | 8 ++++---- .../ConfigurationInConsulTests.cs | 1 - 5 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs b/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs index 910b99e4..5015fefa 100644 --- a/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs +++ b/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs @@ -19,7 +19,7 @@ namespace Ocelot.Authentication.Handler.Creator { var builder = app.New(); - var authenticationConfig = authOptions.Config as IdentityServerConfig; + var authenticationConfig = authOptions.Config; builder.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions { diff --git a/src/Ocelot/Configuration/AuthenticationOptions.cs b/src/Ocelot/Configuration/AuthenticationOptions.cs index cfb76fe4..25b65fe9 100644 --- a/src/Ocelot/Configuration/AuthenticationOptions.cs +++ b/src/Ocelot/Configuration/AuthenticationOptions.cs @@ -2,9 +2,11 @@ namespace Ocelot.Configuration { + using Newtonsoft.Json; + public class AuthenticationOptions { - public AuthenticationOptions(string provider, List allowedScopes, IAuthenticationConfig config) + public AuthenticationOptions(string provider, List allowedScopes, IdentityServerConfig config) { Provider = provider; AllowedScopes = allowedScopes; @@ -15,15 +17,10 @@ namespace Ocelot.Configuration public List AllowedScopes { get; private set; } - public IAuthenticationConfig Config { get; } + public IdentityServerConfig Config { get; private set; } } - - public interface IAuthenticationConfig - { - } - - public class IdentityServerConfig : IAuthenticationConfig + public class IdentityServerConfig { public IdentityServerConfig(string providerRootUrl, string apiName, bool requireHttps, string apiSecret) { diff --git a/src/Ocelot/Configuration/Builder/AuthenticationOptionsBuilder.cs b/src/Ocelot/Configuration/Builder/AuthenticationOptionsBuilder.cs index bd20717c..3f83d3a3 100644 --- a/src/Ocelot/Configuration/Builder/AuthenticationOptionsBuilder.cs +++ b/src/Ocelot/Configuration/Builder/AuthenticationOptionsBuilder.cs @@ -9,7 +9,7 @@ namespace Ocelot.Configuration.Builder private List _allowedScopes; - private IAuthenticationConfig _config; + private IdentityServerConfig _identityServerConfig; public AuthenticationOptionsBuilder WithProvider(string provider) { @@ -23,15 +23,15 @@ namespace Ocelot.Configuration.Builder return this; } - public AuthenticationOptionsBuilder WithConfiguration(IAuthenticationConfig config) + public AuthenticationOptionsBuilder WithIdntityServerConfigConfiguration(IdentityServerConfig config) { - _config = config; + _identityServerConfig = config; return this; } public AuthenticationOptions Build() { - return new AuthenticationOptions(_provider, _allowedScopes, _config); + return new AuthenticationOptions(_provider, _allowedScopes, _identityServerConfig); } } diff --git a/src/Ocelot/Configuration/Creator/AuthenticationOptionsCreator.cs b/src/Ocelot/Configuration/Creator/AuthenticationOptionsCreator.cs index ac185cdf..7f3f34a3 100644 --- a/src/Ocelot/Configuration/Creator/AuthenticationOptionsCreator.cs +++ b/src/Ocelot/Configuration/Creator/AuthenticationOptionsCreator.cs @@ -7,19 +7,19 @@ namespace Ocelot.Configuration.Creator { public AuthenticationOptions Create(FileReRoute fileReRoute) { - var authenticationConfig = new AuthenticationConfigCreator().Create(fileReRoute.AuthenticationOptions); + var authenticationConfig = new IdentityServerConfigCreator().Create(fileReRoute.AuthenticationOptions); return new AuthenticationOptionsBuilder() .WithProvider(fileReRoute.AuthenticationOptions?.Provider) .WithAllowedScopes(fileReRoute.AuthenticationOptions?.AllowedScopes) - .WithConfiguration(authenticationConfig) + .WithIdntityServerConfigConfiguration(authenticationConfig) .Build(); } } - public class AuthenticationConfigCreator + public class IdentityServerConfigCreator { - public IAuthenticationConfig Create(FileAuthenticationOptions authenticationOptions) + public IdentityServerConfig Create(FileAuthenticationOptions authenticationOptions) { return new IdentityServerConfigBuilder() .WithApiName(authenticationOptions.IdentityServerConfig?.ApiName) diff --git a/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs b/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs index 0ab4cc6a..88301610 100644 --- a/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs +++ b/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs @@ -29,7 +29,6 @@ namespace Ocelot.AcceptanceTests _steps = new Steps(); } - [Fact] public void should_return_response_200_with_simple_url() { From ec0f3b32e46b0742d1b86b7f8bf8462c99bb9533 Mon Sep 17 00:00:00 2001 From: Nick Sharp Date: Tue, 27 Jun 2017 13:49:30 +0100 Subject: [PATCH 15/35] Adding deserializer config for consul --- .../Creator/AuthenticationHandlerCreator.cs | 2 +- .../Configuration/AuthenticationOptions.cs | 8 ++- .../ConsulOcelotConfigurationRepository.cs | 6 +- .../AuthenticationConfigConverter.cs | 55 +++++++++++++++++++ .../ConfigurationInConsulTests.cs | 6 +- 5 files changed, 70 insertions(+), 7 deletions(-) create mode 100644 src/Ocelot/JsonConverters/AuthenticationConfigConverter.cs diff --git a/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs b/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs index 5015fefa..910b99e4 100644 --- a/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs +++ b/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs @@ -19,7 +19,7 @@ namespace Ocelot.Authentication.Handler.Creator { var builder = app.New(); - var authenticationConfig = authOptions.Config; + var authenticationConfig = authOptions.Config as IdentityServerConfig; builder.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions { diff --git a/src/Ocelot/Configuration/AuthenticationOptions.cs b/src/Ocelot/Configuration/AuthenticationOptions.cs index 25b65fe9..c4a49b7d 100644 --- a/src/Ocelot/Configuration/AuthenticationOptions.cs +++ b/src/Ocelot/Configuration/AuthenticationOptions.cs @@ -6,7 +6,7 @@ namespace Ocelot.Configuration public class AuthenticationOptions { - public AuthenticationOptions(string provider, List allowedScopes, IdentityServerConfig config) + public AuthenticationOptions(string provider, List allowedScopes, IAuthenticationConfig config) { Provider = provider; AllowedScopes = allowedScopes; @@ -17,10 +17,10 @@ namespace Ocelot.Configuration public List AllowedScopes { get; private set; } - public IdentityServerConfig Config { get; private set; } + public IAuthenticationConfig Config { get; private set; } } - public class IdentityServerConfig + public class IdentityServerConfig : IAuthenticationConfig { public IdentityServerConfig(string providerRootUrl, string apiName, bool requireHttps, string apiSecret) { @@ -35,4 +35,6 @@ namespace Ocelot.Configuration public string ApiSecret { get; private set; } public bool RequireHttps { get; private set; } } + + public interface IAuthenticationConfig {} } diff --git a/src/Ocelot/Configuration/Repository/ConsulOcelotConfigurationRepository.cs b/src/Ocelot/Configuration/Repository/ConsulOcelotConfigurationRepository.cs index 703d039b..34529303 100644 --- a/src/Ocelot/Configuration/Repository/ConsulOcelotConfigurationRepository.cs +++ b/src/Ocelot/Configuration/Repository/ConsulOcelotConfigurationRepository.cs @@ -9,6 +9,8 @@ using Ocelot.ServiceDiscovery; namespace Ocelot.Configuration.Repository { + using Ocelot.AcceptanceTests; + public class ConsulOcelotConfigurationRepository : IOcelotConfigurationRepository { private readonly ConsulClient _consul; @@ -48,7 +50,9 @@ namespace Ocelot.Configuration.Repository var json = Encoding.UTF8.GetString(bytes); - var consulConfig = JsonConvert.DeserializeObject(json); + var settings = new JsonSerializerSettings(); + settings.Converters.Add(new AuthenticationConfigConverter()); + var consulConfig = JsonConvert.DeserializeObject(json, settings); return new OkResponse(consulConfig); } diff --git a/src/Ocelot/JsonConverters/AuthenticationConfigConverter.cs b/src/Ocelot/JsonConverters/AuthenticationConfigConverter.cs new file mode 100644 index 00000000..e63b1fe6 --- /dev/null +++ b/src/Ocelot/JsonConverters/AuthenticationConfigConverter.cs @@ -0,0 +1,55 @@ +using System; +using Newtonsoft.Json; +using Ocelot.Configuration; + +namespace Ocelot.AcceptanceTests +{ + using Newtonsoft.Json.Linq; + public class AuthenticationConfigConverter : JsonConverter + { + public override bool CanWrite => false; + + public override bool CanRead => true; + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + throw new InvalidOperationException("Use default serialization."); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var jsonObject = JObject.Load(reader); + var setting = default(IAuthenticationConfig); + + if (jsonObject["Provider"] != null) + { + switch (jsonObject["Provider"].Value()) + { + //case "Jwt": + // setting = new + default: + setting = new IdentityServerConfig( + jsonObject["ProviderRootUrl"].Value(), + jsonObject["ApiName"].Value(), + jsonObject["RequireHttps"].Value(), + jsonObject["ApiSecret"].Value()); + break; + } + } + else + { + setting = new IdentityServerConfig(string.Empty, string.Empty, false, string.Empty); + } + + serializer.Populate(jsonObject.CreateReader(), setting); + return setting; + } + + public override bool CanConvert(Type objectType) + { + return objectType == typeof(IAuthenticationConfig); + } + } + + +} diff --git a/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs b/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs index 88301610..afed1164 100644 --- a/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs +++ b/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs @@ -104,7 +104,9 @@ namespace Ocelot.AcceptanceTests var json = reader.ReadToEnd(); - _config = JsonConvert.DeserializeObject(json); + var settings = new JsonSerializerSettings(); + settings.Converters.Add(new AuthenticationConfigConverter()); + _config = JsonConvert.DeserializeObject(json, settings); var response = JsonConvert.SerializeObject(true); @@ -166,4 +168,4 @@ namespace Ocelot.AcceptanceTests _steps.Dispose(); } } -} +} \ No newline at end of file From e4e7fcc943662069b403c1fafeb53d9e11518151 Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Tue, 27 Jun 2017 18:54:15 +0100 Subject: [PATCH 16/35] unit tests for cache clearing passing --- .../Cache/Middleware/OutputCacheMiddleware.cs | 8 +- src/Ocelot/Cache/RegionBuilder.cs | 22 ++++ src/Ocelot/Cache/RegionsGetter.cs | 47 ++++++++ .../Controllers/OutputCacheController.cs | 8 +- .../ServiceCollectionExtensions.cs | 2 + .../Ocelot.AcceptanceTests.csproj | 1 + .../Cache/OutputCacheMiddlewareTests.cs | 2 + .../Cache/RegionCreatorTests.cs | 46 ++++++++ .../Cache/RegionsGetterTests.cs | 109 ++++++++++++++++++ .../Controllers/OutputCacheControllerTests.cs | 4 +- 10 files changed, 244 insertions(+), 5 deletions(-) create mode 100644 src/Ocelot/Cache/RegionBuilder.cs create mode 100644 src/Ocelot/Cache/RegionsGetter.cs create mode 100644 test/Ocelot.UnitTests/Cache/RegionCreatorTests.cs create mode 100644 test/Ocelot.UnitTests/Cache/RegionsGetterTests.cs diff --git a/src/Ocelot/Cache/Middleware/OutputCacheMiddleware.cs b/src/Ocelot/Cache/Middleware/OutputCacheMiddleware.cs index fb1ebce5..8b8b565d 100644 --- a/src/Ocelot/Cache/Middleware/OutputCacheMiddleware.cs +++ b/src/Ocelot/Cache/Middleware/OutputCacheMiddleware.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; @@ -13,16 +14,19 @@ namespace Ocelot.Cache.Middleware private readonly RequestDelegate _next; private readonly IOcelotLogger _logger; private readonly IOcelotCache _outputCache; + private readonly IRegionCreator _regionCreator; public OutputCacheMiddleware(RequestDelegate next, IOcelotLoggerFactory loggerFactory, IRequestScopedDataRepository scopedDataRepository, - IOcelotCache outputCache) + IOcelotCache outputCache, + IRegionCreator regionCreator) :base(scopedDataRepository) { _next = next; _outputCache = outputCache; _logger = loggerFactory.CreateLogger(); + _regionCreator = regionCreator; } public async Task Invoke(HttpContext context) @@ -63,7 +67,7 @@ namespace Ocelot.Cache.Middleware var response = HttpResponseMessage; - var region = $"{DownstreamRoute.ReRoute.UpstreamHttpMethod}-{DownstreamRoute.ReRoute.UpstreamPathTemplate.Value}"; + var region = _regionCreator.Region(DownstreamRoute.ReRoute); _outputCache.Add(downstreamUrlKey, response, TimeSpan.FromSeconds(DownstreamRoute.ReRoute.FileCacheOptions.TtlSeconds), region); diff --git a/src/Ocelot/Cache/RegionBuilder.cs b/src/Ocelot/Cache/RegionBuilder.cs new file mode 100644 index 00000000..eb9972bc --- /dev/null +++ b/src/Ocelot/Cache/RegionBuilder.cs @@ -0,0 +1,22 @@ +using System.Linq; +using Ocelot.Configuration; + +namespace Ocelot.Cache +{ + public interface IRegionCreator + { + string Region(ReRoute reRoute); + } + + public class RegionCreator : IRegionCreator + { + public string Region(ReRoute reRoute) + { + var methods = string.Join(",", reRoute.UpstreamHttpMethod.Select(m => m.Method)); + + var region = $"{methods} {reRoute.UpstreamPathTemplate.Value}"; + + return region; + } + } +} \ No newline at end of file diff --git a/src/Ocelot/Cache/RegionsGetter.cs b/src/Ocelot/Cache/RegionsGetter.cs new file mode 100644 index 00000000..1c331c2a --- /dev/null +++ b/src/Ocelot/Cache/RegionsGetter.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Ocelot.Configuration.Provider; +using Ocelot.Logging; + +namespace Ocelot.Cache +{ + public interface IRegionsGetter + { + Task> Regions(); + } + public class RegionsGetter : IRegionsGetter + { + private readonly IOcelotConfigurationProvider _provider; + private readonly IRegionCreator _creator; + private readonly IOcelotLogger _logger; + + public RegionsGetter(IOcelotConfigurationProvider provider, IRegionCreator creator, IOcelotLoggerFactory loggerFactory) + { + _logger = loggerFactory.CreateLogger(); + _provider = provider; + _creator = creator; + } + + public async Task> Regions() + { + var config = await _provider.Get(); + + if(config.IsError) + { + _logger.LogError("unable to find regions", new Exception(string.Join(",", config.Errors))); + return new List(); + } + + var regions = new List(); + + foreach(var reRoute in config.Data.ReRoutes) + { + var region = _creator.Region(reRoute); + regions.Add(region); + } + + return regions; + } + } +} \ No newline at end of file diff --git a/src/Ocelot/Controllers/OutputCacheController.cs b/src/Ocelot/Controllers/OutputCacheController.cs index 2f56bf8d..04150a5f 100644 --- a/src/Ocelot/Controllers/OutputCacheController.cs +++ b/src/Ocelot/Controllers/OutputCacheController.cs @@ -2,6 +2,7 @@ using System.Net.Http; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Ocelot.Cache; +using Ocelot.Configuration.Provider; namespace Ocelot.Controllers { @@ -10,16 +11,19 @@ namespace Ocelot.Controllers public class OutputCacheController : Controller { private IOcelotCache _cache; + private IRegionsGetter _regionsGetter; - public OutputCacheController(IOcelotCache cache) + public OutputCacheController(IOcelotCache cache, IRegionsGetter regionsGetter) { _cache = cache; + _regionsGetter = regionsGetter; } [HttpGet] public IActionResult Get() { - return new NotFoundResult(); + var regions = _regionsGetter.Regions(); + return new OkObjectResult(regions); } [HttpDelete] diff --git a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs index 14410379..d2ff4b74 100644 --- a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs @@ -145,6 +145,8 @@ namespace Ocelot.DependencyInjection .AddJsonFormatters(); services.AddLogging(); + services.TryAddSingleton(); + services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); diff --git a/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj b/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj index 08bbf527..eea05872 100644 --- a/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj +++ b/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj @@ -30,6 +30,7 @@ + diff --git a/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs b/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs index ab063b61..0039e2af 100644 --- a/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs @@ -5,6 +5,7 @@ using System.Net.Http; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Moq; using Ocelot.Cache; using Ocelot.Cache.Middleware; @@ -43,6 +44,7 @@ namespace Ocelot.UnitTests.Cache x.AddLogging(); x.AddSingleton(_cacheManager.Object); x.AddSingleton(_scopedRepo.Object); + x.AddSingleton(); }) .UseUrls(_url) .UseKestrel() diff --git a/test/Ocelot.UnitTests/Cache/RegionCreatorTests.cs b/test/Ocelot.UnitTests/Cache/RegionCreatorTests.cs new file mode 100644 index 00000000..9d2b5a65 --- /dev/null +++ b/test/Ocelot.UnitTests/Cache/RegionCreatorTests.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using Ocelot.Cache; +using Ocelot.Configuration; +using Ocelot.Configuration.Builder; +using Shouldly; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests.Cache +{ + public class RegionCreatorTests + { + private string _result; + private ReRoute _reRoute; + + [Fact] + public void should_create_region() + { + var reRoute = new ReRouteBuilder() + .WithUpstreamHttpMethod(new List{"Get"}) + .WithUpstreamPathTemplate("/test/dummy") + .Build(); + + this.Given(_ => GivenTheReRoute(reRoute)) + .When(_ => WhenICreateTheRegion()) + .Then(_ => ThenTheRegionIs("Get /test/dummy")) + .BDDfy(); + } + + private void GivenTheReRoute(ReRoute reRoute) + { + _reRoute = reRoute; + } + + private void WhenICreateTheRegion() + { + RegionCreator regionCreator = new RegionCreator(); + _result = regionCreator.Region(_reRoute); + } + + private void ThenTheRegionIs(string expected) + { + _result.ShouldBe(expected); + } + } +} \ No newline at end of file diff --git a/test/Ocelot.UnitTests/Cache/RegionsGetterTests.cs b/test/Ocelot.UnitTests/Cache/RegionsGetterTests.cs new file mode 100644 index 00000000..1f235daf --- /dev/null +++ b/test/Ocelot.UnitTests/Cache/RegionsGetterTests.cs @@ -0,0 +1,109 @@ +using Xunit; +using TestStack.BDDfy; +using Shouldly; +using Ocelot.Cache; +using Moq; +using Ocelot.Configuration.Provider; +using System.Collections.Generic; +using Ocelot.Responses; +using Ocelot.Configuration; +using System.Threading.Tasks; +using Ocelot.Configuration.Builder; +using System; +using Ocelot.Errors; +using Ocelot.Logging; + +namespace Ocelot.UnitTests.Cache +{ + public class RegionsGetterTests + { + private RegionsGetter _regionsGetter; + private readonly Mock _provider; + private readonly Mock _creator; + private readonly Mock _factory; + private List _result; + + public RegionsGetterTests() + { + _provider = new Mock(); + _creator = new Mock(); + _factory = new Mock(); + var logger = new Mock(); + _factory + .Setup(x => x.CreateLogger()) + .Returns(logger.Object); + _regionsGetter = new RegionsGetter(_provider.Object, _creator.Object, _factory.Object); + } + + [Fact] + public void should_get_regions() + { + var reRoute = new ReRouteBuilder() + .WithUpstreamHttpMethod(new List{"Get"}) + .WithUpstreamPathTemplate("/") + .Build(); + + var reRoutes = new List + { + reRoute + }; + + var config = new OcelotConfiguration(reRoutes, "whocares!"); + + var expected = new List + { + "balls" + }; + + this.Given(_ => GivenTheFollowingConfig(config)) + .And(_ => GivenTheProviderReturns("balls")) + .When(_ => WhenIGetTheRegions()) + .Then(_ => ThenTheFollowingIsReturned(expected)) + .BDDfy(); + } + + [Fact] + public void should_return_empty_regions() + { + var expected = new List(); + + this.Given(_ => GivenAnErrorGettingTheConfig()) + .When(_ => WhenIGetTheRegions()) + .Then(_ => ThenTheFollowingIsReturned(expected)) + .BDDfy(); + } + + private void GivenAnErrorGettingTheConfig() + { + var config = new OcelotConfiguration(new List(), "whocares!"); + + _provider + .Setup(x => x.Get()) + .ReturnsAsync(new ErrorResponse(It.IsAny())); + } + + private void GivenTheProviderReturns(string expected) + { + _creator + .Setup(x => x.Region(It.IsAny())) + .Returns(expected); + } + + private void GivenTheFollowingConfig(IOcelotConfiguration config) + { + _provider + .Setup(x => x.Get()) + .ReturnsAsync(new OkResponse(config)); + } + + private void WhenIGetTheRegions() + { + _result = _regionsGetter.Regions().Result; + } + + private void ThenTheFollowingIsReturned(List expected) + { + _result.ShouldBe(expected); + } + } +} \ No newline at end of file diff --git a/test/Ocelot.UnitTests/Controllers/OutputCacheControllerTests.cs b/test/Ocelot.UnitTests/Controllers/OutputCacheControllerTests.cs index 5e2268af..fa43369e 100644 --- a/test/Ocelot.UnitTests/Controllers/OutputCacheControllerTests.cs +++ b/test/Ocelot.UnitTests/Controllers/OutputCacheControllerTests.cs @@ -15,12 +15,14 @@ namespace Ocelot.UnitTests.Controllers { private OutputCacheController _controller; private Mock> _cache; + private Mock _getter; private IActionResult _result; public OutputCacheControllerTests() { _cache = new Mock>(); - _controller = new OutputCacheController(_cache.Object); + _getter = new Mock(); + _controller = new OutputCacheController(_cache.Object, _getter.Object); } [Fact] From 0fa759c76c6b568449fb906cd0aaa86be54c9fc9 Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Tue, 27 Jun 2017 19:07:55 +0100 Subject: [PATCH 17/35] first acceptance test failing.. --- src/Ocelot/Cache/RegionsGetter.cs | 5 +- .../Controllers/OutputCacheController.cs | 2 +- .../AdministrationTests.cs | 64 +++++++++++++++++++ .../Cache/RegionsGetterTests.cs | 6 +- 4 files changed, 74 insertions(+), 3 deletions(-) diff --git a/src/Ocelot/Cache/RegionsGetter.cs b/src/Ocelot/Cache/RegionsGetter.cs index 1c331c2a..ae87a49f 100644 --- a/src/Ocelot/Cache/RegionsGetter.cs +++ b/src/Ocelot/Cache/RegionsGetter.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Ocelot.Configuration.Provider; using Ocelot.Logging; @@ -33,9 +34,11 @@ namespace Ocelot.Cache return new List(); } + var cachedReRoutes = config.Data.ReRoutes.Where(x => x.IsCached); + var regions = new List(); - foreach(var reRoute in config.Data.ReRoutes) + foreach(var reRoute in cachedReRoutes) { var region = _creator.Region(reRoute); regions.Add(region); diff --git a/src/Ocelot/Controllers/OutputCacheController.cs b/src/Ocelot/Controllers/OutputCacheController.cs index 04150a5f..67a07d07 100644 --- a/src/Ocelot/Controllers/OutputCacheController.cs +++ b/src/Ocelot/Controllers/OutputCacheController.cs @@ -7,7 +7,7 @@ using Ocelot.Configuration.Provider; namespace Ocelot.Controllers { [Authorize] - [Route("cache")] + [Route("outputcache")] public class OutputCacheController : Controller { private IOcelotCache _cache; diff --git a/test/Ocelot.IntegrationTests/AdministrationTests.cs b/test/Ocelot.IntegrationTests/AdministrationTests.cs index b03d587e..e0826b68 100644 --- a/test/Ocelot.IntegrationTests/AdministrationTests.cs +++ b/test/Ocelot.IntegrationTests/AdministrationTests.cs @@ -218,6 +218,63 @@ namespace Ocelot.IntegrationTests .BDDfy(); } + [Fact] + public void should_return_regions() + { + + var initialConfiguration = new FileConfiguration + { + GlobalConfiguration = new FileGlobalConfiguration + { + AdministrationPath = "/administration" + }, + ReRoutes = new List() + { + new FileReRoute() + { + DownstreamHost = "localhost", + DownstreamPort = 80, + DownstreamScheme = "https", + DownstreamPathTemplate = "/", + UpstreamHttpMethod = new List { "get" }, + UpstreamPathTemplate = "/", + FileCacheOptions = new FileCacheOptions + { + TtlSeconds = 10 + } + }, + new FileReRoute() + { + DownstreamHost = "localhost", + DownstreamPort = 80, + DownstreamScheme = "https", + DownstreamPathTemplate = "/", + UpstreamHttpMethod = new List { "get" }, + UpstreamPathTemplate = "/test", + FileCacheOptions = new FileCacheOptions + { + TtlSeconds = 10 + } + } + } + }; + + var expected = new List + { + "get /", + "get /test" + }; + + this.Given(x => GivenThereIsAConfiguration(initialConfiguration)) + .And(x => GivenOcelotIsRunning()) + .And(x => GivenIHaveAnOcelotToken("/administration")) + .And(x => GivenIHaveAddedATokenToMyRequest()) + .When(x => WhenIGetUrlOnTheApiGateway("/administration/outputcache")) + .Then(x => ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .And(x => ThenTheResponseShouldBe(expected)) + .BDDfy(); + } + private void GivenAnotherOcelotIsRunning(string baseUrl) { _httpClientTwo.BaseAddress = new Uri(baseUrl); @@ -256,6 +313,13 @@ namespace Ocelot.IntegrationTests _response = _httpClient.PostAsync(url, content).Result; } + private void ThenTheResponseShouldBe(List expected) + { + var content = _response.Content.ReadAsStringAsync().Result; + var result = JsonConvert.DeserializeObject>(content); + result.ShouldBe(expected); + } + private void ThenTheResponseShouldBe(FileConfiguration expected) { var response = JsonConvert.DeserializeObject(_response.Content.ReadAsStringAsync().Result); diff --git a/test/Ocelot.UnitTests/Cache/RegionsGetterTests.cs b/test/Ocelot.UnitTests/Cache/RegionsGetterTests.cs index 1f235daf..a7d2b662 100644 --- a/test/Ocelot.UnitTests/Cache/RegionsGetterTests.cs +++ b/test/Ocelot.UnitTests/Cache/RegionsGetterTests.cs @@ -38,9 +38,13 @@ namespace Ocelot.UnitTests.Cache [Fact] public void should_get_regions() { + var cacheOptions = new CacheOptions(12); + var reRoute = new ReRouteBuilder() .WithUpstreamHttpMethod(new List{"Get"}) .WithUpstreamPathTemplate("/") + .WithCacheOptions(cacheOptions) + .WithIsCached(true) .Build(); var reRoutes = new List @@ -62,7 +66,7 @@ namespace Ocelot.UnitTests.Cache .BDDfy(); } - [Fact] + [Fact] public void should_return_empty_regions() { var expected = new List(); From ab953f28fdeb29f37e05758d3ee09891e893f1a8 Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Wed, 28 Jun 2017 08:17:48 +0100 Subject: [PATCH 18/35] realised the user can just set the region..delete time --- src/Ocelot/Cache/RegionBuilder.cs | 4 +- src/Ocelot/Cache/Regions.cs | 13 ++++ src/Ocelot/Configuration/CacheOptions.cs | 1 + .../Configuration/File/FileCacheOptions.cs | 1 + .../Controllers/OutputCacheController.cs | 7 +- .../AdministrationTests.cs | 66 +++++++++++++++++-- .../Ocelot.IntegrationTests.csproj | 1 + .../Ocelot.ManualTest.csproj | 1 + .../Cache/RegionCreatorTests.cs | 2 +- .../Controllers/OutputCacheControllerTests.cs | 2 +- 10 files changed, 86 insertions(+), 12 deletions(-) create mode 100644 src/Ocelot/Cache/Regions.cs diff --git a/src/Ocelot/Cache/RegionBuilder.cs b/src/Ocelot/Cache/RegionBuilder.cs index eb9972bc..5ccf8973 100644 --- a/src/Ocelot/Cache/RegionBuilder.cs +++ b/src/Ocelot/Cache/RegionBuilder.cs @@ -12,9 +12,9 @@ namespace Ocelot.Cache { public string Region(ReRoute reRoute) { - var methods = string.Join(",", reRoute.UpstreamHttpMethod.Select(m => m.Method)); + var methods = string.Join("", reRoute.UpstreamHttpMethod.Select(m => m.Method)); - var region = $"{methods} {reRoute.UpstreamPathTemplate.Value}"; + var region = $"{methods}{reRoute.UpstreamPathTemplate.Value.Replace("/", "")}"; return region; } diff --git a/src/Ocelot/Cache/Regions.cs b/src/Ocelot/Cache/Regions.cs new file mode 100644 index 00000000..1dbefbd5 --- /dev/null +++ b/src/Ocelot/Cache/Regions.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace Ocelot.Cache +{ + public class Regions + { + public Regions(List value) + { + Value = value; + } + public List Value {get;private set;} + } +} \ No newline at end of file diff --git a/src/Ocelot/Configuration/CacheOptions.cs b/src/Ocelot/Configuration/CacheOptions.cs index 2fdaf2bb..3de9e019 100644 --- a/src/Ocelot/Configuration/CacheOptions.cs +++ b/src/Ocelot/Configuration/CacheOptions.cs @@ -8,5 +8,6 @@ } public int TtlSeconds { get; private set; } + public string Region {get;private set;} } } diff --git a/src/Ocelot/Configuration/File/FileCacheOptions.cs b/src/Ocelot/Configuration/File/FileCacheOptions.cs index 3f86006b..46fc7b87 100644 --- a/src/Ocelot/Configuration/File/FileCacheOptions.cs +++ b/src/Ocelot/Configuration/File/FileCacheOptions.cs @@ -3,5 +3,6 @@ public class FileCacheOptions { public int TtlSeconds { get; set; } + public string Region {get;private set;} } } diff --git a/src/Ocelot/Controllers/OutputCacheController.cs b/src/Ocelot/Controllers/OutputCacheController.cs index 67a07d07..21dccb8d 100644 --- a/src/Ocelot/Controllers/OutputCacheController.cs +++ b/src/Ocelot/Controllers/OutputCacheController.cs @@ -1,4 +1,5 @@ using System.Net.Http; +using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Ocelot.Cache; @@ -20,10 +21,10 @@ namespace Ocelot.Controllers } [HttpGet] - public IActionResult Get() + public async Task Get() { - var regions = _regionsGetter.Regions(); - return new OkObjectResult(regions); + var regions = await _regionsGetter.Regions(); + return new OkObjectResult(new Regions(regions)); } [HttpDelete] diff --git a/test/Ocelot.IntegrationTests/AdministrationTests.cs b/test/Ocelot.IntegrationTests/AdministrationTests.cs index e0826b68..0a0f20e4 100644 --- a/test/Ocelot.IntegrationTests/AdministrationTests.cs +++ b/test/Ocelot.IntegrationTests/AdministrationTests.cs @@ -7,6 +7,7 @@ using System.Net.Http.Headers; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; +using Ocelot.Cache; using Ocelot.Configuration.File; using Ocelot.ManualTest; using Shouldly; @@ -221,7 +222,6 @@ namespace Ocelot.IntegrationTests [Fact] public void should_return_regions() { - var initialConfiguration = new FileConfiguration { GlobalConfiguration = new FileGlobalConfiguration @@ -261,8 +261,8 @@ namespace Ocelot.IntegrationTests var expected = new List { - "get /", - "get /test" + "get", + "gettest" }; this.Given(x => GivenThereIsAConfiguration(initialConfiguration)) @@ -275,6 +275,57 @@ namespace Ocelot.IntegrationTests .BDDfy(); } + [Fact] + public void should_clear_region() + { + var initialConfiguration = new FileConfiguration + { + GlobalConfiguration = new FileGlobalConfiguration + { + AdministrationPath = "/administration" + }, + ReRoutes = new List() + { + new FileReRoute() + { + DownstreamHost = "localhost", + DownstreamPort = 80, + DownstreamScheme = "https", + DownstreamPathTemplate = "/", + UpstreamHttpMethod = new List { "get" }, + UpstreamPathTemplate = "/", + FileCacheOptions = new FileCacheOptions + { + TtlSeconds = 10 + } + }, + new FileReRoute() + { + DownstreamHost = "localhost", + DownstreamPort = 80, + DownstreamScheme = "https", + DownstreamPathTemplate = "/", + UpstreamHttpMethod = new List { "get" }, + UpstreamPathTemplate = "/test", + FileCacheOptions = new FileCacheOptions + { + TtlSeconds = 10 + } + } + } + }; + + var regionToClear = "gettest"; + + this.Given(x => GivenThereIsAConfiguration(initialConfiguration)) + .And(x => GivenOcelotIsRunning()) + .And(x => GivenIHaveAnOcelotToken("/administration")) + .And(x => GivenIHaveAddedATokenToMyRequest()) + .When(x => WhenIDeleteOnTheApiGateway($"/administration/outputcache/{regionToClear}")) + .Then(x => ThenTheStatusCodeShouldBe(HttpStatusCode.NoContent)) + .BDDfy(); + } + private void GivenAnotherOcelotIsRunning(string baseUrl) { _httpClientTwo.BaseAddress = new Uri(baseUrl); @@ -316,8 +367,8 @@ namespace Ocelot.IntegrationTests private void ThenTheResponseShouldBe(List expected) { var content = _response.Content.ReadAsStringAsync().Result; - var result = JsonConvert.DeserializeObject>(content); - result.ShouldBe(expected); + var result = JsonConvert.DeserializeObject(content); + result.Value.ShouldBe(expected); } private void ThenTheResponseShouldBe(FileConfiguration expected) @@ -417,6 +468,11 @@ namespace Ocelot.IntegrationTests _response = _httpClient.GetAsync(url).Result; } + private void WhenIDeleteOnTheApiGateway(string url) + { + _response = _httpClient.DeleteAsync(url).Result; + } + private void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode) { _response.StatusCode.ShouldBe(expectedHttpStatusCode); diff --git a/test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.csproj b/test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.csproj index 59513b38..1556111a 100644 --- a/test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.csproj +++ b/test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.csproj @@ -30,6 +30,7 @@ + diff --git a/test/Ocelot.ManualTest/Ocelot.ManualTest.csproj b/test/Ocelot.ManualTest/Ocelot.ManualTest.csproj index f541111f..57f23ad0 100644 --- a/test/Ocelot.ManualTest/Ocelot.ManualTest.csproj +++ b/test/Ocelot.ManualTest/Ocelot.ManualTest.csproj @@ -22,6 +22,7 @@ + diff --git a/test/Ocelot.UnitTests/Cache/RegionCreatorTests.cs b/test/Ocelot.UnitTests/Cache/RegionCreatorTests.cs index 9d2b5a65..ed8491ec 100644 --- a/test/Ocelot.UnitTests/Cache/RegionCreatorTests.cs +++ b/test/Ocelot.UnitTests/Cache/RegionCreatorTests.cs @@ -23,7 +23,7 @@ namespace Ocelot.UnitTests.Cache this.Given(_ => GivenTheReRoute(reRoute)) .When(_ => WhenICreateTheRegion()) - .Then(_ => ThenTheRegionIs("Get /test/dummy")) + .Then(_ => ThenTheRegionIs("Gettestdummy")) .BDDfy(); } diff --git a/test/Ocelot.UnitTests/Controllers/OutputCacheControllerTests.cs b/test/Ocelot.UnitTests/Controllers/OutputCacheControllerTests.cs index fa43369e..7639ed78 100644 --- a/test/Ocelot.UnitTests/Controllers/OutputCacheControllerTests.cs +++ b/test/Ocelot.UnitTests/Controllers/OutputCacheControllerTests.cs @@ -61,7 +61,7 @@ namespace Ocelot.UnitTests.Controllers private void WhenIGetTheKeys() { - _result = _controller.Get(); + _result = _controller.Get().Result; } private void ThenTheKeysAreReturned() From 0f60a353efdaca0d73f17e17b122fbd8aa58ef76 Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Wed, 28 Jun 2017 19:02:08 +0100 Subject: [PATCH 19/35] now set region in config...or it defaults to something --- src/Ocelot/Cache/IOcelotCache.cs | 2 +- src/Ocelot/Cache/IRegionCreator.cs | 9 ++ .../Cache/Middleware/OutputCacheMiddleware.cs | 8 +- src/Ocelot/Cache/OcelotCacheManagerCache.cs | 7 +- .../{RegionBuilder.cs => RegionCreator.cs} | 16 +-- src/Ocelot/Cache/RegionsGetter.cs | 50 -------- src/Ocelot/Configuration/CacheOptions.cs | 3 +- .../Creator/FileOcelotConfigurationCreator.cs | 10 +- .../Configuration/File/FileCacheOptions.cs | 2 +- src/Ocelot/Configuration/ReRoute.cs | 4 +- .../ConsulOcelotConfigurationRepository.cs | 4 +- .../Controllers/OutputCacheController.cs | 11 +- .../ServiceCollectionExtensions.cs | 1 - .../Cache/CacheManagerCacheTests.cs | 10 +- .../Cache/OutputCacheMiddlewareTests.cs | 6 +- .../Cache/RegionCreatorTests.cs | 33 +++-- .../Cache/RegionsGetterTests.cs | 113 ------------------ .../FileConfigurationCreatorTests.cs | 49 +++++++- .../Controllers/OutputCacheControllerTests.cs | 28 +---- 19 files changed, 124 insertions(+), 242 deletions(-) create mode 100644 src/Ocelot/Cache/IRegionCreator.cs rename src/Ocelot/Cache/{RegionBuilder.cs => RegionCreator.cs} (53%) delete mode 100644 src/Ocelot/Cache/RegionsGetter.cs delete mode 100644 test/Ocelot.UnitTests/Cache/RegionsGetterTests.cs diff --git a/src/Ocelot/Cache/IOcelotCache.cs b/src/Ocelot/Cache/IOcelotCache.cs index 9d7ead9b..9abf5761 100644 --- a/src/Ocelot/Cache/IOcelotCache.cs +++ b/src/Ocelot/Cache/IOcelotCache.cs @@ -7,7 +7,7 @@ namespace Ocelot.Cache { void Add(string key, T value, TimeSpan ttl, string region); void AddAndDelete(string key, T value, TimeSpan ttl, string region); - T Get(string key); + T Get(string key, string region); void ClearRegion(string region); } } diff --git a/src/Ocelot/Cache/IRegionCreator.cs b/src/Ocelot/Cache/IRegionCreator.cs new file mode 100644 index 00000000..8ed186dd --- /dev/null +++ b/src/Ocelot/Cache/IRegionCreator.cs @@ -0,0 +1,9 @@ +using Ocelot.Configuration.File; + +namespace Ocelot.Cache +{ + public interface IRegionCreator + { + string Create(FileReRoute reRoute); + } +} \ No newline at end of file diff --git a/src/Ocelot/Cache/Middleware/OutputCacheMiddleware.cs b/src/Ocelot/Cache/Middleware/OutputCacheMiddleware.cs index 8b8b565d..9c6dcf32 100644 --- a/src/Ocelot/Cache/Middleware/OutputCacheMiddleware.cs +++ b/src/Ocelot/Cache/Middleware/OutputCacheMiddleware.cs @@ -37,11 +37,11 @@ namespace Ocelot.Cache.Middleware return; } - var downstreamUrlKey = DownstreamRequest.RequestUri.OriginalString; + var downstreamUrlKey = $"{DownstreamRequest.Method.Method}-{DownstreamRequest.RequestUri.OriginalString}"; _logger.LogDebug("started checking cache for {downstreamUrlKey}", downstreamUrlKey); - var cached = _outputCache.Get(downstreamUrlKey); + var cached = _outputCache.Get(downstreamUrlKey, DownstreamRoute.ReRoute.CacheOptions.Region); if (cached != null) { @@ -67,9 +67,7 @@ namespace Ocelot.Cache.Middleware var response = HttpResponseMessage; - var region = _regionCreator.Region(DownstreamRoute.ReRoute); - - _outputCache.Add(downstreamUrlKey, response, TimeSpan.FromSeconds(DownstreamRoute.ReRoute.FileCacheOptions.TtlSeconds), region); + _outputCache.Add(downstreamUrlKey, response, TimeSpan.FromSeconds(DownstreamRoute.ReRoute.CacheOptions.TtlSeconds), DownstreamRoute.ReRoute.CacheOptions.Region); _logger.LogDebug("finished response added to cache for {downstreamUrlKey}", downstreamUrlKey); } diff --git a/src/Ocelot/Cache/OcelotCacheManagerCache.cs b/src/Ocelot/Cache/OcelotCacheManagerCache.cs index 4edfdaad..33ee1543 100644 --- a/src/Ocelot/Cache/OcelotCacheManagerCache.cs +++ b/src/Ocelot/Cache/OcelotCacheManagerCache.cs @@ -8,18 +8,15 @@ namespace Ocelot.Cache public class OcelotCacheManagerCache : IOcelotCache { private readonly ICacheManager _cacheManager; - private HashSet _keys; public OcelotCacheManagerCache(ICacheManager cacheManager) { _cacheManager = cacheManager; - _keys = new HashSet(); } public void Add(string key, T value, TimeSpan ttl, string region) { _cacheManager.Add(new CacheItem(key, region, value, ExpirationMode.Absolute, ttl)); - _keys.Add(key); } public void AddAndDelete(string key, T value, TimeSpan ttl, string region) @@ -34,9 +31,9 @@ namespace Ocelot.Cache Add(key, value, ttl, region); } - public T Get(string key) + public T Get(string key, string region) { - return _cacheManager.Get(key); + return _cacheManager.Get(key, region); } public void ClearRegion(string region) diff --git a/src/Ocelot/Cache/RegionBuilder.cs b/src/Ocelot/Cache/RegionCreator.cs similarity index 53% rename from src/Ocelot/Cache/RegionBuilder.cs rename to src/Ocelot/Cache/RegionCreator.cs index 5ccf8973..87de751c 100644 --- a/src/Ocelot/Cache/RegionBuilder.cs +++ b/src/Ocelot/Cache/RegionCreator.cs @@ -1,20 +1,22 @@ using System.Linq; using Ocelot.Configuration; +using Ocelot.Configuration.File; namespace Ocelot.Cache { - public interface IRegionCreator - { - string Region(ReRoute reRoute); - } public class RegionCreator : IRegionCreator { - public string Region(ReRoute reRoute) + public string Create(FileReRoute reRoute) { - var methods = string.Join("", reRoute.UpstreamHttpMethod.Select(m => m.Method)); + if(!string.IsNullOrEmpty(reRoute?.FileCacheOptions?.Region)) + { + return reRoute?.FileCacheOptions?.Region; + } - var region = $"{methods}{reRoute.UpstreamPathTemplate.Value.Replace("/", "")}"; + var methods = string.Join("", reRoute.UpstreamHttpMethod.Select(m => m)); + + var region = $"{methods}{reRoute.UpstreamPathTemplate.Replace("/", "")}"; return region; } diff --git a/src/Ocelot/Cache/RegionsGetter.cs b/src/Ocelot/Cache/RegionsGetter.cs deleted file mode 100644 index ae87a49f..00000000 --- a/src/Ocelot/Cache/RegionsGetter.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Ocelot.Configuration.Provider; -using Ocelot.Logging; - -namespace Ocelot.Cache -{ - public interface IRegionsGetter - { - Task> Regions(); - } - public class RegionsGetter : IRegionsGetter - { - private readonly IOcelotConfigurationProvider _provider; - private readonly IRegionCreator _creator; - private readonly IOcelotLogger _logger; - - public RegionsGetter(IOcelotConfigurationProvider provider, IRegionCreator creator, IOcelotLoggerFactory loggerFactory) - { - _logger = loggerFactory.CreateLogger(); - _provider = provider; - _creator = creator; - } - - public async Task> Regions() - { - var config = await _provider.Get(); - - if(config.IsError) - { - _logger.LogError("unable to find regions", new Exception(string.Join(",", config.Errors))); - return new List(); - } - - var cachedReRoutes = config.Data.ReRoutes.Where(x => x.IsCached); - - var regions = new List(); - - foreach(var reRoute in cachedReRoutes) - { - var region = _creator.Region(reRoute); - regions.Add(region); - } - - return regions; - } - } -} \ No newline at end of file diff --git a/src/Ocelot/Configuration/CacheOptions.cs b/src/Ocelot/Configuration/CacheOptions.cs index 3de9e019..a8b6a9d3 100644 --- a/src/Ocelot/Configuration/CacheOptions.cs +++ b/src/Ocelot/Configuration/CacheOptions.cs @@ -2,9 +2,10 @@ { public class CacheOptions { - public CacheOptions(int ttlSeconds) + public CacheOptions(int ttlSeconds, string region) { TtlSeconds = ttlSeconds; + Region = region; } public int TtlSeconds { get; private set; } diff --git a/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs index c44edd08..3b9c91d0 100644 --- a/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs +++ b/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs @@ -4,6 +4,7 @@ using System.Text; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Ocelot.Cache; using Ocelot.Configuration.Builder; using Ocelot.Configuration.File; using Ocelot.Configuration.Parser; @@ -36,6 +37,7 @@ namespace Ocelot.Configuration.Creator private IQoSOptionsCreator _qosOptionsCreator; private IReRouteOptionsCreator _fileReRouteOptionsCreator; private IRateLimitOptionsCreator _rateLimitOptionsCreator; + private IRegionCreator _regionCreator; public FileOcelotConfigurationCreator( IOptions options, @@ -52,9 +54,11 @@ namespace Ocelot.Configuration.Creator IServiceProviderConfigurationCreator serviceProviderConfigCreator, IQoSOptionsCreator qosOptionsCreator, IReRouteOptionsCreator fileReRouteOptionsCreator, - IRateLimitOptionsCreator rateLimitOptionsCreator + IRateLimitOptionsCreator rateLimitOptionsCreator, + IRegionCreator regionCreator ) { + _regionCreator = regionCreator; _rateLimitOptionsCreator = rateLimitOptionsCreator; _requestIdKeyCreator = requestIdKeyCreator; _upstreamTemplatePatternCreator = upstreamTemplatePatternCreator; @@ -137,6 +141,8 @@ namespace Ocelot.Configuration.Creator var rateLimitOption = _rateLimitOptionsCreator.Create(fileReRoute, globalConfiguration, fileReRouteOptions.EnableRateLimiting); + var region = _regionCreator.Create(fileReRoute); + var reRoute = new ReRouteBuilder() .WithDownstreamPathTemplate(fileReRoute.DownstreamPathTemplate) .WithUpstreamPathTemplate(fileReRoute.UpstreamPathTemplate) @@ -151,7 +157,7 @@ namespace Ocelot.Configuration.Creator .WithClaimsToQueries(claimsToQueries) .WithRequestIdKey(requestIdKey) .WithIsCached(fileReRouteOptions.IsCached) - .WithCacheOptions(new CacheOptions(fileReRoute.FileCacheOptions.TtlSeconds)) + .WithCacheOptions(new CacheOptions(fileReRoute.FileCacheOptions.TtlSeconds, region)) .WithDownstreamScheme(fileReRoute.DownstreamScheme) .WithLoadBalancer(fileReRoute.LoadBalancer) .WithDownstreamHost(fileReRoute.DownstreamHost) diff --git a/src/Ocelot/Configuration/File/FileCacheOptions.cs b/src/Ocelot/Configuration/File/FileCacheOptions.cs index 46fc7b87..df9fb631 100644 --- a/src/Ocelot/Configuration/File/FileCacheOptions.cs +++ b/src/Ocelot/Configuration/File/FileCacheOptions.cs @@ -3,6 +3,6 @@ public class FileCacheOptions { public int TtlSeconds { get; set; } - public string Region {get;private set;} + public string Region {get; set;} } } diff --git a/src/Ocelot/Configuration/ReRoute.cs b/src/Ocelot/Configuration/ReRoute.cs index a6673d09..2b8734c4 100644 --- a/src/Ocelot/Configuration/ReRoute.cs +++ b/src/Ocelot/Configuration/ReRoute.cs @@ -46,7 +46,7 @@ namespace Ocelot.Configuration IsAuthorised = isAuthorised; RequestIdKey = requestIdKey; IsCached = isCached; - FileCacheOptions = fileCacheOptions; + CacheOptions = fileCacheOptions; ClaimsToQueries = claimsToQueries ?? new List(); ClaimsToClaims = claimsToClaims @@ -74,7 +74,7 @@ namespace Ocelot.Configuration public Dictionary RouteClaimsRequirement { get; private set; } public string RequestIdKey { get; private set; } public bool IsCached { get; private set; } - public CacheOptions FileCacheOptions { get; private set; } + public CacheOptions CacheOptions { get; private set; } public string DownstreamScheme {get;private set;} public bool IsQos { get; private set; } public QoSOptions QosOptionsOptions { get; private set; } diff --git a/src/Ocelot/Configuration/Repository/ConsulOcelotConfigurationRepository.cs b/src/Ocelot/Configuration/Repository/ConsulOcelotConfigurationRepository.cs index d7929aaa..c5413274 100644 --- a/src/Ocelot/Configuration/Repository/ConsulOcelotConfigurationRepository.cs +++ b/src/Ocelot/Configuration/Repository/ConsulOcelotConfigurationRepository.cs @@ -30,7 +30,7 @@ namespace Ocelot.Configuration.Repository public async Task> Get() { - var config = _cache.Get(_ocelotConfiguration); + var config = _cache.Get(_ocelotConfiguration, _ocelotConfiguration); if (config != null) { @@ -68,7 +68,7 @@ namespace Ocelot.Configuration.Repository if (result.Response) { - _cache.AddAndDelete(_ocelotConfiguration, ocelotConfiguration, TimeSpan.FromSeconds(3), "OcelotConfiguration"); + _cache.AddAndDelete(_ocelotConfiguration, ocelotConfiguration, TimeSpan.FromSeconds(3), _ocelotConfiguration); return new OkResponse(); } diff --git a/src/Ocelot/Controllers/OutputCacheController.cs b/src/Ocelot/Controllers/OutputCacheController.cs index 21dccb8d..a68201a1 100644 --- a/src/Ocelot/Controllers/OutputCacheController.cs +++ b/src/Ocelot/Controllers/OutputCacheController.cs @@ -12,19 +12,10 @@ namespace Ocelot.Controllers public class OutputCacheController : Controller { private IOcelotCache _cache; - private IRegionsGetter _regionsGetter; - public OutputCacheController(IOcelotCache cache, IRegionsGetter regionsGetter) + public OutputCacheController(IOcelotCache cache) { _cache = cache; - _regionsGetter = regionsGetter; - } - - [HttpGet] - public async Task Get() - { - var regions = await _regionsGetter.Regions(); - return new OkObjectResult(new Regions(regions)); } [HttpDelete] diff --git a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs index d2ff4b74..954942dc 100644 --- a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs @@ -145,7 +145,6 @@ namespace Ocelot.DependencyInjection .AddJsonFormatters(); services.AddLogging(); - services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); diff --git a/test/Ocelot.UnitTests/Cache/CacheManagerCacheTests.cs b/test/Ocelot.UnitTests/Cache/CacheManagerCacheTests.cs index 5780cff2..f097ccf1 100644 --- a/test/Ocelot.UnitTests/Cache/CacheManagerCacheTests.cs +++ b/test/Ocelot.UnitTests/Cache/CacheManagerCacheTests.cs @@ -18,6 +18,7 @@ namespace Ocelot.UnitTests.Cache private string _resultGet; private TimeSpan _ttlSeconds; private List _resultKeys; + private string _region; public CacheManagerCacheTests() { @@ -28,7 +29,7 @@ namespace Ocelot.UnitTests.Cache [Fact] public void should_get_from_cache() { - this.Given(x => x.GivenTheFollowingIsCached("someKey", "someValue")) + this.Given(x => x.GivenTheFollowingIsCached("someKey", "someRegion", "someValue")) .When(x => x.WhenIGetFromTheCache()) .Then(x => x.ThenTheResultIs("someValue")) .BDDfy(); @@ -88,15 +89,16 @@ namespace Ocelot.UnitTests.Cache private void WhenIGetFromTheCache() { - _resultGet = _ocelotOcelotCacheManager.Get(_key); + _resultGet = _ocelotOcelotCacheManager.Get(_key, _region); } - private void GivenTheFollowingIsCached(string key, string value) + private void GivenTheFollowingIsCached(string key, string region, string value) { _key = key; _value = value; + _region = region; _mockCacheManager - .Setup(x => x.Get(It.IsAny())) + .Setup(x => x.Get(It.IsAny(), It.IsAny())) .Returns(value); } } diff --git a/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs b/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs index 0039e2af..ff74fba0 100644 --- a/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs @@ -92,7 +92,7 @@ namespace Ocelot.UnitTests.Cache { var reRoute = new ReRouteBuilder() .WithIsCached(true) - .WithCacheOptions(new CacheOptions(100)) + .WithCacheOptions(new CacheOptions(100, "kanken")) .WithUpstreamHttpMethod(new List { "Get" }) .Build(); @@ -120,7 +120,7 @@ namespace Ocelot.UnitTests.Cache private void ThenTheCacheGetIsCalledCorrectly() { _cacheManager - .Verify(x => x.Get(It.IsAny()), Times.Once); + .Verify(x => x.Get(It.IsAny(), It.IsAny()), Times.Once); } private void ThenTheCacheAddIsCalledCorrectly() @@ -140,7 +140,7 @@ namespace Ocelot.UnitTests.Cache { _response = response; _cacheManager - .Setup(x => x.Get(It.IsAny())) + .Setup(x => x.Get(It.IsAny(), It.IsAny())) .Returns(_response); } diff --git a/test/Ocelot.UnitTests/Cache/RegionCreatorTests.cs b/test/Ocelot.UnitTests/Cache/RegionCreatorTests.cs index ed8491ec..6a475425 100644 --- a/test/Ocelot.UnitTests/Cache/RegionCreatorTests.cs +++ b/test/Ocelot.UnitTests/Cache/RegionCreatorTests.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using Ocelot.Cache; using Ocelot.Configuration; using Ocelot.Configuration.Builder; +using Ocelot.Configuration.File; using Shouldly; using TestStack.BDDfy; using Xunit; @@ -11,23 +12,41 @@ namespace Ocelot.UnitTests.Cache public class RegionCreatorTests { private string _result; - private ReRoute _reRoute; + private FileReRoute _reRoute; [Fact] public void should_create_region() { - var reRoute = new ReRouteBuilder() - .WithUpstreamHttpMethod(new List{"Get"}) - .WithUpstreamPathTemplate("/test/dummy") - .Build(); + var reRoute = new FileReRoute + { + UpstreamHttpMethod = new List { "Get" }, + UpstreamPathTemplate = "/testdummy" + }; this.Given(_ => GivenTheReRoute(reRoute)) .When(_ => WhenICreateTheRegion()) .Then(_ => ThenTheRegionIs("Gettestdummy")) .BDDfy(); } + + [Fact] + public void should_use_region() + { + var reRoute = new FileReRoute + { + FileCacheOptions = new FileCacheOptions + { + Region = "region" + } + }; + + this.Given(_ => GivenTheReRoute(reRoute)) + .When(_ => WhenICreateTheRegion()) + .Then(_ => ThenTheRegionIs("region")) + .BDDfy(); + } - private void GivenTheReRoute(ReRoute reRoute) + private void GivenTheReRoute(FileReRoute reRoute) { _reRoute = reRoute; } @@ -35,7 +54,7 @@ namespace Ocelot.UnitTests.Cache private void WhenICreateTheRegion() { RegionCreator regionCreator = new RegionCreator(); - _result = regionCreator.Region(_reRoute); + _result = regionCreator.Create(_reRoute); } private void ThenTheRegionIs(string expected) diff --git a/test/Ocelot.UnitTests/Cache/RegionsGetterTests.cs b/test/Ocelot.UnitTests/Cache/RegionsGetterTests.cs deleted file mode 100644 index a7d2b662..00000000 --- a/test/Ocelot.UnitTests/Cache/RegionsGetterTests.cs +++ /dev/null @@ -1,113 +0,0 @@ -using Xunit; -using TestStack.BDDfy; -using Shouldly; -using Ocelot.Cache; -using Moq; -using Ocelot.Configuration.Provider; -using System.Collections.Generic; -using Ocelot.Responses; -using Ocelot.Configuration; -using System.Threading.Tasks; -using Ocelot.Configuration.Builder; -using System; -using Ocelot.Errors; -using Ocelot.Logging; - -namespace Ocelot.UnitTests.Cache -{ - public class RegionsGetterTests - { - private RegionsGetter _regionsGetter; - private readonly Mock _provider; - private readonly Mock _creator; - private readonly Mock _factory; - private List _result; - - public RegionsGetterTests() - { - _provider = new Mock(); - _creator = new Mock(); - _factory = new Mock(); - var logger = new Mock(); - _factory - .Setup(x => x.CreateLogger()) - .Returns(logger.Object); - _regionsGetter = new RegionsGetter(_provider.Object, _creator.Object, _factory.Object); - } - - [Fact] - public void should_get_regions() - { - var cacheOptions = new CacheOptions(12); - - var reRoute = new ReRouteBuilder() - .WithUpstreamHttpMethod(new List{"Get"}) - .WithUpstreamPathTemplate("/") - .WithCacheOptions(cacheOptions) - .WithIsCached(true) - .Build(); - - var reRoutes = new List - { - reRoute - }; - - var config = new OcelotConfiguration(reRoutes, "whocares!"); - - var expected = new List - { - "balls" - }; - - this.Given(_ => GivenTheFollowingConfig(config)) - .And(_ => GivenTheProviderReturns("balls")) - .When(_ => WhenIGetTheRegions()) - .Then(_ => ThenTheFollowingIsReturned(expected)) - .BDDfy(); - } - - [Fact] - public void should_return_empty_regions() - { - var expected = new List(); - - this.Given(_ => GivenAnErrorGettingTheConfig()) - .When(_ => WhenIGetTheRegions()) - .Then(_ => ThenTheFollowingIsReturned(expected)) - .BDDfy(); - } - - private void GivenAnErrorGettingTheConfig() - { - var config = new OcelotConfiguration(new List(), "whocares!"); - - _provider - .Setup(x => x.Get()) - .ReturnsAsync(new ErrorResponse(It.IsAny())); - } - - private void GivenTheProviderReturns(string expected) - { - _creator - .Setup(x => x.Region(It.IsAny())) - .Returns(expected); - } - - private void GivenTheFollowingConfig(IOcelotConfiguration config) - { - _provider - .Setup(x => x.Get()) - .ReturnsAsync(new OkResponse(config)); - } - - private void WhenIGetTheRegions() - { - _result = _regionsGetter.Regions().Result; - } - - private void ThenTheFollowingIsReturned(List expected) - { - _result.ShouldBe(expected); - } - } -} \ No newline at end of file diff --git a/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs index bd8c46d3..386958c9 100644 --- a/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Moq; +using Ocelot.Cache; using Ocelot.Configuration; using Ocelot.Configuration.Builder; using Ocelot.Configuration.Creator; @@ -39,6 +40,7 @@ namespace Ocelot.UnitTests.Configuration private Mock _qosOptionsCreator; private Mock _fileReRouteOptionsCreator; private Mock _rateLimitOptions; + private Mock _regionCreator; public FileConfigurationCreatorTests() { @@ -59,6 +61,7 @@ namespace Ocelot.UnitTests.Configuration _qosOptionsCreator = new Mock(); _fileReRouteOptionsCreator = new Mock(); _rateLimitOptions = new Mock(); + _regionCreator = new Mock(); _ocelotConfigurationCreator = new FileOcelotConfigurationCreator( _fileConfig.Object, _validator.Object, _logger.Object, @@ -66,7 +69,51 @@ namespace Ocelot.UnitTests.Configuration _qosProviderFactory.Object, _qosProviderHouse.Object, _claimsToThingCreator.Object, _authOptionsCreator.Object, _upstreamTemplatePatternCreator.Object, _requestIdKeyCreator.Object, _serviceProviderConfigCreator.Object, _qosOptionsCreator.Object, _fileReRouteOptionsCreator.Object, - _rateLimitOptions.Object); + _rateLimitOptions.Object, _regionCreator.Object); + } + + [Fact] + public void should_call_region_creator() + { + var reRouteOptions = new ReRouteOptionsBuilder() + .Build(); + + this.Given(x => x.GivenTheConfigIs(new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamHost = "127.0.0.1", + UpstreamPathTemplate = "/api/products/{productId}", + DownstreamPathTemplate = "/products/{productId}", + UpstreamHttpMethod = new List { "Get" }, + FileCacheOptions = new FileCacheOptions + { + Region = "region" + } + } + }, + })) + .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions)) + .And(x => x.GivenTheConfigIsValid()) + .And(x => x.GivenTheFollowingRegionIsReturned("region")) + .When(x => x.WhenICreateTheConfig()) + .Then(x => x.ThenTheRegionCreatorIsCalledCorrectly("region")) + .BDDfy(); + } + + private void GivenTheFollowingRegionIsReturned(string region) + { + _regionCreator + .Setup(x => x.Create(It.IsAny())) + .Returns(region); + } + + private void ThenTheRegionCreatorIsCalledCorrectly(string expected) + { + _regionCreator + .Verify(x => x.Create(_fileConfiguration.ReRoutes[0]), Times.Once); } [Fact] diff --git a/test/Ocelot.UnitTests/Controllers/OutputCacheControllerTests.cs b/test/Ocelot.UnitTests/Controllers/OutputCacheControllerTests.cs index 7639ed78..100597a0 100644 --- a/test/Ocelot.UnitTests/Controllers/OutputCacheControllerTests.cs +++ b/test/Ocelot.UnitTests/Controllers/OutputCacheControllerTests.cs @@ -15,23 +15,12 @@ namespace Ocelot.UnitTests.Controllers { private OutputCacheController _controller; private Mock> _cache; - private Mock _getter; private IActionResult _result; public OutputCacheControllerTests() { _cache = new Mock>(); - _getter = new Mock(); - _controller = new OutputCacheController(_cache.Object, _getter.Object); - } - - [Fact] - public void should_get_all_keys_from_server() - { - this.Given(_ => GivenTheFollowingKeys(new List{"b", "a"})) - .When(_ => WhenIGetTheKeys()) - .Then(_ => ThenTheKeysAreReturned()) - .BDDfy(); + _controller = new OutputCacheController(_cache.Object); } [Fact] @@ -53,20 +42,5 @@ namespace Ocelot.UnitTests.Controllers { _result = _controller.Delete(key); } - - private void GivenTheFollowingKeys(List keys) - { - - } - - private void WhenIGetTheKeys() - { - _result = _controller.Get().Result; - } - - private void ThenTheKeysAreReturned() - { - _result.ShouldBeOfType(); - } } } \ No newline at end of file From 9a4a670e795959304e436d14cb3f4757ec952bee Mon Sep 17 00:00:00 2001 From: Tom Gardham-Pallister Date: Wed, 28 Jun 2017 19:05:06 +0100 Subject: [PATCH 20/35] sorted int tests --- .../AdministrationTests.cs | 70 ++++--------------- 1 file changed, 12 insertions(+), 58 deletions(-) diff --git a/test/Ocelot.IntegrationTests/AdministrationTests.cs b/test/Ocelot.IntegrationTests/AdministrationTests.cs index 0a0f20e4..39721df6 100644 --- a/test/Ocelot.IntegrationTests/AdministrationTests.cs +++ b/test/Ocelot.IntegrationTests/AdministrationTests.cs @@ -121,7 +121,12 @@ namespace Ocelot.IntegrationTests DownstreamScheme = "https", DownstreamPathTemplate = "/", UpstreamHttpMethod = new List { "get" }, - UpstreamPathTemplate = "/" + UpstreamPathTemplate = "/", + FileCacheOptions = new FileCacheOptions + { + TtlSeconds = 10, + Region = "Geoff" + } }, new FileReRoute() { @@ -130,7 +135,12 @@ namespace Ocelot.IntegrationTests DownstreamScheme = "https", DownstreamPathTemplate = "/", UpstreamHttpMethod = new List { "get" }, - UpstreamPathTemplate = "/test" + UpstreamPathTemplate = "/test", + FileCacheOptions = new FileCacheOptions + { + TtlSeconds = 10, + Region = "Dave" + } } } }; @@ -219,62 +229,6 @@ namespace Ocelot.IntegrationTests .BDDfy(); } - [Fact] - public void should_return_regions() - { - var initialConfiguration = new FileConfiguration - { - GlobalConfiguration = new FileGlobalConfiguration - { - AdministrationPath = "/administration" - }, - ReRoutes = new List() - { - new FileReRoute() - { - DownstreamHost = "localhost", - DownstreamPort = 80, - DownstreamScheme = "https", - DownstreamPathTemplate = "/", - UpstreamHttpMethod = new List { "get" }, - UpstreamPathTemplate = "/", - FileCacheOptions = new FileCacheOptions - { - TtlSeconds = 10 - } - }, - new FileReRoute() - { - DownstreamHost = "localhost", - DownstreamPort = 80, - DownstreamScheme = "https", - DownstreamPathTemplate = "/", - UpstreamHttpMethod = new List { "get" }, - UpstreamPathTemplate = "/test", - FileCacheOptions = new FileCacheOptions - { - TtlSeconds = 10 - } - } - } - }; - - var expected = new List - { - "get", - "gettest" - }; - - this.Given(x => GivenThereIsAConfiguration(initialConfiguration)) - .And(x => GivenOcelotIsRunning()) - .And(x => GivenIHaveAnOcelotToken("/administration")) - .And(x => GivenIHaveAddedATokenToMyRequest()) - .When(x => WhenIGetUrlOnTheApiGateway("/administration/outputcache")) - .Then(x => ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) - .And(x => ThenTheResponseShouldBe(expected)) - .BDDfy(); - } - [Fact] public void should_clear_region() { From 9532d940f15e2c311ffd7782c01d3b1f7b41ed93 Mon Sep 17 00:00:00 2001 From: Nick Sharp Date: Wed, 28 Jun 2017 21:43:37 +0100 Subject: [PATCH 21/35] Implementing jwt and adding tests --- .../Creator/AuthenticationHandlerCreator.cs | 34 +++-- .../SupportedAuthenticationProviders.cs | 3 +- .../Configuration/AuthenticationOptions.cs | 13 ++ .../Builder/AuthenticationOptionsBuilder.cs | 30 +++- .../Creator/AuthenticationOptionsCreator.cs | 16 +-- .../Configuration/Creator/ConfigCreator.cs | 35 +++++ .../File/FileAuthenticationOptions.cs | 9 ++ .../AuthenticationConfigConverter.cs | 8 +- .../AuthenticationHandlerFactoryTests.cs | 10 +- .../AuthenticationOptionsCreatorTests.cs | 133 +++++++++++++----- 10 files changed, 219 insertions(+), 72 deletions(-) create mode 100644 src/Ocelot/Configuration/Creator/ConfigCreator.cs diff --git a/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs b/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs index 910b99e4..b4c1503a 100644 --- a/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs +++ b/src/Ocelot/Authentication/Handler/Creator/AuthenticationHandlerCreator.cs @@ -19,17 +19,31 @@ namespace Ocelot.Authentication.Handler.Creator { var builder = app.New(); - var authenticationConfig = authOptions.Config as IdentityServerConfig; - - builder.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions + if (authOptions.Provider.ToLower() == "jwt") { - Authority = authenticationConfig.ProviderRootUrl, - ApiName = authenticationConfig.ApiName, - RequireHttpsMetadata = authenticationConfig.RequireHttps, - AllowedScopes = authOptions.AllowedScopes, - SupportedTokens = SupportedTokens.Both, - ApiSecret = authenticationConfig.ApiSecret - }); + var authenticationConfig = authOptions.Config as JwtConfig; + + builder.UseJwtBearerAuthentication( + new JwtBearerOptions() + { + Authority = authenticationConfig.Authority, + Audience = authenticationConfig.Audience + }); + } + else + { + var authenticationConfig = authOptions.Config as IdentityServerConfig; + + builder.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions + { + Authority = authenticationConfig.ProviderRootUrl, + ApiName = authenticationConfig.ApiName, + RequireHttpsMetadata = authenticationConfig.RequireHttps, + AllowedScopes = authOptions.AllowedScopes, + SupportedTokens = SupportedTokens.Both, + ApiSecret = authenticationConfig.ApiSecret + }); + } var authenticationNext = builder.Build(); diff --git a/src/Ocelot/Authentication/Handler/SupportedAuthenticationProviders.cs b/src/Ocelot/Authentication/Handler/SupportedAuthenticationProviders.cs index 2a815ee0..5662fe40 100644 --- a/src/Ocelot/Authentication/Handler/SupportedAuthenticationProviders.cs +++ b/src/Ocelot/Authentication/Handler/SupportedAuthenticationProviders.cs @@ -2,6 +2,7 @@ { public enum SupportedAuthenticationProviders { - IdentityServer + IdentityServer, + Jwt } } diff --git a/src/Ocelot/Configuration/AuthenticationOptions.cs b/src/Ocelot/Configuration/AuthenticationOptions.cs index c4a49b7d..1c71d68b 100644 --- a/src/Ocelot/Configuration/AuthenticationOptions.cs +++ b/src/Ocelot/Configuration/AuthenticationOptions.cs @@ -36,5 +36,18 @@ namespace Ocelot.Configuration public bool RequireHttps { get; private set; } } + public class JwtConfig : IAuthenticationConfig + { + public JwtConfig(string authority, string audience) + { + Audience = audience; + Authority = authority; + } + + public string Audience { get; } + + public string Authority { get; } + } + public interface IAuthenticationConfig {} } diff --git a/src/Ocelot/Configuration/Builder/AuthenticationOptionsBuilder.cs b/src/Ocelot/Configuration/Builder/AuthenticationOptionsBuilder.cs index 3f83d3a3..ea43a23e 100644 --- a/src/Ocelot/Configuration/Builder/AuthenticationOptionsBuilder.cs +++ b/src/Ocelot/Configuration/Builder/AuthenticationOptionsBuilder.cs @@ -9,7 +9,7 @@ namespace Ocelot.Configuration.Builder private List _allowedScopes; - private IdentityServerConfig _identityServerConfig; + private IAuthenticationConfig _identityServerConfig; public AuthenticationOptionsBuilder WithProvider(string provider) { @@ -23,7 +23,7 @@ namespace Ocelot.Configuration.Builder return this; } - public AuthenticationOptionsBuilder WithIdntityServerConfigConfiguration(IdentityServerConfig config) + public AuthenticationOptionsBuilder WithConfig(IAuthenticationConfig config) { _identityServerConfig = config; return this; @@ -66,11 +66,33 @@ namespace Ocelot.Configuration.Builder return this; } - - public IdentityServerConfig Build() { return new IdentityServerConfig(_providerRootUrl, _apiName, _requireHttps, _apiSecret); } } + + public class JwtConfigBuilder + { + public string _authority; + + public string _audience; + + public JwtConfigBuilder WithAuthority(string authority) + { + _authority = authority; + return this; + } + + public JwtConfigBuilder WithAudience(string audience) + { + _audience = audience; + return this; + } + + public JwtConfig Build() + { + return new JwtConfig(_authority, _audience); + } + } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/Creator/AuthenticationOptionsCreator.cs b/src/Ocelot/Configuration/Creator/AuthenticationOptionsCreator.cs index 7f3f34a3..d5be4eee 100644 --- a/src/Ocelot/Configuration/Creator/AuthenticationOptionsCreator.cs +++ b/src/Ocelot/Configuration/Creator/AuthenticationOptionsCreator.cs @@ -7,25 +7,13 @@ namespace Ocelot.Configuration.Creator { public AuthenticationOptions Create(FileReRoute fileReRoute) { - var authenticationConfig = new IdentityServerConfigCreator().Create(fileReRoute.AuthenticationOptions); + var authenticationConfig = new ConfigCreator().Create(fileReRoute.AuthenticationOptions); return new AuthenticationOptionsBuilder() .WithProvider(fileReRoute.AuthenticationOptions?.Provider) .WithAllowedScopes(fileReRoute.AuthenticationOptions?.AllowedScopes) - .WithIdntityServerConfigConfiguration(authenticationConfig) + .WithConfig(authenticationConfig) .Build(); } } - - public class IdentityServerConfigCreator - { - public IdentityServerConfig Create(FileAuthenticationOptions authenticationOptions) - { - return new IdentityServerConfigBuilder() - .WithApiName(authenticationOptions.IdentityServerConfig?.ApiName) - .WithApiSecret(authenticationOptions.IdentityServerConfig?.ApiSecret) - .WithProviderRootUrl(authenticationOptions.IdentityServerConfig?.ProviderRootUrl) - .WithRequireHttps(authenticationOptions.IdentityServerConfig.RequireHttps).Build(); - } - } } \ No newline at end of file diff --git a/src/Ocelot/Configuration/Creator/ConfigCreator.cs b/src/Ocelot/Configuration/Creator/ConfigCreator.cs new file mode 100644 index 00000000..09c7ab16 --- /dev/null +++ b/src/Ocelot/Configuration/Creator/ConfigCreator.cs @@ -0,0 +1,35 @@ +namespace Ocelot.Configuration.Creator +{ + using Ocelot.Configuration.Builder; + using Ocelot.Configuration.File; + + public class ConfigCreator + { + public IAuthenticationConfig Create(FileAuthenticationOptions authenticationOptions) + { + if (authenticationOptions.Provider == "Jwt") + { + return CreateJwt(authenticationOptions); + } + + return CreateIdentityServer(authenticationOptions); + } + + private JwtConfig CreateJwt(FileAuthenticationOptions authenticationOptions) + { + return new JwtConfigBuilder() + .WithAudience(authenticationOptions.JwtConfig?.Audience) + .WithAuthority(authenticationOptions.JwtConfig?.Authority) + .Build(); + } + + private IdentityServerConfig CreateIdentityServer(FileAuthenticationOptions authenticationOptions) + { + return new IdentityServerConfigBuilder() + .WithApiName(authenticationOptions.IdentityServerConfig?.ApiName) + .WithApiSecret(authenticationOptions.IdentityServerConfig?.ApiSecret) + .WithProviderRootUrl(authenticationOptions.IdentityServerConfig?.ProviderRootUrl) + .WithRequireHttps(authenticationOptions.IdentityServerConfig.RequireHttps).Build(); + } + } +} \ No newline at end of file diff --git a/src/Ocelot/Configuration/File/FileAuthenticationOptions.cs b/src/Ocelot/Configuration/File/FileAuthenticationOptions.cs index 8216aa8d..31be2307 100644 --- a/src/Ocelot/Configuration/File/FileAuthenticationOptions.cs +++ b/src/Ocelot/Configuration/File/FileAuthenticationOptions.cs @@ -8,11 +8,13 @@ namespace Ocelot.Configuration.File { AllowedScopes = new List(); IdentityServerConfig = new FileIdentityServerConfig(); + JwtConfig = new FileJwtConfig(); } public string Provider { get; set; } public List AllowedScopes { get; set; } public FileIdentityServerConfig IdentityServerConfig { get; set; } + public FileJwtConfig JwtConfig { get; set; } } public class FileIdentityServerConfig @@ -22,4 +24,11 @@ namespace Ocelot.Configuration.File public bool RequireHttps { get; set; } public string ApiSecret { get; set; } } + + public class FileJwtConfig + { + public string Authority { get; set; } + + public string Audience { get; set; } + } } diff --git a/src/Ocelot/JsonConverters/AuthenticationConfigConverter.cs b/src/Ocelot/JsonConverters/AuthenticationConfigConverter.cs index e63b1fe6..06699c28 100644 --- a/src/Ocelot/JsonConverters/AuthenticationConfigConverter.cs +++ b/src/Ocelot/JsonConverters/AuthenticationConfigConverter.cs @@ -25,8 +25,12 @@ namespace Ocelot.AcceptanceTests { switch (jsonObject["Provider"].Value()) { - //case "Jwt": - // setting = new + case "Jwt": + setting = new JwtConfig( + jsonObject["Authority"].Value(), + jsonObject["Audience"].Value()); + break; + default: setting = new IdentityServerConfig( jsonObject["ProviderRootUrl"].Value(), diff --git a/test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs b/test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs index 8bf53607..55e1a05c 100644 --- a/test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs +++ b/test/Ocelot.UnitTests/Authentication/AuthenticationHandlerFactoryTests.cs @@ -31,17 +31,19 @@ namespace Ocelot.UnitTests.Authentication _authenticationHandlerFactory = new AuthenticationHandlerFactory(_creator.Object); } - [Fact] - public void should_return_identity_server_access_token_handler() + [Theory] + [InlineData("IdentityServer")] + [InlineData("Jwt")] + public void should_return_access_token_handler(string provider) { var authenticationOptions = new AuthenticationOptionsBuilder() - .WithProvider("IdentityServer") + .WithProvider(provider) .Build(); this.Given(x => x.GivenTheAuthenticationOptionsAre(authenticationOptions)) .And(x => x.GivenTheCreatorReturns()) .When(x => x.WhenIGetFromTheFactory()) - .Then(x => x.ThenTheHandlerIsReturned("IdentityServer")) + .Then(x => x.ThenTheHandlerIsReturned(provider)) .BDDfy(); } diff --git a/test/Ocelot.UnitTests/Configuration/AuthenticationOptionsCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/AuthenticationOptionsCreatorTests.cs index 575b62b7..85245207 100644 --- a/test/Ocelot.UnitTests/Configuration/AuthenticationOptionsCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/AuthenticationOptionsCreatorTests.cs @@ -20,36 +20,78 @@ namespace Ocelot.UnitTests.Configuration _authOptionsCreator = new AuthenticationOptionsCreator(); } - // [Fact] - // public void should_return_auth_options() - // { - // var fileReRoute = new FileReRoute() - // { - // AuthenticationOptions = new FileAuthenticationOptions - // { - // Provider = "Geoff", - // ProviderRootUrl = "http://www.bbc.co.uk/", - //ApiName = "Laura", - // RequireHttps = true, - //AllowedScopes = new List {"cheese"}, - // ApiSecret = "secret" - // } - // }; + [Fact] + public void should_return_auth_options() + { + var fileReRoute = new FileReRoute() + { + AuthenticationOptions = new FileAuthenticationOptions + { + Provider = "Geoff", + IdentityServerConfig = new FileIdentityServerConfig() + { + ProviderRootUrl = "http://www.bbc.co.uk/", + ApiName = "Laura", + RequireHttps = true, + ApiSecret = "secret" + }, + AllowedScopes = new List { "cheese" }, + + } + }; - // var expected = new AuthenticationOptionsBuilder() - // .WithProvider(fileReRoute.AuthenticationOptions?.Provider) - // .WithProviderRootUrl(fileReRoute.AuthenticationOptions?.ProviderRootUrl) - // .WithApiName(fileReRoute.AuthenticationOptions?.ApiName) - // .WithRequireHttps(fileReRoute.AuthenticationOptions.RequireHttps) - // .WithAllowedScopes(fileReRoute.AuthenticationOptions?.AllowedScopes) - // .WithApiSecret(fileReRoute.AuthenticationOptions?.ApiSecret) - // .Build(); + var authenticationConfig = new IdentityServerConfigBuilder() + .WithProviderRootUrl(fileReRoute.AuthenticationOptions?.IdentityServerConfig?.ProviderRootUrl) + .WithApiName(fileReRoute.AuthenticationOptions?.IdentityServerConfig?.ApiName) + .WithRequireHttps(fileReRoute.AuthenticationOptions.IdentityServerConfig.RequireHttps) + .WithApiSecret(fileReRoute.AuthenticationOptions?.IdentityServerConfig?.ApiSecret) + .Build(); - // this.Given(x => x.GivenTheFollowing(fileReRoute)) - // .When(x => x.WhenICreateTheAuthenticationOptions()) - // .Then(x => x.ThenTheFollowingIsReturned(expected)) - // .BDDfy(); - // } + var expected = new AuthenticationOptionsBuilder() + .WithProvider(fileReRoute.AuthenticationOptions?.Provider) + .WithAllowedScopes(fileReRoute.AuthenticationOptions?.AllowedScopes) + .WithConfig(authenticationConfig) + .Build(); + + this.Given(x => x.GivenTheFollowing(fileReRoute)) + .When(x => x.WhenICreateTheAuthenticationOptions()) + .Then(x => x.ThenTheFollowingIdentityServerConfigIsReturned(expected)) + .BDDfy(); + } + + [Fact] + public void should_return_Jwt_auth_options() + { + var fileReRoute = new FileReRoute() + { + AuthenticationOptions = new FileAuthenticationOptions + { + Provider = "Jwt", + JwtConfig = new FileJwtConfig() + { + Audience = "Audience", + Authority = "Authority" + }, + AllowedScopes = new List { "cheese" } + } + }; + + var authenticationConfig = new JwtConfigBuilder() + .WithAudience(fileReRoute.AuthenticationOptions?.JwtConfig?.Audience) + .WithAuthority(fileReRoute.AuthenticationOptions?.JwtConfig?.Authority) + .Build(); + + var expected = new AuthenticationOptionsBuilder() + .WithProvider(fileReRoute.AuthenticationOptions?.Provider) + .WithAllowedScopes(fileReRoute.AuthenticationOptions?.AllowedScopes) + .WithConfig(authenticationConfig) + .Build(); + + this.Given(x => x.GivenTheFollowing(fileReRoute)) + .When(x => x.WhenICreateTheAuthenticationOptions()) + .Then(x => x.ThenTheFollowingJwtConfigIsReturned(expected)) + .BDDfy(); + } private void GivenTheFollowing(FileReRoute fileReRoute) { @@ -61,14 +103,31 @@ namespace Ocelot.UnitTests.Configuration _result = _authOptionsCreator.Create(_fileReRoute); } - //private void ThenTheFollowingIsReturned(AuthenticationOptions expected) - //{ - // _result.AllowedScopes.ShouldBe(expected.AllowedScopes); - // _result.Provider.ShouldBe(expected.Provider); - // _result.ProviderRootUrl.ShouldBe(expected.ProviderRootUrl); - // _result.RequireHttps.ShouldBe(expected.RequireHttps); - // _result.ApiName.ShouldBe(expected.ApiName); - // _result.ApiSecret.ShouldBe(expected.ApiSecret); - //} + private void ThenTheFollowingJwtConfigIsReturned(AuthenticationOptions expected) + { + _result.AllowedScopes.ShouldBe(expected.AllowedScopes); + _result.Provider.ShouldBe(expected.Provider); + + var _resultSettings = _result.Config as JwtConfig; + var expectedSettngs = expected.Config as JwtConfig; + + _resultSettings.Audience.ShouldBe(expectedSettngs.Audience); + _resultSettings.Authority.ShouldBe(expectedSettngs.Authority); + + } + + private void ThenTheFollowingIdentityServerConfigIsReturned(AuthenticationOptions expected) + { + _result.AllowedScopes.ShouldBe(expected.AllowedScopes); + _result.Provider.ShouldBe(expected.Provider); + + var _resultSettings = _result.Config as IdentityServerConfig; + var expectedSettngs = expected.Config as IdentityServerConfig; + + _resultSettings.ProviderRootUrl.ShouldBe(expectedSettngs.ProviderRootUrl); + _resultSettings.RequireHttps.ShouldBe(expectedSettngs.RequireHttps); + _resultSettings.ApiName.ShouldBe(expectedSettngs.ApiName); + _resultSettings.ApiSecret.ShouldBe(expectedSettngs.ApiSecret); + } } } \ No newline at end of file From 1168eb311042613360b121cf3e1eb453189f33ae Mon Sep 17 00:00:00 2001 From: Nick Sharp Date: Thu, 29 Jun 2017 08:58:41 +0100 Subject: [PATCH 22/35] Reenabling some tests --- .../FileConfigurationCreatorTests.cs | 234 ++++++++---------- .../TestData/AuthenticationConfigTestData.cs | 89 +++++++ 2 files changed, 190 insertions(+), 133 deletions(-) create mode 100644 test/Ocelot.UnitTests/TestData/AuthenticationConfigTestData.cs diff --git a/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs index 8a701f31..f7f59c97 100644 --- a/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/FileConfigurationCreatorTests.cs @@ -17,6 +17,10 @@ using Xunit; namespace Ocelot.UnitTests.Configuration { + using System.Collections; + + using Ocelot.UnitTests.TestData; + public class FileConfigurationCreatorTests { private readonly Mock> _fileConfig; @@ -393,132 +397,82 @@ namespace Ocelot.UnitTests.Configuration .BDDfy(); } - //[Fact] - //public void should_create_with_headers_to_extract() - //{ - // var reRouteOptions = new ReRouteOptionsBuilder() - // .WithIsAuthenticated(true) - // .Build(); + [Theory] + [MemberData(nameof(AuthenticationConfigTestData.GetAuthenticationData), MemberType = typeof(AuthenticationConfigTestData))] + public void should_create_with_headers_to_extract(string provider, IAuthenticationConfig config, FileConfiguration fileConfig) + { + var reRouteOptions = new ReRouteOptionsBuilder() + .WithIsAuthenticated(true) + .Build(); - // var authenticationOptions = new AuthenticationOptionsBuilder() - // .WithProvider("IdentityServer") - // .WithProviderRootUrl("http://localhost:51888") - // .WithRequireHttps(false) - // .WithApiSecret("secret") - // .WithApiName("api") - // .WithAllowedScopes(new List()) - // .Build(); + var authenticationOptions = new AuthenticationOptionsBuilder() + .WithProvider(provider) + .WithAllowedScopes(new List()) + .WithConfig(config) + .Build(); - // var expected = new List - // { - // new ReRouteBuilder() - // .WithDownstreamPathTemplate("/products/{productId}") - // .WithUpstreamPathTemplate("/api/products/{productId}") - // .WithUpstreamHttpMethod(new List { "Get" }) - // .WithAuthenticationOptions(authenticationOptions) - // .WithClaimsToHeaders(new List - // { - // new ClaimToThing("CustomerId", "CustomerId", "", 0), - // }) - // .Build() - // }; + var expected = new List + { + new ReRouteBuilder() + .WithDownstreamPathTemplate("/products/{productId}") + .WithUpstreamPathTemplate("/api/products/{productId}") + .WithUpstreamHttpMethod(new List { "Get" }) + .WithAuthenticationOptions(authenticationOptions) + .WithClaimsToHeaders(new List + { + new ClaimToThing("CustomerId", "CustomerId", "", 0), + }) + .Build() + }; - // this.Given(x => x.GivenTheConfigIs(new FileConfiguration - // { - // ReRoutes = new List - // { - // new FileReRoute - // { - // UpstreamPathTemplate = "/api/products/{productId}", - // DownstreamPathTemplate = "/products/{productId}", - // UpstreamHttpMethod = new List { "Get" }, - // ReRouteIsCaseSensitive = true, - // AuthenticationOptions = new FileAuthenticationOptions - // { - //AllowedScopes= new List(), - // Provider = "IdentityServer", - // ProviderRootUrl = "http://localhost:51888", - // RequireHttps = false, - //ApiName= "api", - // ApiSecret = "secret" - // }, - // AddHeadersToRequest = - // { - // {"CustomerId", "Claims[CustomerId] > value"}, - // } - // } - // } - // })) - // .And(x => x.GivenTheConfigIsValid()) - // .And(x => x.GivenTheAuthOptionsCreatorReturns(authenticationOptions)) - // .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions)) - // .And(x => x.GivenTheClaimsToThingCreatorReturns(new List{new ClaimToThing("CustomerId", "CustomerId", "", 0)})) - // .And(x => x.GivenTheLoadBalancerFactoryReturns()) - // .When(x => x.WhenICreateTheConfig()) - // .Then(x => x.ThenTheReRoutesAre(expected)) - // .And(x => x.ThenTheAuthenticationOptionsAre(expected)) - // .And(x => x.ThenTheAuthOptionsCreatorIsCalledCorrectly()) - // .BDDfy(); - //} + this.Given(x => x.GivenTheConfigIs(fileConfig)) + .And(x => x.GivenTheConfigIsValid()) + .And(x => x.GivenTheAuthOptionsCreatorReturns(authenticationOptions)) + .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions)) + .And(x => x.GivenTheClaimsToThingCreatorReturns(new List { new ClaimToThing("CustomerId", "CustomerId", "", 0) })) + .And(x => x.GivenTheLoadBalancerFactoryReturns()) + .When(x => x.WhenICreateTheConfig()) + .Then(x => x.ThenTheReRoutesAre(expected)) + .And(x => x.ThenTheAuthenticationOptionsAre(provider, expected)) + .And(x => x.ThenTheAuthOptionsCreatorIsCalledCorrectly()) + .BDDfy(); + } - //[Fact] - //public void should_create_with_authentication_properties() - //{ - // var reRouteOptions = new ReRouteOptionsBuilder() - // .WithIsAuthenticated(true) - // .Build(); + [Theory] + [MemberData(nameof(AuthenticationConfigTestData.GetAuthenticationData), MemberType = typeof(AuthenticationConfigTestData))] + public void should_create_with_authentication_properties(string provider, IAuthenticationConfig config, FileConfiguration fileConfig) + { + var reRouteOptions = new ReRouteOptionsBuilder() + .WithIsAuthenticated(true) + .Build(); - // var authenticationOptions = new AuthenticationOptionsBuilder() - // .WithProvider("IdentityServer") - // .WithProviderRootUrl("http://localhost:51888") - // .WithRequireHttps(false) - // .WithApiSecret("secret") - // .WithApiName("api") - // .WithAllowedScopes(new List()) - // .Build(); + var authenticationOptions = new AuthenticationOptionsBuilder() + .WithProvider(provider) + .WithAllowedScopes(new List()) + .WithConfig(config) + .Build(); - // var expected = new List - // { - // new ReRouteBuilder() - // .WithDownstreamPathTemplate("/products/{productId}") - // .WithUpstreamPathTemplate("/api/products/{productId}") - // .WithUpstreamHttpMethod(new List { "Get" }) - // .WithAuthenticationOptions(authenticationOptions) - // .Build() - // }; + var expected = new List + { + new ReRouteBuilder() + .WithDownstreamPathTemplate("/products/{productId}") + .WithUpstreamPathTemplate("/api/products/{productId}") + .WithUpstreamHttpMethod(new List { "Get" }) + .WithAuthenticationOptions(authenticationOptions) + .Build() + }; - // this.Given(x => x.GivenTheConfigIs(new FileConfiguration - // { - // ReRoutes = new List - // { - // new FileReRoute - // { - // UpstreamPathTemplate = "/api/products/{productId}", - // DownstreamPathTemplate = "/products/{productId}", - // UpstreamHttpMethod = new List { "Get" }, - // ReRouteIsCaseSensitive = true, - // AuthenticationOptions = new FileAuthenticationOptions - // { - //AllowedScopes = new List(), - // Provider = "IdentityServer", - // ProviderRootUrl = "http://localhost:51888", - // RequireHttps = false, - //ApiName= "api", - // ApiSecret = "secret" - // } - // } - // } - // })) - // .And(x => x.GivenTheConfigIsValid()) - // .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions)) - // .And(x => x.GivenTheAuthOptionsCreatorReturns(authenticationOptions)) - // .And(x => x.GivenTheLoadBalancerFactoryReturns()) - // .When(x => x.WhenICreateTheConfig()) - // .Then(x => x.ThenTheReRoutesAre(expected)) - // .And(x => x.ThenTheAuthenticationOptionsAre(expected)) - // .And(x => x.ThenTheAuthOptionsCreatorIsCalledCorrectly()) - // .BDDfy(); - //} + this.Given(x => x.GivenTheConfigIs(fileConfig)) + .And(x => x.GivenTheConfigIsValid()) + .And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions)) + .And(x => x.GivenTheAuthOptionsCreatorReturns(authenticationOptions)) + .And(x => x.GivenTheLoadBalancerFactoryReturns()) + .When(x => x.WhenICreateTheConfig()) + .Then(x => x.ThenTheReRoutesAre(expected)) + .And(x => x.ThenTheAuthenticationOptionsAre(provider, expected)) + .And(x => x.ThenTheAuthOptionsCreatorIsCalledCorrectly()) + .BDDfy(); + } private void GivenTheFollowingOptionsAreReturned(ReRouteOptions fileReRouteOptions) { @@ -586,22 +540,36 @@ namespace Ocelot.UnitTests.Configuration } } - //private void ThenTheAuthenticationOptionsAre(List expectedReRoutes) - //{ - // for (int i = 0; i < _config.Data.ReRoutes.Count; i++) - // { - // var result = _config.Data.ReRoutes[i].AuthenticationOptions; - // var expected = expectedReRoutes[i].AuthenticationOptions; + private void ThenTheAuthenticationOptionsAre(string provider, List expectedReRoutes) + { + for (int i = 0; i < _config.Data.ReRoutes.Count; i++) + { + var result = _config.Data.ReRoutes[i].AuthenticationOptions; + var expected = expectedReRoutes[i].AuthenticationOptions; - // result.AllowedScopes.ShouldBe(expected.AllowedScopes); - // result.Provider.ShouldBe(expected.Provider); - // result.ProviderRootUrl.ShouldBe(expected.ProviderRootUrl); - // result.RequireHttps.ShouldBe(expected.RequireHttps); - // result.ApiName.ShouldBe(expected.ApiName); - // result.ApiSecret.ShouldBe(expected.ApiSecret); + result.AllowedScopes.ShouldBe(expected.AllowedScopes); + result.Provider.ShouldBe(expected.Provider); - // } - //} + if (provider.ToLower() == "identityserver") + { + var config = result.Config as IdentityServerConfig; + var expectedConfig = expected.Config as IdentityServerConfig; + + config.ProviderRootUrl.ShouldBe(expectedConfig.ProviderRootUrl); + config.RequireHttps.ShouldBe(expectedConfig.RequireHttps); + config.ApiName.ShouldBe(expectedConfig.ApiName); + config.ApiSecret.ShouldBe(expectedConfig.ApiSecret); + } + else + { + var config = result.Config as JwtConfig; + var expectedConfig = expected.Config as JwtConfig; + + config.Audience.ShouldBe(expectedConfig.Audience); + config.Authority.ShouldBe(expectedConfig.Authority); + } + } + } private void GivenTheLoadBalancerFactoryReturns() { diff --git a/test/Ocelot.UnitTests/TestData/AuthenticationConfigTestData.cs b/test/Ocelot.UnitTests/TestData/AuthenticationConfigTestData.cs new file mode 100644 index 00000000..5392a58d --- /dev/null +++ b/test/Ocelot.UnitTests/TestData/AuthenticationConfigTestData.cs @@ -0,0 +1,89 @@ +namespace Ocelot.UnitTests.TestData +{ + using System.Collections.Generic; + + using Ocelot.Configuration.Builder; + using Ocelot.Configuration.File; + + public class AuthenticationConfigTestData + { + public static IEnumerable GetAuthenticationData() + { + yield return new object[] + { + "IdentityServer", + new IdentityServerConfigBuilder() + .WithRequireHttps(true) + .WithApiName("test") + .WithApiSecret("test") + .WithProviderRootUrl("test") + .Build(), + new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + UpstreamPathTemplate = "/api/products/{productId}", + DownstreamPathTemplate = "/products/{productId}", + UpstreamHttpMethod = new List { "Get" }, + ReRouteIsCaseSensitive = true, + AuthenticationOptions = new FileAuthenticationOptions + { + AllowedScopes = new List(), + Provider = "IdentityServer", + IdentityServerConfig = new FileIdentityServerConfig + { + ProviderRootUrl = "http://localhost:51888", + RequireHttps = false, + ApiName = "api", + ApiSecret = "secret" + } + }, + AddHeadersToRequest = + { + { "CustomerId", "Claims[CustomerId] > value" }, + } + } + } + } + }; + + yield return new object[] + { + "Jwt", + new JwtConfigBuilder() + .WithAudience("a") + .WithAuthority("au") + .Build(), + new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + UpstreamPathTemplate = "/api/products/{productId}", + DownstreamPathTemplate = "/products/{productId}", + UpstreamHttpMethod = new List { "Get" }, + ReRouteIsCaseSensitive = true, + AuthenticationOptions = new FileAuthenticationOptions + { + AllowedScopes = new List(), + Provider = "IdentityServer", + JwtConfig = new FileJwtConfig + { + Audience = "a", + Authority = "au" + } + }, + AddHeadersToRequest = + { + { "CustomerId", "Claims[CustomerId] > value" }, + } + } + } + } + }; + } + } +} From 58dc7c93bc0b8bd6ebc1949cbcd277345d245c4f Mon Sep 17 00:00:00 2001 From: TomPallister Date: Tue, 4 Jul 2017 19:14:37 +0100 Subject: [PATCH 23/35] moved json converters under authentication feature --- .../JsonConverters/AuthenticationConfigConverter.cs | 4 ++-- .../Repository/ConsulOcelotConfigurationRepository.cs | 3 +-- test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs | 1 + 3 files changed, 4 insertions(+), 4 deletions(-) rename src/Ocelot/{ => Authentication}/JsonConverters/AuthenticationConfigConverter.cs (96%) diff --git a/src/Ocelot/JsonConverters/AuthenticationConfigConverter.cs b/src/Ocelot/Authentication/JsonConverters/AuthenticationConfigConverter.cs similarity index 96% rename from src/Ocelot/JsonConverters/AuthenticationConfigConverter.cs rename to src/Ocelot/Authentication/JsonConverters/AuthenticationConfigConverter.cs index 06699c28..6aca01be 100644 --- a/src/Ocelot/JsonConverters/AuthenticationConfigConverter.cs +++ b/src/Ocelot/Authentication/JsonConverters/AuthenticationConfigConverter.cs @@ -1,10 +1,10 @@ using System; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using Ocelot.Configuration; -namespace Ocelot.AcceptanceTests +namespace Ocelot.Authentication.JsonConverters { - using Newtonsoft.Json.Linq; public class AuthenticationConfigConverter : JsonConverter { public override bool CanWrite => false; diff --git a/src/Ocelot/Configuration/Repository/ConsulOcelotConfigurationRepository.cs b/src/Ocelot/Configuration/Repository/ConsulOcelotConfigurationRepository.cs index 9fd26f87..6fa6f72a 100644 --- a/src/Ocelot/Configuration/Repository/ConsulOcelotConfigurationRepository.cs +++ b/src/Ocelot/Configuration/Repository/ConsulOcelotConfigurationRepository.cs @@ -4,13 +4,12 @@ using System.Threading.Tasks; using Consul; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using Ocelot.Authentication.JsonConverters; using Ocelot.Responses; using Ocelot.ServiceDiscovery; namespace Ocelot.Configuration.Repository { - using Ocelot.AcceptanceTests; - public class ConsulOcelotConfigurationRepository : IOcelotConfigurationRepository { private readonly ConsulClient _consul; diff --git a/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs b/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs index afed1164..231f8410 100644 --- a/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs +++ b/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs @@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Newtonsoft.Json; +using Ocelot.Authentication.JsonConverters; using Ocelot.Configuration; using Ocelot.Configuration.File; using Ocelot.Configuration.Repository; From 34cd2e1392124c5673a5ec3c54f46965d22bd58d Mon Sep 17 00:00:00 2001 From: TomPallister Date: Tue, 4 Jul 2017 19:18:08 +0100 Subject: [PATCH 24/35] moved classes into seperate files --- .../File/FileAuthenticationOptions.cs | 15 --------------- .../File/FileIdentityServerConfig.cs | 10 ++++++++++ src/Ocelot/Configuration/File/FileJwtConfig.cs | 9 +++++++++ 3 files changed, 19 insertions(+), 15 deletions(-) create mode 100644 src/Ocelot/Configuration/File/FileIdentityServerConfig.cs create mode 100644 src/Ocelot/Configuration/File/FileJwtConfig.cs diff --git a/src/Ocelot/Configuration/File/FileAuthenticationOptions.cs b/src/Ocelot/Configuration/File/FileAuthenticationOptions.cs index 31be2307..6333993d 100644 --- a/src/Ocelot/Configuration/File/FileAuthenticationOptions.cs +++ b/src/Ocelot/Configuration/File/FileAuthenticationOptions.cs @@ -16,19 +16,4 @@ namespace Ocelot.Configuration.File public FileIdentityServerConfig IdentityServerConfig { get; set; } public FileJwtConfig JwtConfig { get; set; } } - - public class FileIdentityServerConfig - { - public string ProviderRootUrl { get; set; } - public string ApiName { get; set; } - public bool RequireHttps { get; set; } - public string ApiSecret { get; set; } - } - - public class FileJwtConfig - { - public string Authority { get; set; } - - public string Audience { get; set; } - } } diff --git a/src/Ocelot/Configuration/File/FileIdentityServerConfig.cs b/src/Ocelot/Configuration/File/FileIdentityServerConfig.cs new file mode 100644 index 00000000..dfc023b2 --- /dev/null +++ b/src/Ocelot/Configuration/File/FileIdentityServerConfig.cs @@ -0,0 +1,10 @@ +namespace Ocelot.Configuration.File +{ + public class FileIdentityServerConfig + { + public string ProviderRootUrl { get; set; } + public string ApiName { get; set; } + public bool RequireHttps { get; set; } + public string ApiSecret { get; set; } + } +} \ No newline at end of file diff --git a/src/Ocelot/Configuration/File/FileJwtConfig.cs b/src/Ocelot/Configuration/File/FileJwtConfig.cs new file mode 100644 index 00000000..a24522fc --- /dev/null +++ b/src/Ocelot/Configuration/File/FileJwtConfig.cs @@ -0,0 +1,9 @@ +namespace Ocelot.Configuration.File +{ + public class FileJwtConfig + { + public string Authority { get; set; } + + public string Audience { get; set; } + } +} \ No newline at end of file From 09c9a258833fac1f3a66038c3edffbe57cf41e99 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Tue, 4 Jul 2017 19:41:41 +0100 Subject: [PATCH 25/35] bit more tidying --- .../Middleware/AuthenticationMiddleware.cs | 4 ++-- .../Creator/AuthenticationOptionsCreator.cs | 10 +++++++++- ...r.cs => AuthenticationProviderConfigCreator.cs} | 6 ++++-- .../Creator/FileOcelotConfigurationCreator.cs | 14 +++++++------- .../IAuthenticationProviderConfigCreator.cs | 10 ++++++++++ .../ServiceCollectionExtensions.cs | 2 ++ test/Ocelot.ManualTest/configuration.json | 9 ++++++--- .../AuthenticationOptionsCreatorTests.cs | 4 ++-- 8 files changed, 42 insertions(+), 17 deletions(-) rename src/Ocelot/Configuration/Creator/{ConfigCreator.cs => AuthenticationProviderConfigCreator.cs} (86%) create mode 100644 src/Ocelot/Creator/Configuration/IAuthenticationProviderConfigCreator.cs diff --git a/src/Ocelot/Authentication/Middleware/AuthenticationMiddleware.cs b/src/Ocelot/Authentication/Middleware/AuthenticationMiddleware.cs index cfd21b64..31ef6976 100644 --- a/src/Ocelot/Authentication/Middleware/AuthenticationMiddleware.cs +++ b/src/Ocelot/Authentication/Middleware/AuthenticationMiddleware.cs @@ -53,7 +53,7 @@ namespace Ocelot.Authentication.Middleware if (context.User.Identity.IsAuthenticated) { _logger.LogDebug($"Client has been authenticated for {context.Request.Path}"); - await _next.Invoke(context); + await _next.Invoke(context); } else { @@ -72,7 +72,7 @@ namespace Ocelot.Authentication.Middleware { _logger.LogTrace($"No authentication needed for {context.Request.Path}"); - await _next.Invoke(context); + await _next.Invoke(context); } } diff --git a/src/Ocelot/Configuration/Creator/AuthenticationOptionsCreator.cs b/src/Ocelot/Configuration/Creator/AuthenticationOptionsCreator.cs index d5be4eee..284ec33c 100644 --- a/src/Ocelot/Configuration/Creator/AuthenticationOptionsCreator.cs +++ b/src/Ocelot/Configuration/Creator/AuthenticationOptionsCreator.cs @@ -1,13 +1,21 @@ using Ocelot.Configuration.Builder; using Ocelot.Configuration.File; +using Ocelot.Creator.Configuration; namespace Ocelot.Configuration.Creator { public class AuthenticationOptionsCreator : IAuthenticationOptionsCreator { + private readonly IAuthenticationProviderConfigCreator _creator; + + public AuthenticationOptionsCreator(IAuthenticationProviderConfigCreator creator) + { + _creator = creator; + } + public AuthenticationOptions Create(FileReRoute fileReRoute) { - var authenticationConfig = new ConfigCreator().Create(fileReRoute.AuthenticationOptions); + var authenticationConfig = _creator.Create(fileReRoute.AuthenticationOptions); return new AuthenticationOptionsBuilder() .WithProvider(fileReRoute.AuthenticationOptions?.Provider) diff --git a/src/Ocelot/Configuration/Creator/ConfigCreator.cs b/src/Ocelot/Configuration/Creator/AuthenticationProviderConfigCreator.cs similarity index 86% rename from src/Ocelot/Configuration/Creator/ConfigCreator.cs rename to src/Ocelot/Configuration/Creator/AuthenticationProviderConfigCreator.cs index 09c7ab16..c7a25799 100644 --- a/src/Ocelot/Configuration/Creator/ConfigCreator.cs +++ b/src/Ocelot/Configuration/Creator/AuthenticationProviderConfigCreator.cs @@ -1,13 +1,15 @@ +using Ocelot.Creator.Configuration; + namespace Ocelot.Configuration.Creator { using Ocelot.Configuration.Builder; using Ocelot.Configuration.File; - public class ConfigCreator + public class AuthenticationProviderConfigCreator : IAuthenticationProviderConfigCreator { public IAuthenticationConfig Create(FileAuthenticationOptions authenticationOptions) { - if (authenticationOptions.Provider == "Jwt") + if (authenticationOptions.Provider?.ToLower() == "jwt") { return CreateJwt(authenticationOptions); } diff --git a/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs index 3b9c91d0..c6f5f4fe 100644 --- a/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs +++ b/src/Ocelot/Configuration/Creator/FileOcelotConfigurationCreator.cs @@ -31,13 +31,13 @@ namespace Ocelot.Configuration.Creator private readonly IQosProviderHouse _qosProviderHouse; private readonly IClaimsToThingCreator _claimsToThingCreator; private readonly IAuthenticationOptionsCreator _authOptionsCreator; - private IUpstreamTemplatePatternCreator _upstreamTemplatePatternCreator; - private IRequestIdKeyCreator _requestIdKeyCreator; - private IServiceProviderConfigurationCreator _serviceProviderConfigCreator; - private IQoSOptionsCreator _qosOptionsCreator; - private IReRouteOptionsCreator _fileReRouteOptionsCreator; - private IRateLimitOptionsCreator _rateLimitOptionsCreator; - private IRegionCreator _regionCreator; + private readonly IUpstreamTemplatePatternCreator _upstreamTemplatePatternCreator; + private readonly IRequestIdKeyCreator _requestIdKeyCreator; + private readonly IServiceProviderConfigurationCreator _serviceProviderConfigCreator; + private readonly IQoSOptionsCreator _qosOptionsCreator; + private readonly IReRouteOptionsCreator _fileReRouteOptionsCreator; + private readonly IRateLimitOptionsCreator _rateLimitOptionsCreator; + private readonly IRegionCreator _regionCreator; public FileOcelotConfigurationCreator( IOptions options, diff --git a/src/Ocelot/Creator/Configuration/IAuthenticationProviderConfigCreator.cs b/src/Ocelot/Creator/Configuration/IAuthenticationProviderConfigCreator.cs new file mode 100644 index 00000000..f5cd4fda --- /dev/null +++ b/src/Ocelot/Creator/Configuration/IAuthenticationProviderConfigCreator.cs @@ -0,0 +1,10 @@ +using Ocelot.Configuration; +using Ocelot.Configuration.File; + +namespace Ocelot.Creator.Configuration +{ + public interface IAuthenticationProviderConfigCreator + { + IAuthenticationConfig Create(FileAuthenticationOptions authenticationOptions); + } +} \ No newline at end of file diff --git a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs index 954942dc..d55a8573 100644 --- a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs @@ -44,6 +44,7 @@ using System.Reflection; using System.Security.Cryptography.X509Certificates; using Microsoft.IdentityModel.Tokens; using Ocelot.Configuration; +using Ocelot.Creator.Configuration; using FileConfigurationProvider = Ocelot.Configuration.Provider.FileConfigurationProvider; namespace Ocelot.DependencyInjection @@ -71,6 +72,7 @@ namespace Ocelot.DependencyInjection services.Configure(configurationRoot); services.TryAddSingleton(); + services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); diff --git a/test/Ocelot.ManualTest/configuration.json b/test/Ocelot.ManualTest/configuration.json index 765326cf..6d2ee544 100644 --- a/test/Ocelot.ManualTest/configuration.json +++ b/test/Ocelot.ManualTest/configuration.json @@ -14,13 +14,16 @@ }, "AuthenticationOptions": { "Provider": "IdentityServer", - "ProviderRootUrl": "http://localhost:52888", - "ApiName": "api", "AllowedScopes": [ "openid", "offline_access" ], - "ApiSecret": "secret" + "IdentityServerConfig": { + "ProviderRootUrl": "http://localhost:52888", + "ApiName": "api", + "ApiSecret": "secret", + "RequireHttps": false + } }, "AddHeadersToRequest": { "CustomerId": "Claims[CustomerId] > value", diff --git a/test/Ocelot.UnitTests/Configuration/AuthenticationOptionsCreatorTests.cs b/test/Ocelot.UnitTests/Configuration/AuthenticationOptionsCreatorTests.cs index 85245207..7e2108ee 100644 --- a/test/Ocelot.UnitTests/Configuration/AuthenticationOptionsCreatorTests.cs +++ b/test/Ocelot.UnitTests/Configuration/AuthenticationOptionsCreatorTests.cs @@ -11,13 +11,13 @@ namespace Ocelot.UnitTests.Configuration { public class AuthenticationOptionsCreatorTests { - private AuthenticationOptionsCreator _authOptionsCreator; + private readonly AuthenticationOptionsCreator _authOptionsCreator; private FileReRoute _fileReRoute; private AuthenticationOptions _result; public AuthenticationOptionsCreatorTests() { - _authOptionsCreator = new AuthenticationOptionsCreator(); + _authOptionsCreator = new AuthenticationOptionsCreator(new AuthenticationProviderConfigCreator()); } [Fact] From c173f3bb45417f055cb5227d8d692461e65a80be Mon Sep 17 00:00:00 2001 From: TomPallister Date: Tue, 4 Jul 2017 19:45:03 +0100 Subject: [PATCH 26/35] removed files we dont use anymore --- configuration-explanation.txt | 103 ---------------------------------- configuration.json | 1 - configuration.yaml | 3 - 3 files changed, 107 deletions(-) delete mode 100644 configuration-explanation.txt delete mode 100755 configuration.json delete mode 100755 configuration.yaml diff --git a/configuration-explanation.txt b/configuration-explanation.txt deleted file mode 100644 index 09d44a2a..00000000 --- a/configuration-explanation.txt +++ /dev/null @@ -1,103 +0,0 @@ -{ - "ReRoutes": [ - { - # 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 - "UpstreamPathTemplate": "/identityserverexample", - # The method we are listening for on this re route - "UpstreamHttpMethod": "Get", - # Only support identity server at the moment - "AuthenticationOptions": { - "Provider": "IdentityServer", - "ProviderRootUrl": "http://localhost:52888", - "ApiName": "api", - "AllowedScopes": [ - "openid", - "offline_access" - ], - # Required if using reference tokens - "ApiSecret": "secret" - }, - # WARNING - will overwrite any headers already in the request with these values. - # Ocelot will look in the user claims for the key in [] then return the value and save - # it as a header with the given key before the colon (:). The index selection on value - # means that Ocelot will use the delimiter specified after the next > to split the - # claim value and return the index specified. - "AddHeadersToRequest": { - "CustomerId": "Claims[CustomerId] > value", - "LocationId": "Claims[LocationId] > value", - "UserType": "Claims[sub] > value[0] > |", - "UserId": "Claims[sub] > value[1] > |" - }, - # WARNING - will overwrite any claims already in the request with these values. - # Ocelot will look in the user claims for the key in [] then return the value and save - # it as a claim with the given key before the colon (:). The index selection on value - # means that Ocelot will use the delimiter specified after the next > to split the - # claim value and return the index specified. - "AddClaimsToRequest": { - "CustomerId": "Claims[CustomerId] > value", - "LocationId": "Claims[LocationId] > value", - "UserType": "Claims[sub] > value[0] > |", - "UserId": "Claims[sub] > value[1] > |" - }, - # WARNING - will overwrite any query string entries already in the request with these values. - # Ocelot will look in the user claims for the key in [] then return the value and save - # it as a query string with the given key before the colon (:). The index selection on value - # means that Ocelot will use the delimiter specified after the next > to split the - # claim value and return the index specified. - "AddQueriesToRequest": { - "CustomerId": "Claims[CustomerId] > value", - "LocationId": "Claims[LocationId] > value", - "UserType": "Claims[sub] > value[0] > |", - "UserId": "Claims[sub] > value[1] > |" - }, - # This specifies any claims that are required for the user to access this re route. - # In this example the user must have the claim type UserType and - # the value must be registered - "RouteClaimsRequirement": { - "UserType": "registered" - }, - # This tells Ocelot to look for a header and use its value as a request/correlation id. - # If it is set here then the id will be forwarded to the downstream service. If it - # does not then it will not be forwarded - "RequestIdKey": "OcRequestId", - # If this is set the response from the downstream service will be cached using the key that called it. - # This gives the user a chance to influence the key by adding some random query string paramter for - # a user id or something that would get ignored by the downstream service. This is a hack and I - # intend to provide a mechanism the user can specify for the ttl caching. Also want to expand - # the caching a lot. - "FileCacheOptions": { "TtlSeconds": 15 }, - # The value of this is used when matching the upstream template to an upstream url. - "ReRouteIsCaseSensitive": false, - # Tells Ocelot the name of the service it is looking when making requests to service discovery - # for hosts and ports - "ServiceName": "product" - # Tells Ocelot which load balancer to use when making downstream requests. - "LoadBalancer": "RoundRobin" - }, - # This section is meant to be for global configuration settings - "GlobalConfiguration": { - # If this is set it will override any route specific request id keys, behaves the same - # otherwise - "RequestIdKey": "OcRequestId", - # If set Ocelot will try and use service discovery to locate downstream hosts and ports - "ServiceDiscoveryProvider": - { - "Provider":"Consul", - "Host":"localhost", - "Port":8500 - } - } - } \ No newline at end of file diff --git a/configuration.json b/configuration.json deleted file mode 100755 index 65b211fc..00000000 --- a/configuration.json +++ /dev/null @@ -1 +0,0 @@ -{"ReRoutes":[{"DownstreamPathTemplate":"/","UpstreamPathTemplate":"/","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":"https","DownstreamHost":"localhost","DownstreamPort":80,"QoSOptions":{"ExceptionsAllowedBeforeBreaking":0,"DurationOfBreak":0,"TimeoutValue":0},"LoadBalancer":null,"RateLimitOptions":{"ClientWhitelist":[],"EnableRateLimiting":false,"Period":null,"PeriodTimespan":0.0,"Limit":0}},{"DownstreamPathTemplate":"/","UpstreamPathTemplate":"/test","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":"https","DownstreamHost":"localhost","DownstreamPort":80,"QoSOptions":{"ExceptionsAllowedBeforeBreaking":0,"DurationOfBreak":0,"TimeoutValue":0},"LoadBalancer":null,"RateLimitOptions":{"ClientWhitelist":[],"EnableRateLimiting":false,"Period":null,"PeriodTimespan":0.0,"Limit":0}}],"GlobalConfiguration":{"RequestIdKey":"RequestId","ServiceDiscoveryProvider":{"Provider":"test","Host":"127.0.0.1","Port":0},"AdministrationPath":"/administration","RateLimitOptions":{"ClientIdHeader":"ClientId","QuotaExceededMessage":null,"RateLimitCounterPrefix":"ocelot","DisableRateLimitHeaders":false,"HttpStatusCode":429}}} \ No newline at end of file diff --git a/configuration.yaml b/configuration.yaml deleted file mode 100755 index 2e47e77d..00000000 --- a/configuration.yaml +++ /dev/null @@ -1,3 +0,0 @@ -Routes: -- Downstream: http://localhost:51879/ - Upstream: /heee From b0c12431d61b613432e4cb3f417a12eee5908597 Mon Sep 17 00:00:00 2001 From: Philip Wood Date: Tue, 11 Jul 2017 18:45:53 +0100 Subject: [PATCH 27/35] Added test coverage around responder middleware, and refactored these to not use test server. --- .../Middleware/AuthenticationMiddleware.cs | 2 +- .../DownstreamRouteFinderMiddleware.cs | 2 +- src/Ocelot/Middleware/OcelotMiddleware.cs | 4 +- .../Middleware/ResponderMiddleware.cs | 3 +- test/Ocelot.UnitTests/Responder/AnyError.cs | 15 ++ .../ErrorsToHttpStatusCodeMapperTests.cs | 158 ++++++++++++++---- .../Responder/ResponderMiddlewareTestsV2.cs | 140 ++++++++++++++++ 7 files changed, 281 insertions(+), 43 deletions(-) create mode 100644 test/Ocelot.UnitTests/Responder/AnyError.cs create mode 100644 test/Ocelot.UnitTests/Responder/ResponderMiddlewareTestsV2.cs diff --git a/src/Ocelot/Authentication/Middleware/AuthenticationMiddleware.cs b/src/Ocelot/Authentication/Middleware/AuthenticationMiddleware.cs index 31ef6976..f6ecd654 100644 --- a/src/Ocelot/Authentication/Middleware/AuthenticationMiddleware.cs +++ b/src/Ocelot/Authentication/Middleware/AuthenticationMiddleware.cs @@ -36,7 +36,7 @@ namespace Ocelot.Authentication.Middleware { if (IsAuthenticatedRoute(DownstreamRoute.ReRoute)) { - _logger.LogDebug($"{context.Request.Path} is an authenticated route. {MiddlwareName} checking if client is authenticated"); + _logger.LogDebug($"{context.Request.Path} is an authenticated route. {MiddlewareName} checking if client is authenticated"); var authenticationHandler = _authHandlerFactory.Get(_app, DownstreamRoute.ReRoute.AuthenticationOptions); diff --git a/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs b/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs index 8fdd2a54..51cb3a0b 100644 --- a/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs +++ b/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs @@ -38,7 +38,7 @@ namespace Ocelot.DownstreamRouteFinder.Middleware if (downstreamRoute.IsError) { - _logger.LogError($"{MiddlwareName} setting pipeline errors. IDownstreamRouteFinder returned {downstreamRoute.Errors.ToErrorString()}"); + _logger.LogError($"{MiddlewareName} setting pipeline errors. IDownstreamRouteFinder returned {downstreamRoute.Errors.ToErrorString()}"); SetPipelineError(downstreamRoute.Errors); return; diff --git a/src/Ocelot/Middleware/OcelotMiddleware.cs b/src/Ocelot/Middleware/OcelotMiddleware.cs index af56891e..0060cbb3 100644 --- a/src/Ocelot/Middleware/OcelotMiddleware.cs +++ b/src/Ocelot/Middleware/OcelotMiddleware.cs @@ -13,10 +13,10 @@ namespace Ocelot.Middleware protected OcelotMiddleware(IRequestScopedDataRepository requestScopedDataRepository) { _requestScopedDataRepository = requestScopedDataRepository; - MiddlwareName = this.GetType().Name; + MiddlewareName = this.GetType().Name; } - public string MiddlwareName { get; } + public string MiddlewareName { get; } public bool PipelineError => _requestScopedDataRepository.Get("OcelotMiddlewareError").Data; diff --git a/src/Ocelot/Responder/Middleware/ResponderMiddleware.cs b/src/Ocelot/Responder/Middleware/ResponderMiddleware.cs index 2b6f52f1..b6ed2717 100644 --- a/src/Ocelot/Responder/Middleware/ResponderMiddleware.cs +++ b/src/Ocelot/Responder/Middleware/ResponderMiddleware.cs @@ -39,7 +39,7 @@ namespace Ocelot.Responder.Middleware if (PipelineError) { var errors = PipelineErrors; - _logger.LogError($"{errors.Count} pipeline errors found in {MiddlwareName}. Setting error response status code"); + _logger.LogError($"{PipelineErrors.Count} pipeline errors found in {MiddlewareName}. Setting error response status code"); SetErrorResponse(context, errors); } @@ -53,7 +53,6 @@ namespace Ocelot.Responder.Middleware private void SetErrorResponse(HttpContext context, List errors) { var statusCode = _codeMapper.Map(errors); - _responder.SetErrorResponseOnContext(context, statusCode); } } diff --git a/test/Ocelot.UnitTests/Responder/AnyError.cs b/test/Ocelot.UnitTests/Responder/AnyError.cs new file mode 100644 index 00000000..a4b35df0 --- /dev/null +++ b/test/Ocelot.UnitTests/Responder/AnyError.cs @@ -0,0 +1,15 @@ +using Ocelot.Errors; + +namespace Ocelot.UnitTests.Responder +{ + class AnyError : Error + { + public AnyError() : base("blahh", OcelotErrorCode.UnknownError) + { + } + + public AnyError(OcelotErrorCode errorCode) : base("blah", errorCode) + { + } + } +} diff --git a/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs b/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs index 3b79715e..b0455e38 100644 --- a/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs +++ b/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs @@ -1,8 +1,7 @@ using System; using System.Collections.Generic; +using System.Net; using Ocelot.Errors; -using Ocelot.Middleware; -using Ocelot.Requester; using Ocelot.Responder; using Shouldly; using TestStack.BDDfy; @@ -21,47 +20,127 @@ namespace Ocelot.UnitTests.Responder _codeMapper = new ErrorsToHttpStatusCodeMapper(); } - [Fact] - public void should_return_timeout() + [Theory] + [InlineData(OcelotErrorCode.UnauthenticatedError)] + public void should_return_unauthorized(OcelotErrorCode errorCode) { - this.Given(x => x.GivenThereAreErrors(new List - { - new RequestTimedOutError(new Exception()) - })) - .When(x => x.WhenIGetErrorStatusCode()) - .Then(x => x.ThenTheResponseIsStatusCodeIs(503)) - .BDDfy(); + ShouldMapErrorToStatusCode(errorCode, HttpStatusCode.Unauthorized); + } + + [Theory] + [InlineData(OcelotErrorCode.CannotFindClaimError)] + [InlineData(OcelotErrorCode.ClaimValueNotAuthorisedError)] + [InlineData(OcelotErrorCode.ScopeNotAuthorisedError)] + [InlineData(OcelotErrorCode.UnauthorizedError)] + [InlineData(OcelotErrorCode.UserDoesNotHaveClaimError)] + public void should_return_forbidden(OcelotErrorCode errorCode) + { + ShouldMapErrorToStatusCode(errorCode, HttpStatusCode.Forbidden); + } + + [Theory] + [InlineData(OcelotErrorCode.RequestTimedOutError)] + public void should_return_service_unavailable(OcelotErrorCode errorCode) + { + ShouldMapErrorToStatusCode(errorCode, HttpStatusCode.ServiceUnavailable); + } + + + [Theory] + [InlineData(OcelotErrorCode.CannotAddDataError)] + [InlineData(OcelotErrorCode.CannotFindDataError)] + [InlineData(OcelotErrorCode.DownstreamHostNullOrEmptyError)] + [InlineData(OcelotErrorCode.DownstreamPathNullOrEmptyError)] + [InlineData(OcelotErrorCode.DownstreampathTemplateAlreadyUsedError)] + [InlineData(OcelotErrorCode.DownstreamPathTemplateContainsSchemeError)] + [InlineData(OcelotErrorCode.DownstreamSchemeNullOrEmptyError)] + [InlineData(OcelotErrorCode.InstructionNotForClaimsError)] + [InlineData(OcelotErrorCode.NoInstructionsError)] + [InlineData(OcelotErrorCode.ParsingConfigurationHeaderError)] + [InlineData(OcelotErrorCode.RateLimitOptionsError)] + [InlineData(OcelotErrorCode.ServicesAreEmptyError)] + [InlineData(OcelotErrorCode.ServicesAreNullError)] + [InlineData(OcelotErrorCode.UnableToCompleteRequestError)] + [InlineData(OcelotErrorCode.UnableToCreateAuthenticationHandlerError)] + [InlineData(OcelotErrorCode.UnableToFindDownstreamRouteError)] + [InlineData(OcelotErrorCode.UnableToFindLoadBalancerError)] + [InlineData(OcelotErrorCode.UnableToFindServiceDiscoveryProviderError)] + [InlineData(OcelotErrorCode.UnableToFindQoSProviderError)] + [InlineData(OcelotErrorCode.UnableToSetConfigInConsulError)] + [InlineData(OcelotErrorCode.UnknownError)] + [InlineData(OcelotErrorCode.UnmappableRequestError)] + [InlineData(OcelotErrorCode.UnsupportedAuthenticationProviderError)] + public void should_return_not_found(OcelotErrorCode errorCode) + { + ShouldMapErrorToStatusCode(errorCode, HttpStatusCode.NotFound); } [Fact] - public void should_create_unauthenticated_response_code() + public void AuthenticationErrorsHaveHighestPriority() { - this.Given(x => x.GivenThereAreErrors(new List - { - new UnauthenticatedError("no matter") - })) - .When(x => x.WhenIGetErrorStatusCode()) - .Then(x => x.ThenTheResponseIsStatusCodeIs(401)) - .BDDfy(); - } - - [Fact] - public void should_create_not_found_response_response_code() - { - this.Given(x => x.GivenThereAreErrors(new List - { - new AnyError() - })) - .When(x => x.WhenIGetErrorStatusCode()) - .Then(x => x.ThenTheResponseIsStatusCodeIs(404)) - .BDDfy(); - } - - class AnyError : Error - { - public AnyError() : base("blahh", OcelotErrorCode.UnknownError) + var errors = new List { + OcelotErrorCode.CannotAddDataError, + OcelotErrorCode.CannotFindClaimError, + OcelotErrorCode.UnauthenticatedError, + OcelotErrorCode.RequestTimedOutError, + }; + + ShouldMapErrorsToStatusCode(errors, HttpStatusCode.Unauthorized); + } + + [Fact] + public void AuthorisationErrorsHaveSecondHighestPriority() + { + var errors = new List + { + OcelotErrorCode.CannotAddDataError, + OcelotErrorCode.CannotFindClaimError, + OcelotErrorCode.RequestTimedOutError + }; + + ShouldMapErrorsToStatusCode(errors, HttpStatusCode.Forbidden); + } + + [Fact] + public void ServiceUnavailableErrorsHaveThirdHighestPriority() + { + var errors = new List + { + OcelotErrorCode.CannotAddDataError, + OcelotErrorCode.RequestTimedOutError + }; + + ShouldMapErrorsToStatusCode(errors, HttpStatusCode.ServiceUnavailable); + } + + [Fact] + public void check_we_have_considered_all_errors_in_these_tests() + { + // If this test fails then it's because the number of error codes has changed. + // You should make the appropriate changes to the test cases here to ensure + // they cover all the error codes, and then modify this assertion. + Enum.GetNames(typeof(OcelotErrorCode)).Length.ShouldBe(30, "Looks like the number of error codes has changed. Do you need to modify ErrorsToHttpStatusCodeMapper?"); + } + + private void ShouldMapErrorToStatusCode(OcelotErrorCode errorCode, HttpStatusCode expectedHttpStatusCode) + { + ShouldMapErrorsToStatusCode(new List { errorCode }, expectedHttpStatusCode); + } + + private void ShouldMapErrorsToStatusCode(List errorCodes, HttpStatusCode expectedHttpStatusCode) + { + var errors = new List(); + + foreach(var errorCode in errorCodes) + { + errors.Add(new AnyError(errorCode)); } + + this.Given(x => x.GivenThereAreErrors(errors)) + .When(x => x.WhenIGetErrorStatusCode()) + .Then(x => x.ThenTheResponseIsStatusCodeIs(expectedHttpStatusCode)) + .BDDfy(); } private void GivenThereAreErrors(List errors) @@ -77,6 +156,11 @@ namespace Ocelot.UnitTests.Responder private void ThenTheResponseIsStatusCodeIs(int expectedCode) { _result.ShouldBe(expectedCode); - } + } + + private void ThenTheResponseIsStatusCodeIs(HttpStatusCode expectedCode) + { + _result.ShouldBe((int)expectedCode); + } } } diff --git a/test/Ocelot.UnitTests/Responder/ResponderMiddlewareTestsV2.cs b/test/Ocelot.UnitTests/Responder/ResponderMiddlewareTestsV2.cs new file mode 100644 index 00000000..28c3e9fa --- /dev/null +++ b/test/Ocelot.UnitTests/Responder/ResponderMiddlewareTestsV2.cs @@ -0,0 +1,140 @@ +using System.Collections.Generic; +using System.Net.Http; +using Microsoft.AspNetCore.Http; +using Moq; +using Ocelot.Infrastructure.RequestData; +using Ocelot.Errors; +using Ocelot.Logging; +using Ocelot.Responder; +using Ocelot.Responder.Middleware; +using Ocelot.Responses; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.UnitTests.Responder +{ + public class ResponderMiddlewareTestsV2 + { + private readonly Mock _responder; + private readonly Mock _scopedRepository; + private readonly Mock _codeMapper; + private readonly Mock _next; + private readonly Mock _loggerFactory; + private readonly Mock _logger; + private readonly Mock _httpContext; + private ResponderMiddleware _middleware; + private OkResponse _response; + private int _mappedStatusCode; + private List _pipelineErrors; + + public ResponderMiddlewareTestsV2() + { + _responder = new Mock(); + _codeMapper = new Mock(); + _next = new Mock(); + _logger = new Mock(); + _scopedRepository = new Mock(); + _loggerFactory = new Mock(); + _httpContext = new Mock(); + + _loggerFactory + .Setup(lf => lf.CreateLogger()) + .Returns(_logger.Object); + + _middleware = new ResponderMiddleware(_next.Object, _responder.Object, _loggerFactory.Object, _scopedRepository.Object, _codeMapper.Object); + + GivenTheHttpResponseMessageIs(new HttpResponseMessage()); + } + + [Fact] + public void NoPipelineErrors() + { + this.Given(x => x.GivenThereAreNoPipelineErrors()) + .When(x => x.WhenICallTheMiddleware()) + .Then(_ => ThenTheNextMiddlewareIsCalled()) + .And(x => x.ThenThereAreNoErrorsOnTheHttpContext()) + .BDDfy(); + } + + [Fact] + public void PipelineErrors() + { + this.Given(_ => GivenThereArePipelineErrors()) + .And(_ => GivenTheErrorsCanBeMappedToAStatusCode()) + .When(_ => WhenICallTheMiddleware()) + .Then(_ => ThenTheNextMiddlewareIsCalled()) + .And(x => x.ThenTheErrorsAreLogged()) + .And(_ => ThenTheErrorsAreMappedToAnHttpStatus()) + .And(_ => ThenAnErrorResponseIsSetOnTheHttpContext()) + .BDDfy(); + } + + private void GivenTheHttpResponseMessageIs(HttpResponseMessage response) + { + _response = new OkResponse(response); + _scopedRepository + .Setup(x => x.Get(It.IsAny())) + .Returns(_response); + } + + private void GivenThereAreNoPipelineErrors() + { + GivenThereArePipelineErrors(new List()); + } + + private void GivenThereArePipelineErrors() + { + GivenThereArePipelineErrors(new List() { new AnyError() }); + } + + private void GivenThereArePipelineErrors(List pipelineErrors) + { + _pipelineErrors = pipelineErrors; + + _scopedRepository + .Setup(x => x.Get("OcelotMiddlewareError")) + .Returns(new OkResponse(_pipelineErrors.Count != 0)); + + _scopedRepository + .Setup(sr => sr.Get>("OcelotMiddlewareErrors")) + .Returns(new OkResponse>(_pipelineErrors)); + } + + private void GivenTheErrorsCanBeMappedToAStatusCode() + { + _mappedStatusCode = 500; //TODO: autofixture + _codeMapper.Setup(cm => cm.Map(It.IsAny>())) + .Returns(_mappedStatusCode); + } + + private void WhenICallTheMiddleware() + { + _middleware.Invoke(_httpContext.Object).GetAwaiter().GetResult(); + } + + private void ThenTheNextMiddlewareIsCalled() + { + _next.Verify(n => n(_httpContext.Object), Times.Once); + } + + private void ThenTheErrorsAreMappedToAnHttpStatus() + { + _codeMapper.Verify(cm => cm.Map(_pipelineErrors), Times.Once); + } + + private void ThenTheErrorsAreLogged() + { + _logger.Verify(l => l.LogError($"{_pipelineErrors.Count} pipeline errors found in ResponderMiddleware. Setting error response status code"), Times.Once); + } + + private void ThenThereAreNoErrorsOnTheHttpContext() + { + _responder.Verify(r => r.SetErrorResponseOnContext(It.IsAny(), It.IsAny()), Times.Never); + } + + private void ThenAnErrorResponseIsSetOnTheHttpContext() + { + _responder.Verify(r => r.SetErrorResponseOnContext(_httpContext.Object, _mappedStatusCode), Times.Once); + } + } +} From 8042bbab2c15ddd163ff42989d416b8f08de3bd6 Mon Sep 17 00:00:00 2001 From: Philip Wood Date: Tue, 18 Jul 2017 09:28:32 +0100 Subject: [PATCH 28/35] Moved common middleare test setup into a base class --- src/Ocelot/Responder/HttpContextResponder.cs | 16 +- .../AuthenticationMiddlewareTests.cs | 117 ++++++--------- .../AuthorisationMiddlewareTests.cs | 109 +++++--------- .../Cache/OutputCacheMiddlewareTests.cs | 118 ++++++--------- .../Claims/ClaimsBuilderMiddlewareTests.cs | 111 +++++--------- .../DownstreamRouteFinderMiddlewareTests.cs | 84 ++++------- .../DownstreamUrlCreatorMiddlewareTests.cs | 97 +++++------- .../Errors/ExceptionHandlerMiddlewareTests.cs | 57 ++++--- ...ttpRequestHeadersBuilderMiddlewareTests.cs | 109 +++++--------- test/Ocelot.UnitTests/HostedMiddlewareTest.cs | 58 +++++++ .../LoadBalancerMiddlewareTests.cs | 97 +++++------- test/Ocelot.UnitTests/Ocelot.UnitTests.csproj | 4 + .../QueryStringBuilderMiddlewareTests.cs | 93 +++++------- .../ClientRateLimitMiddlewareTests.cs | 64 ++++---- .../HttpRequestBuilderMiddlewareTests.cs | 108 ++++++------- .../RequestId/RequestIdMiddlewareTests.cs | 116 ++++++-------- .../Requester/HttpRequesterMiddlewareTests.cs | 103 +++++-------- .../Responder/HttpContextResponderTests.cs | 98 ++++++++++++ .../Responder/ResponderMiddlewareTests.cs | 142 +++++++++++------- .../Responder/ResponderMiddlewareTestsV2.cs | 2 +- 20 files changed, 787 insertions(+), 916 deletions(-) create mode 100644 test/Ocelot.UnitTests/HostedMiddlewareTest.cs create mode 100644 test/Ocelot.UnitTests/Responder/HttpContextResponderTests.cs diff --git a/src/Ocelot/Responder/HttpContextResponder.cs b/src/Ocelot/Responder/HttpContextResponder.cs index 20313e8f..571113d6 100644 --- a/src/Ocelot/Responder/HttpContextResponder.cs +++ b/src/Ocelot/Responder/HttpContextResponder.cs @@ -62,14 +62,6 @@ namespace Ocelot.Responder } } - private static void AddHeaderIfDoesntExist(HttpContext context, KeyValuePair> httpResponseHeader) - { - if (!context.Response.Headers.ContainsKey(httpResponseHeader.Key)) - { - context.Response.Headers.Add(httpResponseHeader.Key, new StringValues(httpResponseHeader.Value.ToArray())); - } - } - public void SetErrorResponseOnContext(HttpContext context, int statusCode) { context.Response.OnStarting(x => @@ -78,5 +70,13 @@ namespace Ocelot.Responder return Task.CompletedTask; }, context); } + + private static void AddHeaderIfDoesntExist(HttpContext context, KeyValuePair> httpResponseHeader) + { + if (!context.Response.Headers.ContainsKey(httpResponseHeader.Key)) + { + context.Response.Headers.Add(httpResponseHeader.Key, new StringValues(httpResponseHeader.Value.ToArray())); + } + } } } \ No newline at end of file diff --git a/test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs b/test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs index be709dff..be52e909 100644 --- a/test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs @@ -1,87 +1,70 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Net.Http; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Moq; -using Ocelot.Authentication.Handler; -using Ocelot.Authentication.Handler.Factory; -using Ocelot.Authentication.Middleware; -using Ocelot.Cache.Middleware; -using Ocelot.Configuration; -using Ocelot.Configuration.Builder; -using Ocelot.DownstreamRouteFinder; -using Ocelot.DownstreamRouteFinder.UrlMatcher; -using Ocelot.Infrastructure.RequestData; -using Ocelot.Logging; -using Ocelot.Responses; -using Shouldly; -using TestStack.BDDfy; -using Xunit; - -namespace Ocelot.UnitTests.Authentication +namespace Ocelot.UnitTests.Authentication { - public class AuthenticationMiddlewareTests : IDisposable + using System.Collections.Generic; + using Microsoft.AspNetCore.Builder; + using Microsoft.AspNetCore.Hosting; + using Microsoft.AspNetCore.Http; + using Microsoft.Extensions.DependencyInjection; + using Moq; + using Ocelot.Authentication.Handler.Factory; + using Ocelot.Authentication.Middleware; + using Ocelot.Configuration.Builder; + using Ocelot.DownstreamRouteFinder; + using Ocelot.DownstreamRouteFinder.UrlMatcher; + using Ocelot.Infrastructure.RequestData; + using Ocelot.Logging; + using Ocelot.Responses; + using Shouldly; + using TestStack.BDDfy; + using Xunit; + + public class AuthenticationMiddlewareTests : ServerHostedMiddlewareTest { private readonly Mock _scopedRepository; private readonly Mock _authFactory; - private readonly string _url; - private readonly TestServer _server; - private readonly HttpClient _client; - private HttpResponseMessage _result; private OkResponse _downstreamRoute; public AuthenticationMiddlewareTests() { - _url = "http://localhost:51879"; _scopedRepository = new Mock(); _authFactory = new Mock(); - var builder = new WebHostBuilder() - .ConfigureServices(x => - { - x.AddSingleton(); - x.AddLogging(); - x.AddSingleton(_authFactory.Object); - x.AddSingleton(_scopedRepository.Object); - }) - .UseUrls(_url) - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseUrls(_url) - .Configure(app => - { - app.UseAuthenticationMiddleware(); - app.Run(async x => - { - await x.Response.WriteAsync("The user is authenticated"); - }); - }); - - _server = new TestServer(builder); - _client = _server.CreateClient(); + GivenTheTestServerIsConfigured(); } [Fact] public void should_call_next_middleware_if_route_is_not_authenticated() { - this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List(), new ReRouteBuilder() - .WithUpstreamHttpMethod(new List { "Get" }) - .Build()))) + this.Given(x => x.GivenTheDownStreamRouteIs( + new DownstreamRoute( + new List(), + new ReRouteBuilder().WithUpstreamHttpMethod(new List { "Get" }).Build()))) .When(x => x.WhenICallTheMiddleware()) .Then(x => x.ThenTheUserIsAuthenticated()) .BDDfy(); } + protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services) + { + services.AddSingleton(); + services.AddLogging(); + services.AddSingleton(_authFactory.Object); + services.AddSingleton(_scopedRepository.Object); + } + + protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) + { + app.UseAuthenticationMiddleware(); + + app.Run(async x => + { + await x.Response.WriteAsync("The user is authenticated"); + }); + } + private void ThenTheUserIsAuthenticated() { - var content = _result.Content.ReadAsStringAsync().Result; + var content = ResponseMessage.Content.ReadAsStringAsync().Result; content.ShouldBe("The user is authenticated"); } @@ -92,17 +75,5 @@ namespace Ocelot.UnitTests.Authentication .Setup(x => x.Get(It.IsAny())) .Returns(_downstreamRoute); } - - private void WhenICallTheMiddleware() - { - _result = _client.GetAsync(_url).Result; - } - - - public void Dispose() - { - _client.Dispose(); - _server.Dispose(); - } } } diff --git a/test/Ocelot.UnitTests/Authorization/AuthorisationMiddlewareTests.cs b/test/Ocelot.UnitTests/Authorization/AuthorisationMiddlewareTests.cs index 9bf15b42..508db7ce 100644 --- a/test/Ocelot.UnitTests/Authorization/AuthorisationMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Authorization/AuthorisationMiddlewareTests.cs @@ -1,66 +1,35 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Net.Http; -using System.Security.Claims; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Moq; -using Ocelot.Authorisation; -using Ocelot.Configuration.Builder; -using Ocelot.DownstreamRouteFinder; -using Ocelot.DownstreamRouteFinder.UrlMatcher; -using Ocelot.Infrastructure.RequestData; -using Ocelot.Logging; -using Ocelot.Responses; -using TestStack.BDDfy; -using Xunit; - -namespace Ocelot.UnitTests.Authorization +namespace Ocelot.UnitTests.Authorization { - using Authorisation.Middleware; + using System.Collections.Generic; + using System.Security.Claims; + using Microsoft.AspNetCore.Builder; + using Microsoft.Extensions.DependencyInjection; + using Moq; + using Ocelot.Authorisation; + using Ocelot.Authorisation.Middleware; + using Ocelot.Configuration.Builder; + using Ocelot.DownstreamRouteFinder; + using Ocelot.DownstreamRouteFinder.UrlMatcher; + using Ocelot.Infrastructure.RequestData; + using Ocelot.Logging; + using Ocelot.Responses; + using TestStack.BDDfy; + using Xunit; - public class AuthorisationMiddlewareTests : IDisposable + public class AuthorisationMiddlewareTests : ServerHostedMiddlewareTest { private readonly Mock _scopedRepository; private readonly Mock _authService; private readonly Mock _authScopesService; - private readonly string _url; - private readonly TestServer _server; - private readonly HttpClient _client; - private HttpResponseMessage _result; private OkResponse _downstreamRoute; public AuthorisationMiddlewareTests() { - _url = "http://localhost:51879"; _scopedRepository = new Mock(); _authService = new Mock(); _authScopesService = new Mock(); - var builder = new WebHostBuilder() - .ConfigureServices(x => - { - x.AddSingleton(); - x.AddLogging(); - x.AddSingleton(_authService.Object); - x.AddSingleton(_authScopesService.Object); - x.AddSingleton(_scopedRepository.Object); - }) - .UseUrls(_url) - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseUrls(_url) - .Configure(app => - { - app.UseAuthorisationMiddleware(); - }); - - _server = new TestServer(builder); - _client = _server.CreateClient(); + GivenTheTestServerIsConfigured(); } [Fact] @@ -77,6 +46,28 @@ namespace Ocelot.UnitTests.Authorization .BDDfy(); } + protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services) + { + services.AddSingleton(); + services.AddLogging(); + services.AddSingleton(_authService.Object); + services.AddSingleton(_authScopesService.Object); + services.AddSingleton(_scopedRepository.Object); + } + + protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) + { + app.UseAuthorisationMiddleware(); + } + + private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) + { + _downstreamRoute = new OkResponse(downstreamRoute); + _scopedRepository + .Setup(x => x.Get(It.IsAny())) + .Returns(_downstreamRoute); + } + private void GivenTheAuthServiceReturns(Response expected) { _authService @@ -90,25 +81,5 @@ namespace Ocelot.UnitTests.Authorization .Verify(x => x.Authorise(It.IsAny(), It.IsAny>()), Times.Once); } - - private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) - { - _downstreamRoute = new OkResponse(downstreamRoute); - _scopedRepository - .Setup(x => x.Get(It.IsAny())) - .Returns(_downstreamRoute); - } - - private void WhenICallTheMiddleware() - { - _result = _client.GetAsync(_url).Result; - } - - - public void Dispose() - { - _client.Dispose(); - _server.Dispose(); - } } } diff --git a/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs b/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs index ff74fba0..faade351 100644 --- a/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs @@ -1,34 +1,27 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Net.Http; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Moq; -using Ocelot.Cache; -using Ocelot.Cache.Middleware; -using Ocelot.Configuration; -using Ocelot.Configuration.Builder; -using Ocelot.DownstreamRouteFinder; -using Ocelot.DownstreamRouteFinder.UrlMatcher; -using Ocelot.Infrastructure.RequestData; -using Ocelot.Logging; -using Ocelot.Responses; -using TestStack.BDDfy; -using Xunit; - -namespace Ocelot.UnitTests.Cache +namespace Ocelot.UnitTests.Cache { - public class OutputCacheMiddlewareTests + using System; + using System.Collections.Generic; + using System.Net.Http; + using Microsoft.AspNetCore.Builder; + using Microsoft.Extensions.DependencyInjection; + using Moq; + using Ocelot.Cache; + using Ocelot.Cache.Middleware; + using Ocelot.Configuration; + using Ocelot.Configuration.Builder; + using Ocelot.DownstreamRouteFinder; + using Ocelot.DownstreamRouteFinder.UrlMatcher; + using Ocelot.Infrastructure.RequestData; + using Ocelot.Logging; + using Ocelot.Responses; + using TestStack.BDDfy; + using Xunit; + + public class OutputCacheMiddlewareTests : ServerHostedMiddlewareTest { private readonly Mock> _cacheManager; private readonly Mock _scopedRepo; - private readonly string _url; - private readonly TestServer _server; - private readonly HttpClient _client; - private HttpResponseMessage _result; private HttpResponseMessage _response; public OutputCacheMiddlewareTests() @@ -36,32 +29,11 @@ namespace Ocelot.UnitTests.Cache _cacheManager = new Mock>(); _scopedRepo = new Mock(); - _url = "http://localhost:51879"; - var builder = new WebHostBuilder() - .ConfigureServices(x => - { - x.AddSingleton(); - x.AddLogging(); - x.AddSingleton(_cacheManager.Object); - x.AddSingleton(_scopedRepo.Object); - x.AddSingleton(); - }) - .UseUrls(_url) - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseUrls(_url) - .Configure(app => - { - app.UseOutputCacheMiddleware(); - }); - _scopedRepo .Setup(sr => sr.Get("DownstreamRequest")) .Returns(new OkResponse(new HttpRequestMessage(HttpMethod.Get, "https://some.url/blah?abcd=123"))); - _server = new TestServer(builder); - _client = _server.CreateClient(); + GivenTheTestServerIsConfigured(); } [Fact] @@ -87,6 +59,34 @@ namespace Ocelot.UnitTests.Cache .BDDfy(); } + protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services) + { + services.AddSingleton(); + services.AddLogging(); + services.AddSingleton(_cacheManager.Object); + services.AddSingleton(_scopedRepo.Object); + services.AddSingleton(); + } + + protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) + { + app.UseOutputCacheMiddleware(); + } + + private void GivenThereIsACachedResponse(HttpResponseMessage response) + { + _response = response; + _cacheManager + .Setup(x => x.Get(It.IsAny(), It.IsAny())) + .Returns(_response); + } + + private void GivenResponseIsNotCached() + { + _scopedRepo + .Setup(x => x.Get("HttpResponseMessage")) + .Returns(new OkResponse(new HttpResponseMessage())); + } private void GivenTheDownstreamRouteIs() { @@ -128,25 +128,5 @@ namespace Ocelot.UnitTests.Cache _cacheManager .Verify(x => x.Add(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); } - - private void GivenResponseIsNotCached() - { - _scopedRepo - .Setup(x => x.Get("HttpResponseMessage")) - .Returns(new OkResponse(new HttpResponseMessage())); - } - - private void GivenThereIsACachedResponse(HttpResponseMessage response) - { - _response = response; - _cacheManager - .Setup(x => x.Get(It.IsAny(), It.IsAny())) - .Returns(_response); - } - - private void WhenICallTheMiddleware() - { - _result = _client.GetAsync(_url).Result; - } } } diff --git a/test/Ocelot.UnitTests/Claims/ClaimsBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/Claims/ClaimsBuilderMiddlewareTests.cs index d17d7978..8ac75ef4 100644 --- a/test/Ocelot.UnitTests/Claims/ClaimsBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Claims/ClaimsBuilderMiddlewareTests.cs @@ -1,65 +1,34 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Net.Http; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Moq; -using Ocelot.Cache.Middleware; -using Ocelot.Claims; -using Ocelot.Claims.Middleware; -using Ocelot.Configuration; -using Ocelot.Configuration.Builder; -using Ocelot.DownstreamRouteFinder; -using Ocelot.DownstreamRouteFinder.UrlMatcher; -using Ocelot.Infrastructure.RequestData; -using Ocelot.Logging; -using Ocelot.Responses; -using TestStack.BDDfy; -using Xunit; - -namespace Ocelot.UnitTests.Claims +namespace Ocelot.UnitTests.Claims { - public class ClaimsBuilderMiddlewareTests : IDisposable + using System.Collections.Generic; + using Microsoft.AspNetCore.Builder; + using Microsoft.AspNetCore.Http; + using Microsoft.Extensions.DependencyInjection; + using Moq; + using Ocelot.Claims; + using Ocelot.Claims.Middleware; + using Ocelot.Configuration; + using Ocelot.Configuration.Builder; + using Ocelot.DownstreamRouteFinder; + using Ocelot.DownstreamRouteFinder.UrlMatcher; + using Ocelot.Infrastructure.RequestData; + using Ocelot.Logging; + using Ocelot.Responses; + using TestStack.BDDfy; + using Xunit; + + public class ClaimsBuilderMiddlewareTests : ServerHostedMiddlewareTest { private readonly Mock _scopedRepository; private readonly Mock _addHeaders; - private readonly string _url; - private readonly TestServer _server; - private readonly HttpClient _client; private Response _downstreamRoute; - private HttpResponseMessage _result; public ClaimsBuilderMiddlewareTests() { - _url = "http://localhost:51879"; _scopedRepository = new Mock(); _addHeaders = new Mock(); - var builder = new WebHostBuilder() - .ConfigureServices(x => - { - x.AddSingleton(); - - x.AddLogging(); - x.AddSingleton(_addHeaders.Object); - x.AddSingleton(_scopedRepository.Object); - }) - .UseUrls(_url) - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseUrls(_url) - .Configure(app => - { - app.UseClaimsBuilderMiddleware(); - }); - - _server = new TestServer(builder); - _client = _server.CreateClient(); + GivenTheTestServerIsConfigured(); } [Fact] @@ -82,6 +51,27 @@ namespace Ocelot.UnitTests.Claims .BDDfy(); } + protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services) + { + services.AddSingleton(); + services.AddLogging(); + services.AddSingleton(_addHeaders.Object); + services.AddSingleton(_scopedRepository.Object); + } + + protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) + { + app.UseClaimsBuilderMiddleware(); + } + + private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) + { + _downstreamRoute = new OkResponse(downstreamRoute); + _scopedRepository + .Setup(x => x.Get(It.IsAny())) + .Returns(_downstreamRoute); + } + private void GivenTheAddClaimsToRequestReturns() { _addHeaders @@ -96,24 +86,5 @@ namespace Ocelot.UnitTests.Claims .Verify(x => x.SetClaimsOnContext(It.IsAny>(), It.IsAny()), Times.Once); } - - private void WhenICallTheMiddleware() - { - _result = _client.GetAsync(_url).Result; - } - - private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) - { - _downstreamRoute = new OkResponse(downstreamRoute); - _scopedRepository - .Setup(x => x.Get(It.IsAny())) - .Returns(_downstreamRoute); - } - - public void Dispose() - { - _client.Dispose(); - _server.Dispose(); - } } } diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs index 0b3aa149..367b9559 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs @@ -1,61 +1,32 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Net.Http; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Moq; -using Ocelot.Configuration.Builder; -using Ocelot.DownstreamRouteFinder; -using Ocelot.DownstreamRouteFinder.Finder; -using Ocelot.DownstreamRouteFinder.Middleware; -using Ocelot.DownstreamRouteFinder.UrlMatcher; -using Ocelot.Infrastructure.RequestData; -using Ocelot.Logging; -using Ocelot.Responses; -using TestStack.BDDfy; -using Xunit; - -namespace Ocelot.UnitTests.DownstreamRouteFinder +namespace Ocelot.UnitTests.DownstreamRouteFinder { - public class DownstreamRouteFinderMiddlewareTests : IDisposable + using System.Collections.Generic; + using Microsoft.AspNetCore.Builder; + using Microsoft.Extensions.DependencyInjection; + using Moq; + using Ocelot.Configuration.Builder; + using Ocelot.DownstreamRouteFinder; + using Ocelot.DownstreamRouteFinder.Finder; + using Ocelot.DownstreamRouteFinder.Middleware; + using Ocelot.DownstreamRouteFinder.UrlMatcher; + using Ocelot.Infrastructure.RequestData; + using Ocelot.Logging; + using Ocelot.Responses; + using TestStack.BDDfy; + using Xunit; + + public class DownstreamRouteFinderMiddlewareTests : ServerHostedMiddlewareTest { private readonly Mock _downstreamRouteFinder; private readonly Mock _scopedRepository; - private readonly string _url; - private readonly TestServer _server; - private readonly HttpClient _client; private Response _downstreamRoute; - private HttpResponseMessage _result; public DownstreamRouteFinderMiddlewareTests() { - _url = "http://localhost:51879"; _downstreamRouteFinder = new Mock(); _scopedRepository = new Mock(); - var builder = new WebHostBuilder() - .ConfigureServices(x => - { - x.AddSingleton(); - x.AddLogging(); - x.AddSingleton(_downstreamRouteFinder.Object); - x.AddSingleton(_scopedRepository.Object); - }) - .UseUrls(_url) - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseUrls(_url) - .Configure(app => - { - app.UseDownstreamRouteFinderMiddleware(); - }); - - _server = new TestServer(builder); - _client = _server.CreateClient(); + GivenTheTestServerIsConfigured(); } [Fact] @@ -73,16 +44,17 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .BDDfy(); } - - private void ThenTheScopedDataRepositoryIsCalledCorrectly() + protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services) { - _scopedRepository - .Verify(x => x.Add("DownstreamRoute", _downstreamRoute.Data), Times.Once()); + services.AddSingleton(); + services.AddLogging(); + services.AddSingleton(_downstreamRouteFinder.Object); + services.AddSingleton(_scopedRepository.Object); } - private void WhenICallTheMiddleware() + protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) { - _result = _client.GetAsync(_url).Result; + app.UseDownstreamRouteFinderMiddleware(); } private void GivenTheDownStreamRouteFinderReturns(DownstreamRoute downstreamRoute) @@ -93,10 +65,10 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder .ReturnsAsync(_downstreamRoute); } - public void Dispose() + private void ThenTheScopedDataRepositoryIsCalledCorrectly() { - _client.Dispose(); - _server.Dispose(); + _scopedRepository + .Verify(x => x.Add("DownstreamRoute", _downstreamRoute.Data), Times.Once()); } } } diff --git a/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs b/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs index ae322150..a538a9f8 100644 --- a/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs @@ -1,64 +1,39 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Net.Http; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; -using Moq; -using Ocelot.Configuration.Builder; -using Ocelot.DownstreamRouteFinder; -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; -using Shouldly; - -namespace Ocelot.UnitTests.DownstreamUrlCreator +namespace Ocelot.UnitTests.DownstreamUrlCreator { - public class DownstreamUrlCreatorMiddlewareTests : IDisposable + using System; + using System.Collections.Generic; + using System.Net.Http; + using Microsoft.AspNetCore.Builder; + using Microsoft.Extensions.DependencyInjection; + using Moq; + using Ocelot.Configuration.Builder; + using Ocelot.DownstreamRouteFinder; + 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; + using Shouldly; + + public class DownstreamUrlCreatorMiddlewareTests : ServerHostedMiddlewareTest { 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 OkResponse _downstreamPath; private HttpRequestMessage _downstreamRequest; - private HttpResponseMessage _result; public DownstreamUrlCreatorMiddlewareTests() { - _url = "http://localhost:51879"; _downstreamUrlTemplateVariableReplacer = new Mock(); _scopedRepository = new Mock(); _urlBuilder = new Mock(); - var builder = new WebHostBuilder() - .ConfigureServices(x => - { - x.AddSingleton(); - x.AddLogging(); - x.AddSingleton(_downstreamUrlTemplateVariableReplacer.Object); - x.AddSingleton(_scopedRepository.Object); - x.AddSingleton(_urlBuilder.Object); - }) - .UseUrls(_url) - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseUrls(_url) - .Configure(app => - { - app.UseDownstreamUrlCreatorMiddleware(); - }); _downstreamRequest = new HttpRequestMessage(HttpMethod.Get, "https://my.url/abc/?q=123"); @@ -66,8 +41,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator .Setup(sr => sr.Get("DownstreamRequest")) .Returns(new OkResponse(_downstreamRequest)); - _server = new TestServer(builder); - _client = _server.CreateClient(); + GivenTheTestServerIsConfigured(); } [Fact] @@ -88,6 +62,20 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator .BDDfy(); } + protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services) + { + services.AddSingleton(); + services.AddLogging(); + services.AddSingleton(_downstreamUrlTemplateVariableReplacer.Object); + services.AddSingleton(_scopedRepository.Object); + services.AddSingleton(_urlBuilder.Object); + } + + protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) + { + app.UseDownstreamUrlCreatorMiddleware(); + } + private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) { _downstreamRoute = new OkResponse(downstreamRoute); @@ -109,20 +97,9 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator .Returns(_downstreamPath); } - private void WhenICallTheMiddleware() - { - _result = _client.GetAsync(_url).Result; - } - private void ThenTheDownstreamRequestUriIs(string expectedUri) { _downstreamRequest.RequestUri.OriginalString.ShouldBe(expectedUri); } - - public void Dispose() - { - _client.Dispose(); - _server.Dispose(); - } } } diff --git a/test/Ocelot.UnitTests/Errors/ExceptionHandlerMiddlewareTests.cs b/test/Ocelot.UnitTests/Errors/ExceptionHandlerMiddlewareTests.cs index 41beffdc..8584f106 100644 --- a/test/Ocelot.UnitTests/Errors/ExceptionHandlerMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Errors/ExceptionHandlerMiddlewareTests.cs @@ -7,14 +7,9 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Moq; -using Ocelot.DownstreamRouteFinder; -using Ocelot.DownstreamUrlCreator; -using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer; using Ocelot.Errors.Middleware; using Ocelot.Infrastructure.RequestData; using Ocelot.Logging; -using Ocelot.Responses; -using Ocelot.Values; using Shouldly; using TestStack.BDDfy; using Xunit; @@ -53,6 +48,33 @@ namespace Ocelot.UnitTests.Errors .BDDfy(); } + private void GivenAnError() + { + var builder = new WebHostBuilder() + .ConfigureServices(x => + { + x.AddSingleton(); + x.AddLogging(); + x.AddSingleton(_scopedRepository.Object); + }) + .UseUrls(_url) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseUrls(_url) + .Configure(app => + { + app.UseExceptionHandlerMiddleware(); + app.Use(async (context, next) => + { + throw new Exception("BOOM"); + }); + }); + + _server = new TestServer(builder); + _client = _server.CreateClient(); + } + private void ThenTheResponseIsOk() { _result.StatusCode.ShouldBe(HttpStatusCode.OK); @@ -95,31 +117,6 @@ namespace Ocelot.UnitTests.Errors _client = _server.CreateClient(); } - private void GivenAnError() - { - var builder = new WebHostBuilder() - .ConfigureServices(x => - { - x.AddSingleton(); - x.AddLogging(); - x.AddSingleton(_scopedRepository.Object); - }) - .UseUrls(_url) - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseUrls(_url) - .Configure(app => - { - app.UseExceptionHandlerMiddleware(); - app.Use(async (context, next) => - { - throw new Exception("BOOM"); - }); - }); - _server = new TestServer(builder); - _client = _server.CreateClient(); - } } } \ No newline at end of file diff --git a/test/Ocelot.UnitTests/Headers/HttpRequestHeadersBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/Headers/HttpRequestHeadersBuilderMiddlewareTests.cs index 395d7862..26a4e541 100644 --- a/test/Ocelot.UnitTests/Headers/HttpRequestHeadersBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Headers/HttpRequestHeadersBuilderMiddlewareTests.cs @@ -1,69 +1,40 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Net.Http; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; -using Moq; -using Ocelot.Configuration; -using Ocelot.Configuration.Builder; -using Ocelot.DownstreamRouteFinder; -using Ocelot.DownstreamRouteFinder.UrlMatcher; -using Ocelot.Headers; -using Ocelot.Headers.Middleware; -using Ocelot.Infrastructure.RequestData; -using Ocelot.Logging; -using Ocelot.Responses; -using TestStack.BDDfy; -using Xunit; - -namespace Ocelot.UnitTests.Headers +namespace Ocelot.UnitTests.Headers { - public class HttpRequestHeadersBuilderMiddlewareTests : IDisposable + using System.Collections.Generic; + using System.Net.Http; + using Microsoft.AspNetCore.Builder; + using Microsoft.Extensions.DependencyInjection; + using Moq; + using Ocelot.Configuration; + using Ocelot.Configuration.Builder; + using Ocelot.DownstreamRouteFinder; + using Ocelot.DownstreamRouteFinder.UrlMatcher; + using Ocelot.Headers; + using Ocelot.Headers.Middleware; + using Ocelot.Infrastructure.RequestData; + using Ocelot.Logging; + using Ocelot.Responses; + using TestStack.BDDfy; + using Xunit; + + public class HttpRequestHeadersBuilderMiddlewareTests : ServerHostedMiddlewareTest { private readonly Mock _scopedRepository; private readonly Mock _addHeaders; private readonly HttpRequestMessage _downstreamRequest; - private readonly string _url; - private readonly TestServer _server; - private readonly HttpClient _client; private Response _downstreamRoute; - private HttpResponseMessage _result; public HttpRequestHeadersBuilderMiddlewareTests() { - _url = "http://localhost:51879"; _scopedRepository = new Mock(); _addHeaders = new Mock(); - - var builder = new WebHostBuilder() - .ConfigureServices(x => - { - x.AddSingleton(); - x.AddLogging(); - x.AddSingleton(_addHeaders.Object); - x.AddSingleton(_scopedRepository.Object); - }) - .UseUrls(_url) - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseUrls(_url) - .Configure(app => - { - app.UseHttpRequestHeadersBuilderMiddleware(); - }); - _downstreamRequest = new HttpRequestMessage(); - _scopedRepository .Setup(sr => sr.Get("DownstreamRequest")) .Returns(new OkResponse(_downstreamRequest)); - _server = new TestServer(builder); - _client = _server.CreateClient(); + GivenTheTestServerIsConfigured(); } [Fact] @@ -86,6 +57,27 @@ namespace Ocelot.UnitTests.Headers .BDDfy(); } + protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services) + { + services.AddSingleton(); + services.AddLogging(); + services.AddSingleton(_addHeaders.Object); + services.AddSingleton(_scopedRepository.Object); + } + + protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) + { + app.UseHttpRequestHeadersBuilderMiddleware(); + } + + private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) + { + _downstreamRoute = new OkResponse(downstreamRoute); + _scopedRepository + .Setup(x => x.Get(It.IsAny())) + .Returns(_downstreamRoute); + } + private void GivenTheAddHeadersToDownstreamRequestReturnsOk() { _addHeaders @@ -104,24 +96,5 @@ namespace Ocelot.UnitTests.Headers It.IsAny>(), _downstreamRequest), Times.Once); } - - private void WhenICallTheMiddleware() - { - _result = _client.GetAsync(_url).Result; - } - - private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) - { - _downstreamRoute = new OkResponse(downstreamRoute); - _scopedRepository - .Setup(x => x.Get(It.IsAny())) - .Returns(_downstreamRoute); - } - - public void Dispose() - { - _client.Dispose(); - _server.Dispose(); - } } } diff --git a/test/Ocelot.UnitTests/HostedMiddlewareTest.cs b/test/Ocelot.UnitTests/HostedMiddlewareTest.cs new file mode 100644 index 00000000..8409588d --- /dev/null +++ b/test/Ocelot.UnitTests/HostedMiddlewareTest.cs @@ -0,0 +1,58 @@ +namespace Ocelot.UnitTests +{ + using System; + using System.IO; + using System.Net.Http; + using Microsoft.AspNetCore.TestHost; + using Microsoft.AspNetCore.Hosting; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.AspNetCore.Builder; + + public abstract class ServerHostedMiddlewareTest : IDisposable + { + protected TestServer Server { get; private set; } + protected HttpClient Client { get; private set; } + protected string Url { get; private set; } + protected HttpResponseMessage ResponseMessage { get; private set; } + + public ServerHostedMiddlewareTest() + { + Url = "http://localhost:51879"; + } + + protected virtual void GivenTheTestServerIsConfigured() + { + var builder = new WebHostBuilder() + .ConfigureServices(x => GivenTheTestServerServicesAreConfigured(x)) + .UseUrls(Url) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .Configure(app => GivenTheTestServerPipelineIsConfigured(app)); + + Server = new TestServer(builder); + Client = Server.CreateClient(); + } + + protected virtual void GivenTheTestServerServicesAreConfigured(IServiceCollection services) + { + // override this in your test fixture to set up service dependencies + } + + protected virtual void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) + { + // override this in your test fixture to set up the test server pipeline + } + + protected void WhenICallTheMiddleware() + { + ResponseMessage = Client.GetAsync(Url).Result; + } + + public void Dispose() + { + Client.Dispose(); + Server.Dispose(); + } + } +} diff --git a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs index 65074b67..6672a820 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs @@ -1,34 +1,28 @@ -using System.Collections.Generic; -using System.IO; -using System.Net.Http; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; -using Moq; -using Ocelot.Configuration.Builder; -using Ocelot.DownstreamRouteFinder; -using Ocelot.Errors; -using Ocelot.Infrastructure.RequestData; -using Ocelot.LoadBalancer.LoadBalancers; -using Ocelot.LoadBalancer.Middleware; -using Ocelot.Logging; -using Ocelot.Responses; -using Ocelot.Values; -using TestStack.BDDfy; -using Xunit; -using Shouldly; - namespace Ocelot.UnitTests.LoadBalancer { - public class LoadBalancerMiddlewareTests + using System.Collections.Generic; + using System.Net.Http; + using Microsoft.AspNetCore.Builder; + using Microsoft.Extensions.DependencyInjection; + using Moq; + using Ocelot.Configuration.Builder; + using Ocelot.DownstreamRouteFinder; + using Ocelot.Errors; + using Ocelot.Infrastructure.RequestData; + using Ocelot.LoadBalancer.LoadBalancers; + using Ocelot.LoadBalancer.Middleware; + using Ocelot.Logging; + using Ocelot.Responses; + using Ocelot.Values; + using Shouldly; + using TestStack.BDDfy; + using Xunit; + + public class LoadBalancerMiddlewareTests : ServerHostedMiddlewareTest { private readonly Mock _loadBalancerHouse; private readonly Mock _scopedRepository; private readonly Mock _loadBalancer; - private readonly string _url; - private readonly TestServer _server; - private readonly HttpClient _client; - private HttpResponseMessage _result; private HostAndPort _hostAndPort; private OkResponse _downstreamRoute; private ErrorResponse _getLoadBalancerHouseError; @@ -37,35 +31,17 @@ namespace Ocelot.UnitTests.LoadBalancer public LoadBalancerMiddlewareTests() { - _url = "http://localhost:51879"; _loadBalancerHouse = new Mock(); _scopedRepository = new Mock(); _loadBalancer = new Mock(); _loadBalancerHouse = new Mock(); - var builder = new WebHostBuilder() - .ConfigureServices(x => - { - x.AddSingleton(); - x.AddLogging(); - x.AddSingleton(_loadBalancerHouse.Object); - x.AddSingleton(_scopedRepository.Object); - }) - .UseUrls(_url) - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseUrls(_url) - .Configure(app => - { - app.UseLoadBalancingMiddleware(); - }); _downstreamRequest = new HttpRequestMessage(HttpMethod.Get, ""); _scopedRepository .Setup(sr => sr.Get("DownstreamRequest")) .Returns(new OkResponse(_downstreamRequest)); - _server = new TestServer(builder); - _client = _server.CreateClient(); + + GivenTheTestServerIsConfigured(); } [Fact] @@ -118,6 +94,19 @@ namespace Ocelot.UnitTests.LoadBalancer .BDDfy(); } + protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services) + { + services.AddSingleton(); + services.AddLogging(); + services.AddSingleton(_loadBalancerHouse.Object); + services.AddSingleton(_scopedRepository.Object); + } + + protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) + { + app.UseLoadBalancingMiddleware(); + } + private void GivenTheDownStreamUrlIs(string downstreamUrl) { _downstreamRequest.RequestUri = new System.Uri(downstreamUrl); @@ -154,7 +143,6 @@ namespace Ocelot.UnitTests.LoadBalancer .Returns(new OkResponse(_loadBalancer.Object)); } - private void GivenTheLoadBalancerHouseReturnsAnError() { _getLoadBalancerHouseError = new ErrorResponse(new List() @@ -167,11 +155,6 @@ namespace Ocelot.UnitTests.LoadBalancer .Returns(_getLoadBalancerHouseError); } - private void WhenICallTheMiddleware() - { - _result = _client.GetAsync(_url).Result; - } - private void ThenAnErrorStatingLoadBalancerCouldNotBeFoundIsSetOnPipeline() { _scopedRepository @@ -181,7 +164,7 @@ namespace Ocelot.UnitTests.LoadBalancer .Verify(x => x.Add("OcelotMiddlewareErrors", _getLoadBalancerHouseError.Errors), Times.Once); } - private void ThenAnErrorSayingReleaseFailedIsSetOnThePipeline() + private void ThenAnErrorSayingReleaseFailedIsSetOnThePipeline() { _scopedRepository .Verify(x => x.Add("OcelotMiddlewareError", true), Times.Once); @@ -190,7 +173,7 @@ namespace Ocelot.UnitTests.LoadBalancer .Verify(x => x.Add("OcelotMiddlewareErrors", It.IsAny>()), Times.Once); } - private void ThenAnErrorStatingHostAndPortCouldNotBeFoundIsSetOnPipeline() + private void ThenAnErrorStatingHostAndPortCouldNotBeFoundIsSetOnPipeline() { _scopedRepository .Verify(x => x.Add("OcelotMiddlewareError", true), Times.Once); @@ -199,17 +182,9 @@ namespace Ocelot.UnitTests.LoadBalancer .Verify(x => x.Add("OcelotMiddlewareErrors", _getHostAndPortError.Errors), Times.Once); } - - private void ThenTheDownstreamUrlIsReplacedWith(string expectedUri) { _downstreamRequest.RequestUri.OriginalString.ShouldBe(expectedUri); } - - public void Dispose() - { - _client.Dispose(); - _server.Dispose(); - } } } \ No newline at end of file diff --git a/test/Ocelot.UnitTests/Ocelot.UnitTests.csproj b/test/Ocelot.UnitTests/Ocelot.UnitTests.csproj index 403db47f..201ecccf 100644 --- a/test/Ocelot.UnitTests/Ocelot.UnitTests.csproj +++ b/test/Ocelot.UnitTests/Ocelot.UnitTests.csproj @@ -19,6 +19,10 @@ True + + + + diff --git a/test/Ocelot.UnitTests/QueryStrings/QueryStringBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/QueryStrings/QueryStringBuilderMiddlewareTests.cs index 1343df7d..5897cd85 100644 --- a/test/Ocelot.UnitTests/QueryStrings/QueryStringBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/QueryStrings/QueryStringBuilderMiddlewareTests.cs @@ -1,67 +1,40 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Net.Http; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; -using Moq; -using Ocelot.Configuration; -using Ocelot.Configuration.Builder; -using Ocelot.DownstreamRouteFinder; -using Ocelot.DownstreamRouteFinder.UrlMatcher; -using Ocelot.Infrastructure.RequestData; -using Ocelot.Logging; -using Ocelot.QueryStrings; -using Ocelot.QueryStrings.Middleware; -using Ocelot.Responses; -using TestStack.BDDfy; -using Xunit; -using System.Security.Claims; - -namespace Ocelot.UnitTests.QueryStrings +namespace Ocelot.UnitTests.QueryStrings { - public class QueryStringBuilderMiddlewareTests : IDisposable + using System.Collections.Generic; + using System.Net.Http; + using Microsoft.Extensions.DependencyInjection; + using Moq; + using Ocelot.Configuration; + using Ocelot.Configuration.Builder; + using Ocelot.DownstreamRouteFinder; + using Ocelot.DownstreamRouteFinder.UrlMatcher; + using Ocelot.Infrastructure.RequestData; + using Ocelot.Logging; + using Ocelot.QueryStrings; + using Ocelot.QueryStrings.Middleware; + using Ocelot.Responses; + using TestStack.BDDfy; + using Xunit; + using System.Security.Claims; + using Microsoft.AspNetCore.Builder; + + public class QueryStringBuilderMiddlewareTests : ServerHostedMiddlewareTest { private readonly Mock _scopedRepository; private readonly Mock _addQueries; - private readonly string _url; - private readonly TestServer _server; - private readonly HttpClient _client; private readonly HttpRequestMessage _downstreamRequest; private Response _downstreamRoute; - private HttpResponseMessage _result; public QueryStringBuilderMiddlewareTests() { - _url = "http://localhost:51879"; _scopedRepository = new Mock(); _addQueries = new Mock(); - var builder = new WebHostBuilder() - .ConfigureServices(x => - { - x.AddSingleton(); - x.AddLogging(); - x.AddSingleton(_addQueries.Object); - x.AddSingleton(_scopedRepository.Object); - }) - .UseUrls(_url) - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseUrls(_url) - .Configure(app => - { - app.UseQueryStringBuilderMiddleware(); - }); _downstreamRequest = new HttpRequestMessage(); - _scopedRepository.Setup(sr => sr.Get("DownstreamRequest")) .Returns(new OkResponse(_downstreamRequest)); - _server = new TestServer(builder); - _client = _server.CreateClient(); + GivenTheTestServerIsConfigured(); } [Fact] @@ -84,6 +57,19 @@ namespace Ocelot.UnitTests.QueryStrings .BDDfy(); } + protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services) + { + services.AddSingleton(); + services.AddLogging(); + services.AddSingleton(_addQueries.Object); + services.AddSingleton(_scopedRepository.Object); + } + + protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) + { + app.UseQueryStringBuilderMiddleware(); + } + private void GivenTheAddHeadersToRequestReturnsOk() { _addQueries @@ -103,11 +89,6 @@ namespace Ocelot.UnitTests.QueryStrings _downstreamRequest), Times.Once); } - private void WhenICallTheMiddleware() - { - _result = _client.GetAsync(_url).Result; - } - private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) { _downstreamRoute = new OkResponse(downstreamRoute); @@ -115,11 +96,5 @@ namespace Ocelot.UnitTests.QueryStrings .Setup(x => x.Get(It.IsAny())) .Returns(_downstreamRoute); } - - public void Dispose() - { - _client.Dispose(); - _server.Dispose(); - } } } diff --git a/test/Ocelot.UnitTests/RateLimit/ClientRateLimitMiddlewareTests.cs b/test/Ocelot.UnitTests/RateLimit/ClientRateLimitMiddlewareTests.cs index a38d5a67..9ff9c12c 100644 --- a/test/Ocelot.UnitTests/RateLimit/ClientRateLimitMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/RateLimit/ClientRateLimitMiddlewareTests.cs @@ -24,48 +24,19 @@ using Ocelot.Configuration; namespace Ocelot.UnitTests.RateLimit { - public class ClientRateLimitMiddlewareTests + public class ClientRateLimitMiddlewareTests : ServerHostedMiddlewareTest { private readonly Mock _scopedRepository; - private readonly string _url; - private readonly TestServer _server; - private readonly HttpClient _client; private OkResponse _downstreamRoute; private int responseStatusCode; public ClientRateLimitMiddlewareTests() { - _url = "http://localhost:51879/api/ClientRateLimit"; _scopedRepository = new Mock(); - var builder = new WebHostBuilder() - .ConfigureServices(x => - { - x.AddSingleton(); - x.AddLogging(); - x.AddMemoryCache(); - x.AddSingleton(); - x.AddSingleton(_scopedRepository.Object); - }) - .UseUrls(_url) - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseUrls(_url) - .Configure(app => - { - app.UseRateLimiting(); - app.Run(async context => - { - context.Response.StatusCode = 200; - await context.Response.WriteAsync("This is ratelimit test"); - }); - }); - _server = new TestServer(builder); - _client = _server.CreateClient(); + GivenTheTestServerIsConfigured(); } - [Fact] public void should_call_middleware_and_ratelimiting() { @@ -98,6 +69,24 @@ namespace Ocelot.UnitTests.RateLimit .BDDfy(); } + protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services) + { + services.AddSingleton(); + services.AddLogging(); + services.AddMemoryCache(); + services.AddSingleton(); + services.AddSingleton(_scopedRepository.Object); + } + + protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) + { + app.UseRateLimiting(); + app.Run(async context => + { + context.Response.StatusCode = 200; + await context.Response.WriteAsync("This is ratelimit test"); + }); + } private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) { @@ -110,28 +99,27 @@ namespace Ocelot.UnitTests.RateLimit private void WhenICallTheMiddlewareMultipleTime(int times) { var clientId = "ocelotclient1"; - // Act + for (int i = 0; i < times; i++) { - var request = new HttpRequestMessage(new HttpMethod("GET"), _url); + var request = new HttpRequestMessage(new HttpMethod("GET"), Url); request.Headers.Add("ClientId", clientId); - var response = _client.SendAsync(request); + var response = Client.SendAsync(request); responseStatusCode = (int)response.Result.StatusCode; } - } private void WhenICallTheMiddlewareWithWhiteClient() { var clientId = "ocelotclient2"; - // Act + for (int i = 0; i < 10; i++) { - var request = new HttpRequestMessage(new HttpMethod("GET"), _url); + var request = new HttpRequestMessage(new HttpMethod("GET"), Url); request.Headers.Add("ClientId", clientId); - var response = _client.SendAsync(request); + var response = Client.SendAsync(request); responseStatusCode = (int)response.Result.StatusCode; } } diff --git a/test/Ocelot.UnitTests/Request/HttpRequestBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/Request/HttpRequestBuilderMiddlewareTests.cs index f8563abf..02f2b208 100644 --- a/test/Ocelot.UnitTests/Request/HttpRequestBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Request/HttpRequestBuilderMiddlewareTests.cs @@ -1,63 +1,37 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Net.Http; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; -using Moq; -using Ocelot.Configuration.Builder; -using Ocelot.DownstreamRouteFinder; -using Ocelot.DownstreamRouteFinder.UrlMatcher; -using Ocelot.Infrastructure.RequestData; -using Ocelot.Logging; -using Ocelot.Request.Builder; -using Ocelot.Request.Middleware; -using Ocelot.Responses; -using TestStack.BDDfy; -using Xunit; -using Ocelot.Requester.QoS; - -namespace Ocelot.UnitTests.Request +namespace Ocelot.UnitTests.Request { - public class HttpRequestBuilderMiddlewareTests : IDisposable + using System.Collections.Generic; + using System.Net.Http; + using Microsoft.Extensions.DependencyInjection; + using Moq; + using Ocelot.Configuration.Builder; + using Ocelot.DownstreamRouteFinder; + using Ocelot.DownstreamRouteFinder.UrlMatcher; + using Ocelot.Infrastructure.RequestData; + using Ocelot.Logging; + using Ocelot.Request.Builder; + using Ocelot.Request.Middleware; + using Ocelot.Responses; + using TestStack.BDDfy; + using Xunit; + using Ocelot.Requester.QoS; + using Microsoft.AspNetCore.Builder; + + public class HttpRequestBuilderMiddlewareTests : ServerHostedMiddlewareTest { private readonly Mock _requestBuilder; private readonly Mock _scopedRepository; private readonly Mock _qosProviderHouse; private readonly HttpRequestMessage _downstreamRequest; - private readonly string _url; - private readonly TestServer _server; - private readonly HttpClient _client; - private HttpResponseMessage _result; private OkResponse _request; private OkResponse _downstreamUrl; private OkResponse _downstreamRoute; public HttpRequestBuilderMiddlewareTests() { - _url = "http://localhost:51879"; _qosProviderHouse = new Mock(); _requestBuilder = new Mock(); _scopedRepository = new Mock(); - var builder = new WebHostBuilder() - .ConfigureServices(x => - { - x.AddSingleton(); - x.AddLogging(); - x.AddSingleton(_qosProviderHouse.Object); - x.AddSingleton(_requestBuilder.Object); - x.AddSingleton(_scopedRepository.Object); - }) - .UseUrls(_url) - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseUrls(_url) - .Configure(app => - { - app.UseHttpRequestBuilderMiddleware(); - }); _downstreamRequest = new HttpRequestMessage(); @@ -65,8 +39,7 @@ namespace Ocelot.UnitTests.Request .Setup(sr => sr.Get("DownstreamRequest")) .Returns(new OkResponse(_downstreamRequest)); - _server = new TestServer(builder); - _client = _server.CreateClient(); + GivenTheTestServerIsConfigured(); } [Fact] @@ -88,6 +61,28 @@ namespace Ocelot.UnitTests.Request .BDDfy(); } + protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services) + { + services.AddSingleton(); + services.AddLogging(); + services.AddSingleton(_qosProviderHouse.Object); + services.AddSingleton(_requestBuilder.Object); + services.AddSingleton(_scopedRepository.Object); + } + + protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) + { + app.UseHttpRequestBuilderMiddleware(); + } + + private void GivenTheDownStreamUrlIs(string downstreamUrl) + { + _downstreamUrl = new OkResponse(downstreamUrl); + _scopedRepository + .Setup(x => x.Get(It.IsAny())) + .Returns(_downstreamUrl); + } + private void GivenTheQosProviderHouseReturns(Response qosProvider) { _qosProviderHouse @@ -117,24 +112,5 @@ namespace Ocelot.UnitTests.Request _scopedRepository .Verify(x => x.Add("Request", _request.Data), Times.Once()); } - - private void WhenICallTheMiddleware() - { - _result = _client.GetAsync(_url).Result; - } - - private void GivenTheDownStreamUrlIs(string downstreamUrl) - { - _downstreamUrl = new OkResponse(downstreamUrl); - _scopedRepository - .Setup(x => x.Get(It.IsAny())) - .Returns(_downstreamUrl); - } - - public void Dispose() - { - _client.Dispose(); - _server.Dispose(); - } } } diff --git a/test/Ocelot.UnitTests/RequestId/RequestIdMiddlewareTests.cs b/test/Ocelot.UnitTests/RequestId/RequestIdMiddlewareTests.cs index d56bbce6..6ae91b68 100644 --- a/test/Ocelot.UnitTests/RequestId/RequestIdMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/RequestId/RequestIdMiddlewareTests.cs @@ -1,74 +1,43 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net.Http; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; -using Moq; -using Ocelot.Configuration.Builder; -using Ocelot.DownstreamRouteFinder; -using Ocelot.DownstreamRouteFinder.UrlMatcher; -using Ocelot.Infrastructure.RequestData; -using Ocelot.Logging; -using Ocelot.RequestId.Middleware; -using Ocelot.Responses; -using Shouldly; -using TestStack.BDDfy; -using Xunit; - -namespace Ocelot.UnitTests.RequestId +namespace Ocelot.UnitTests.RequestId { - public class RequestIdMiddlewareTests + using System; + using System.Collections.Generic; + using System.Linq; + using System.Net.Http; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Builder; + using Microsoft.AspNetCore.Hosting; + using Microsoft.Extensions.DependencyInjection; + using Moq; + using Ocelot.Configuration.Builder; + using Ocelot.DownstreamRouteFinder; + using Ocelot.DownstreamRouteFinder.UrlMatcher; + using Ocelot.Infrastructure.RequestData; + using Ocelot.Logging; + using Ocelot.RequestId.Middleware; + using Ocelot.Responses; + using Shouldly; + using TestStack.BDDfy; + using Xunit; + + public class RequestIdMiddlewareTests : ServerHostedMiddlewareTest { private readonly Mock _scopedRepository; private readonly HttpRequestMessage _downstreamRequest; - private readonly string _url; - private readonly TestServer _server; - private readonly HttpClient _client; private Response _downstreamRoute; - private HttpResponseMessage _result; private string _value; private string _key; public RequestIdMiddlewareTests() { - _url = "http://localhost:51879"; - _scopedRepository = new Mock(); - var builder = new WebHostBuilder() - .ConfigureServices(x => - { - x.AddSingleton(); - x.AddLogging(); - x.AddSingleton(_scopedRepository.Object); - }) - .UseUrls(_url) - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseUrls(_url) - .Configure(app => - { - app.UseRequestIdMiddleware(); - - app.Run(x => - { - x.Response.Headers.Add("LSRequestId", x.TraceIdentifier); - return Task.CompletedTask; - }); - }); - - _server = new TestServer(builder); - _client = _server.CreateClient(); - _downstreamRequest = new HttpRequestMessage(); + _scopedRepository = new Mock(); _scopedRepository .Setup(sr => sr.Get("DownstreamRequest")) .Returns(new OkResponse(_downstreamRequest)); + + GivenTheTestServerIsConfigured(); } [Fact] @@ -106,6 +75,24 @@ namespace Ocelot.UnitTests.RequestId .BDDfy(); } + protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services) + { + services.AddSingleton(); + services.AddLogging(); + services.AddSingleton(_scopedRepository.Object); + } + + protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) + { + app.UseRequestIdMiddleware(); + + app.Run(x => + { + x.Response.Headers.Add("LSRequestId", x.TraceIdentifier); + return Task.CompletedTask; + }); + } + private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) { _downstreamRoute = new OkResponse(downstreamRoute); @@ -118,28 +105,17 @@ namespace Ocelot.UnitTests.RequestId { _key = key; _value = value; - _client.DefaultRequestHeaders.TryAddWithoutValidation(_key, _value); - } - - private void WhenICallTheMiddleware() - { - _result = _client.GetAsync(_url).Result; + Client.DefaultRequestHeaders.TryAddWithoutValidation(_key, _value); } private void ThenTheTraceIdIsAnything() { - _result.Headers.GetValues("LSRequestId").First().ShouldNotBeNullOrEmpty(); + ResponseMessage.Headers.GetValues("LSRequestId").First().ShouldNotBeNullOrEmpty(); } private void ThenTheTraceIdIs(string expected) { - _result.Headers.GetValues("LSRequestId").First().ShouldBe(expected); - } - - public void Dispose() - { - _client.Dispose(); - _server.Dispose(); + ResponseMessage.Headers.GetValues("LSRequestId").First().ShouldBe(expected); } } } diff --git a/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs b/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs index b95367be..8d227dce 100644 --- a/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs @@ -1,62 +1,31 @@ -using System; -using System.IO; -using System.Net; -using System.Net.Http; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Moq; -using Ocelot.Infrastructure.RequestData; -using Ocelot.Logging; -using Ocelot.QueryStrings.Middleware; -using Ocelot.Requester; -using Ocelot.Requester.Middleware; -using Ocelot.Requester.QoS; -using Ocelot.Responder; -using Ocelot.Responses; -using TestStack.BDDfy; -using Xunit; - -namespace Ocelot.UnitTests.Requester +namespace Ocelot.UnitTests.Requester { - public class HttpRequesterMiddlewareTests : IDisposable + using System.Net.Http; + using Microsoft.AspNetCore.Builder; + using Microsoft.Extensions.DependencyInjection; + using Moq; + using Ocelot.Infrastructure.RequestData; + using Ocelot.Logging; + using Ocelot.Requester; + using Ocelot.Requester.Middleware; + using Ocelot.Requester.QoS; + using Ocelot.Responses; + using TestStack.BDDfy; + using Xunit; + + public class HttpRequesterMiddlewareTests : ServerHostedMiddlewareTest { private readonly Mock _requester; private readonly Mock _scopedRepository; - private readonly string _url; - private readonly TestServer _server; - private readonly HttpClient _client; - private HttpResponseMessage _result; private OkResponse _response; private OkResponse _request; public HttpRequesterMiddlewareTests() { - _url = "http://localhost:51879"; _requester = new Mock(); _scopedRepository = new Mock(); - var builder = new WebHostBuilder() - .ConfigureServices(x => - { - x.AddSingleton(); - x.AddLogging(); - x.AddSingleton(_requester.Object); - x.AddSingleton(_scopedRepository.Object); - }) - .UseUrls(_url) - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseUrls(_url) - .Configure(app => - { - app.UseHttpRequesterMiddleware(); - }); - _server = new TestServer(builder); - _client = _server.CreateClient(); + GivenTheTestServerIsConfigured(); } [Fact] @@ -70,6 +39,27 @@ namespace Ocelot.UnitTests.Requester .BDDfy(); } + protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services) + { + services.AddSingleton(); + services.AddLogging(); + services.AddSingleton(_requester.Object); + services.AddSingleton(_scopedRepository.Object); + } + + protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) + { + app.UseHttpRequesterMiddleware(); + } + + private void GivenTheRequestIs(Ocelot.Request.Request request) + { + _request = new OkResponse(request); + _scopedRepository + .Setup(x => x.Get(It.IsAny())) + .Returns(_request); + } + private void GivenTheRequesterReturns(HttpResponseMessage response) { _response = new OkResponse(response); @@ -90,24 +80,5 @@ namespace Ocelot.UnitTests.Requester _scopedRepository .Verify(x => x.Add("HttpResponseMessage", _response.Data), Times.Once()); } - - private void WhenICallTheMiddleware() - { - _result = _client.GetAsync(_url).Result; - } - - private void GivenTheRequestIs(Ocelot.Request.Request request) - { - _request = new OkResponse(request); - _scopedRepository - .Setup(x => x.Get(It.IsAny())) - .Returns(_request); - } - - public void Dispose() - { - _client.Dispose(); - _server.Dispose(); - } } } diff --git a/test/Ocelot.UnitTests/Responder/HttpContextResponderTests.cs b/test/Ocelot.UnitTests/Responder/HttpContextResponderTests.cs new file mode 100644 index 00000000..ad62dcfc --- /dev/null +++ b/test/Ocelot.UnitTests/Responder/HttpContextResponderTests.cs @@ -0,0 +1,98 @@ +using Microsoft.AspNetCore.Http; +using Moq; +using Ocelot.Headers; +using Ocelot.Responder; +using Shouldly; +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Text; +using TestStack.BDDfy; +using Xunit; +using System.IO; +using System.Net; +using System.Threading.Tasks; + +namespace Ocelot.UnitTests.Responder +{ + public class HttpContextResponderTests + { + readonly HttpContextResponder _responder; + + readonly Mock _removeOutputHeaders; + + HttpContext _httpContext; + + HttpResponseMessage _httpResponseMessage; + + public HttpContextResponderTests() + { + _removeOutputHeaders = new Mock(); + _httpContext = new DefaultHttpContext(); + _httpResponseMessage = new HttpResponseMessage(); + _httpResponseMessage.Content = new MyHttpContent(); + _responder = new HttpContextResponder(_removeOutputHeaders.Object); + } + + [Fact] + public void DoSomething() + { + this.Given(_ => GivenTheHttpResponseMessageHasHeader("abc","123")) + .And(_ => GivenTheHttpResponseMessageHasHeader("def", new[] { "456", "789" })) + .And(_ => GivenTheContextResponseHasHeader("abc", "123")) + .When(_ => WhenWeSetTheResponseOnAnHttpContext()) + .Then(_ => ThenSupportedHeadersAreAddedToTheContextResponse()) + .And(_ => ThenUnsupportedHeadersAreNotAddedToTheResponse()) + .BDDfy(); + } + + + private void GivenTheHttpResponseMessageHasHeader(string name, string value) + { + _httpResponseMessage.Headers.Add(name, value); + } + + private void GivenTheHttpResponseMessageHasHeader(string name, IEnumerable values) + { + _httpResponseMessage.Headers.Add(name, values); + } + + private void GivenTheContextResponseHasHeader(string name, string value) + { + _httpContext.Response.Headers.Add(name, value); + } + + private void WhenWeSetTheResponseOnAnHttpContext() + { + _responder.SetResponseOnHttpContext(_httpContext, _httpResponseMessage).GetAwaiter().GetResult(); + } + + private void ThenSupportedHeadersAreAddedToTheContextResponse() + { + _httpContext.Response.Headers.Count.ShouldBe(2); + _httpContext.Response.Headers.ShouldContain(h => h.Key == "abc" && h.Value == "123"); + _httpContext.Response.Headers.ShouldContain(h => h.Key == "def" && h.Value == "456, 789"); + } + + private void ThenUnsupportedHeadersAreNotAddedToTheResponse() + { + _removeOutputHeaders.Verify(roh => roh.Remove(_httpResponseMessage.Headers), Times.Once); + } + + + class MyHttpContent : HttpContent + { + protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) + { + return Task.CompletedTask; + } + + protected override bool TryComputeLength(out long length) + { + length = 0; + return true; + } + } + + } +} diff --git a/test/Ocelot.UnitTests/Responder/ResponderMiddlewareTests.cs b/test/Ocelot.UnitTests/Responder/ResponderMiddlewareTests.cs index 09a5c22c..36562abc 100644 --- a/test/Ocelot.UnitTests/Responder/ResponderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Responder/ResponderMiddlewareTests.cs @@ -1,11 +1,6 @@ -using System; -using System.IO; -using System.Net.Http; +using System.Net.Http; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using Moq; using Ocelot.Infrastructure.RequestData; using Ocelot.Logging; @@ -14,77 +9,109 @@ using Ocelot.Responder.Middleware; using Ocelot.Responses; using TestStack.BDDfy; using Xunit; +using Microsoft.AspNetCore.Builder; +using Shouldly; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using System.Collections.Generic; +using Ocelot.Errors; +using System.Net; +using Ocelot.Headers; namespace Ocelot.UnitTests.Responder { - public class ResponderMiddlewareTests : IDisposable + public class ResponderMiddlewareTests : ServerHostedMiddlewareTest { - private readonly Mock _responder; + private readonly IHttpResponder _responder; private readonly Mock _scopedRepository; private readonly Mock _codeMapper; - private readonly string _url; - private readonly TestServer _server; - private readonly HttpClient _client; - private HttpResponseMessage _result; + private readonly Mock _outputHeaderRemover; + private HttpStatusCode _httpStatusFromController; + private string _contentFromController; + private OkResponse _response; + private List _pipelineErrors; public ResponderMiddlewareTests() { - _url = "http://localhost:51879"; - _responder = new Mock(); + _outputHeaderRemover = new Mock(); + _responder = new HttpContextResponder(_outputHeaderRemover.Object); _scopedRepository = new Mock(); _codeMapper = new Mock(); - var builder = new WebHostBuilder() - .ConfigureServices(x => - { - x.AddSingleton(); - x.AddLogging(); - x.AddSingleton(_codeMapper.Object); - x.AddSingleton(_responder.Object); - x.AddSingleton(_scopedRepository.Object); - }) - .UseUrls(_url) - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseUrls(_url) - .Configure(app => - { - app.UseResponderMiddleware(); - }); - _server = new TestServer(builder); - _client = _server.CreateClient(); + GivenTheTestServerIsConfigured(); } [Fact] - public void should_not_return_any_errors() + public void PipelineErrors() { - this.Given(x => x.GivenTheHttpResponseMessageIs(new HttpResponseMessage())) + var responseMessage = new HttpResponseMessage(System.Net.HttpStatusCode.Continue); + + this.Given(x => x.GivenTheIncomingHttpResponseMessageIs(new HttpResponseMessage())) + .And(x => x.GivenThereArePipelineErrors()) + .And(x => x.GivenTheErrorWillBeMappedToAnHttpStatus()) + .When(x => x.WhenICallTheMiddleware()) + .Then(x => x.ThenThereAreErrors()) + .BDDfy(); + } + + [Fact] + public void NoPipelineErrors() + { + this.Given(x => x.GivenTheIncomingHttpResponseMessageIs(new HttpResponseMessage())) .And(x => x.GivenThereAreNoPipelineErrors()) .When(x => x.WhenICallTheMiddleware()) .Then(x => x.ThenThereAreNoErrors()) .BDDfy(); } + protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services) + { + services.AddSingleton(); + services.AddLogging(); + services.AddSingleton(_codeMapper.Object); + services.AddSingleton(_responder); + services.AddSingleton(_scopedRepository.Object); + } + + protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) + { + app.UseResponderMiddleware(); + app.Run(SetControllerResponse); + } + + private async Task SetControllerResponse(HttpContext context) + { + _httpStatusFromController = HttpStatusCode.OK; + _contentFromController = "test response"; + context.Response.StatusCode = (int)_httpStatusFromController; + await context.Response.WriteAsync(_contentFromController); + } + private void GivenThereAreNoPipelineErrors() { + GivenThereArePipelineErrors(new List()); + } + + private void GivenThereArePipelineErrors() + { + GivenThereArePipelineErrors(new List() { new AnyError() }); + } + + private void GivenThereArePipelineErrors(List pipelineErrors) + { + _pipelineErrors = pipelineErrors; + _scopedRepository - .Setup(x => x.Get(It.IsAny())) - .Returns(new OkResponse(false)); + .Setup(x => x.Get("OcelotMiddlewareError")) + .Returns(new OkResponse(_pipelineErrors.Count != 0)); + + _scopedRepository + .Setup(sr => sr.Get>("OcelotMiddlewareErrors")) + .Returns(new OkResponse>(_pipelineErrors)); } - private void ThenThereAreNoErrors() - { - //todo a better assert? - } - - private void WhenICallTheMiddleware() - { - _result = _client.GetAsync(_url).Result; - } - - private void GivenTheHttpResponseMessageIs(HttpResponseMessage response) + private void GivenTheIncomingHttpResponseMessageIs(HttpResponseMessage response) { _response = new OkResponse(response); _scopedRepository @@ -92,10 +119,21 @@ namespace Ocelot.UnitTests.Responder .Returns(_response); } - public void Dispose() + private void GivenTheErrorWillBeMappedToAnHttpStatus() { - _client.Dispose(); - _server.Dispose(); + _codeMapper.Setup(cm => cm.Map(_pipelineErrors)) + .Returns((int)HttpStatusCode.InternalServerError); + } + + private void ThenThereAreNoErrors() + { + ResponseMessage.StatusCode.ShouldBe(_httpStatusFromController); + ResponseMessage.Content.ReadAsStringAsync().Result.ShouldBe(_contentFromController); + } + + private void ThenThereAreErrors() + { + ResponseMessage.StatusCode.ShouldBe(System.Net.HttpStatusCode.BadRequest); } } } diff --git a/test/Ocelot.UnitTests/Responder/ResponderMiddlewareTestsV2.cs b/test/Ocelot.UnitTests/Responder/ResponderMiddlewareTestsV2.cs index 28c3e9fa..ff0bc036 100644 --- a/test/Ocelot.UnitTests/Responder/ResponderMiddlewareTestsV2.cs +++ b/test/Ocelot.UnitTests/Responder/ResponderMiddlewareTestsV2.cs @@ -15,6 +15,7 @@ namespace Ocelot.UnitTests.Responder { public class ResponderMiddlewareTestsV2 { + private readonly ResponderMiddleware _middleware; private readonly Mock _responder; private readonly Mock _scopedRepository; private readonly Mock _codeMapper; @@ -22,7 +23,6 @@ namespace Ocelot.UnitTests.Responder private readonly Mock _loggerFactory; private readonly Mock _logger; private readonly Mock _httpContext; - private ResponderMiddleware _middleware; private OkResponse _response; private int _mappedStatusCode; private List _pipelineErrors; From 84743ede0eda0347bd67bbd681c1d9585e36e3c6 Mon Sep 17 00:00:00 2001 From: Philip Wood Date: Tue, 18 Jul 2017 09:31:26 +0100 Subject: [PATCH 29/35] Fix some test-related build warnings --- test/Ocelot.UnitTests/Cache/CacheManagerCacheTests.cs | 2 -- test/Ocelot.UnitTests/ServiceDiscovery/ServiceRegistryTests.cs | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/test/Ocelot.UnitTests/Cache/CacheManagerCacheTests.cs b/test/Ocelot.UnitTests/Cache/CacheManagerCacheTests.cs index f097ccf1..54107298 100644 --- a/test/Ocelot.UnitTests/Cache/CacheManagerCacheTests.cs +++ b/test/Ocelot.UnitTests/Cache/CacheManagerCacheTests.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using CacheManager.Core; using Moq; using Ocelot.Cache; @@ -17,7 +16,6 @@ namespace Ocelot.UnitTests.Cache private string _value; private string _resultGet; private TimeSpan _ttlSeconds; - private List _resultKeys; private string _region; public CacheManagerCacheTests() diff --git a/test/Ocelot.UnitTests/ServiceDiscovery/ServiceRegistryTests.cs b/test/Ocelot.UnitTests/ServiceDiscovery/ServiceRegistryTests.cs index 87425329..3269b420 100644 --- a/test/Ocelot.UnitTests/ServiceDiscovery/ServiceRegistryTests.cs +++ b/test/Ocelot.UnitTests/ServiceDiscovery/ServiceRegistryTests.cs @@ -28,6 +28,7 @@ namespace Ocelot.UnitTests.ServiceDiscovery .BDDfy(); } + [Fact] public void should_lookup_service() { this.Given(x => x.GivenAServiceIsRegistered("product", "localhost:600", 80)) From c70a90f415a048cd8f23b9147e26f9ab4b1a4ce1 Mon Sep 17 00:00:00 2001 From: Philip Wood Date: Tue, 18 Jul 2017 10:20:59 +0100 Subject: [PATCH 30/35] Fix more test-related build warnings --- test/Ocelot.IntegrationTests/ThreadSafeHeadersTests.cs | 7 ++----- .../Errors/ExceptionHandlerMiddlewareTests.cs | 3 +++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/Ocelot.IntegrationTests/ThreadSafeHeadersTests.cs b/test/Ocelot.IntegrationTests/ThreadSafeHeadersTests.cs index 2512a87d..2922d92c 100644 --- a/test/Ocelot.IntegrationTests/ThreadSafeHeadersTests.cs +++ b/test/Ocelot.IntegrationTests/ThreadSafeHeadersTests.cs @@ -15,7 +15,6 @@ using TestStack.BDDfy; using Xunit; using Microsoft.AspNetCore.Http; using System.Threading.Tasks; -using System.Threading; using System.Collections.Concurrent; namespace Ocelot.IntegrationTests @@ -23,11 +22,9 @@ namespace Ocelot.IntegrationTests public class ThreadSafeHeadersTests : IDisposable { private readonly HttpClient _httpClient; - private HttpResponseMessage _response; private IWebHost _builder; private IWebHostBuilder _webHostBuilder; private readonly string _ocelotBaseUrl; - private BearerToken _token; private IWebHost _downstreamBuilder; private readonly Random _random; private readonly ConcurrentBag _results; @@ -61,7 +58,7 @@ namespace Ocelot.IntegrationTests }; this.Given(x => GivenThereIsAConfiguration(configuration)) - .And(x => GivenThereIsAServiceRunningOn("http://localhost:51879")) + .And(x => GivenThereIsAServiceRunningOn("http://localhost:51879")) .And(x => GivenOcelotIsRunning()) .When(x => WhenIGetUrlOnTheApiGatewayMultipleTimesWithDifferentHeaderValues("/", 300)) .Then(x => ThenTheSameHeaderValuesAreReturnedByTheDownstreamService()) @@ -135,7 +132,7 @@ namespace Ocelot.IntegrationTests text = File.ReadAllText(configurationPath); } - public void WhenIGetUrlOnTheApiGatewayMultipleTimesWithDifferentHeaderValues(string url, int times) + private void WhenIGetUrlOnTheApiGatewayMultipleTimesWithDifferentHeaderValues(string url, int times) { var tasks = new Task[times]; diff --git a/test/Ocelot.UnitTests/Errors/ExceptionHandlerMiddlewareTests.cs b/test/Ocelot.UnitTests/Errors/ExceptionHandlerMiddlewareTests.cs index 8584f106..ac786ec1 100644 --- a/test/Ocelot.UnitTests/Errors/ExceptionHandlerMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Errors/ExceptionHandlerMiddlewareTests.cs @@ -13,6 +13,7 @@ using Ocelot.Logging; using Shouldly; using TestStack.BDDfy; using Xunit; +using System.Threading.Tasks; namespace Ocelot.UnitTests.Errors { @@ -67,6 +68,7 @@ namespace Ocelot.UnitTests.Errors app.UseExceptionHandlerMiddleware(); app.Use(async (context, next) => { + await Task.CompletedTask; throw new Exception("BOOM"); }); }); @@ -109,6 +111,7 @@ namespace Ocelot.UnitTests.Errors app.UseExceptionHandlerMiddleware(); app.Run(async context => { + await Task.CompletedTask; context.Response.StatusCode = 200; }); }); From d02e921a58c90545fed6e85b42069b3e09d5b710 Mon Sep 17 00:00:00 2001 From: Philip Wood Date: Tue, 18 Jul 2017 10:53:57 +0100 Subject: [PATCH 31/35] Moved ScopedRepository into test base class. --- .../AuthenticationMiddlewareTests.cs | 7 +-- .../AuthorisationMiddlewareTests.cs | 7 +-- .../Cache/OutputCacheMiddlewareTests.cs | 15 +++--- .../Claims/ClaimsBuilderMiddlewareTests.cs | 7 +-- .../DownstreamRouteFinderMiddlewareTests.cs | 7 +-- .../DownstreamUrlCreatorMiddlewareTests.cs | 8 ++- ...ttpRequestHeadersBuilderMiddlewareTests.cs | 9 ++-- .../LoadBalancerMiddlewareTests.cs | 22 ++++---- .../QueryStringBuilderMiddlewareTests.cs | 9 ++-- .../ClientRateLimitMiddlewareTests.cs | 51 ++++++++---------- .../RequestId/RequestIdMiddlewareTests.cs | 9 ++-- .../Requester/HttpRequesterMiddlewareTests.cs | 11 ++-- .../Responder/ResponderMiddlewareTests.cs | 54 +++++++++---------- ...eTest.cs => ServerHostedMiddlewareTest.cs} | 4 ++ 14 files changed, 91 insertions(+), 129 deletions(-) rename test/Ocelot.UnitTests/{HostedMiddlewareTest.cs => ServerHostedMiddlewareTest.cs} (89%) diff --git a/test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs b/test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs index be52e909..819c48d7 100644 --- a/test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Authentication/AuthenticationMiddlewareTests.cs @@ -11,7 +11,6 @@ using Ocelot.Configuration.Builder; using Ocelot.DownstreamRouteFinder; using Ocelot.DownstreamRouteFinder.UrlMatcher; - using Ocelot.Infrastructure.RequestData; using Ocelot.Logging; using Ocelot.Responses; using Shouldly; @@ -20,13 +19,11 @@ public class AuthenticationMiddlewareTests : ServerHostedMiddlewareTest { - private readonly Mock _scopedRepository; private readonly Mock _authFactory; private OkResponse _downstreamRoute; public AuthenticationMiddlewareTests() { - _scopedRepository = new Mock(); _authFactory = new Mock(); GivenTheTestServerIsConfigured(); @@ -49,7 +46,7 @@ services.AddSingleton(); services.AddLogging(); services.AddSingleton(_authFactory.Object); - services.AddSingleton(_scopedRepository.Object); + services.AddSingleton(ScopedRepository.Object); } protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) @@ -71,7 +68,7 @@ private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) { _downstreamRoute = new OkResponse(downstreamRoute); - _scopedRepository + ScopedRepository .Setup(x => x.Get(It.IsAny())) .Returns(_downstreamRoute); } diff --git a/test/Ocelot.UnitTests/Authorization/AuthorisationMiddlewareTests.cs b/test/Ocelot.UnitTests/Authorization/AuthorisationMiddlewareTests.cs index 508db7ce..ca346974 100644 --- a/test/Ocelot.UnitTests/Authorization/AuthorisationMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Authorization/AuthorisationMiddlewareTests.cs @@ -10,7 +10,6 @@ using Ocelot.Configuration.Builder; using Ocelot.DownstreamRouteFinder; using Ocelot.DownstreamRouteFinder.UrlMatcher; - using Ocelot.Infrastructure.RequestData; using Ocelot.Logging; using Ocelot.Responses; using TestStack.BDDfy; @@ -18,14 +17,12 @@ public class AuthorisationMiddlewareTests : ServerHostedMiddlewareTest { - private readonly Mock _scopedRepository; private readonly Mock _authService; private readonly Mock _authScopesService; private OkResponse _downstreamRoute; public AuthorisationMiddlewareTests() { - _scopedRepository = new Mock(); _authService = new Mock(); _authScopesService = new Mock(); @@ -52,7 +49,7 @@ services.AddLogging(); services.AddSingleton(_authService.Object); services.AddSingleton(_authScopesService.Object); - services.AddSingleton(_scopedRepository.Object); + services.AddSingleton(ScopedRepository.Object); } protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) @@ -63,7 +60,7 @@ private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) { _downstreamRoute = new OkResponse(downstreamRoute); - _scopedRepository + ScopedRepository .Setup(x => x.Get(It.IsAny())) .Returns(_downstreamRoute); } diff --git a/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs b/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs index faade351..11c15d8d 100644 --- a/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Cache/OutputCacheMiddlewareTests.cs @@ -12,7 +12,6 @@ using Ocelot.Configuration.Builder; using Ocelot.DownstreamRouteFinder; using Ocelot.DownstreamRouteFinder.UrlMatcher; - using Ocelot.Infrastructure.RequestData; using Ocelot.Logging; using Ocelot.Responses; using TestStack.BDDfy; @@ -21,15 +20,13 @@ public class OutputCacheMiddlewareTests : ServerHostedMiddlewareTest { private readonly Mock> _cacheManager; - private readonly Mock _scopedRepo; private HttpResponseMessage _response; public OutputCacheMiddlewareTests() { _cacheManager = new Mock>(); - _scopedRepo = new Mock(); - _scopedRepo + ScopedRepository .Setup(sr => sr.Get("DownstreamRequest")) .Returns(new OkResponse(new HttpRequestMessage(HttpMethod.Get, "https://some.url/blah?abcd=123"))); @@ -64,7 +61,7 @@ services.AddSingleton(); services.AddLogging(); services.AddSingleton(_cacheManager.Object); - services.AddSingleton(_scopedRepo.Object); + services.AddSingleton(ScopedRepository.Object); services.AddSingleton(); } @@ -83,7 +80,7 @@ private void GivenResponseIsNotCached() { - _scopedRepo + ScopedRepository .Setup(x => x.Get("HttpResponseMessage")) .Returns(new OkResponse(new HttpResponseMessage())); } @@ -98,21 +95,21 @@ var downstreamRoute = new DownstreamRoute(new List(), reRoute); - _scopedRepo + ScopedRepository .Setup(x => x.Get(It.IsAny())) .Returns(new OkResponse(downstreamRoute)); } private void GivenThereAreNoErrors() { - _scopedRepo + ScopedRepository .Setup(x => x.Get("OcelotMiddlewareError")) .Returns(new OkResponse(false)); } private void GivenThereIsADownstreamUrl() { - _scopedRepo + ScopedRepository .Setup(x => x.Get("DownstreamUrl")) .Returns(new OkResponse("anything")); } diff --git a/test/Ocelot.UnitTests/Claims/ClaimsBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/Claims/ClaimsBuilderMiddlewareTests.cs index 8ac75ef4..3eb86d1e 100644 --- a/test/Ocelot.UnitTests/Claims/ClaimsBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Claims/ClaimsBuilderMiddlewareTests.cs @@ -11,7 +11,6 @@ using Ocelot.Configuration.Builder; using Ocelot.DownstreamRouteFinder; using Ocelot.DownstreamRouteFinder.UrlMatcher; - using Ocelot.Infrastructure.RequestData; using Ocelot.Logging; using Ocelot.Responses; using TestStack.BDDfy; @@ -19,13 +18,11 @@ public class ClaimsBuilderMiddlewareTests : ServerHostedMiddlewareTest { - private readonly Mock _scopedRepository; private readonly Mock _addHeaders; private Response _downstreamRoute; public ClaimsBuilderMiddlewareTests() { - _scopedRepository = new Mock(); _addHeaders = new Mock(); GivenTheTestServerIsConfigured(); @@ -56,7 +53,7 @@ services.AddSingleton(); services.AddLogging(); services.AddSingleton(_addHeaders.Object); - services.AddSingleton(_scopedRepository.Object); + services.AddSingleton(ScopedRepository.Object); } protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) @@ -67,7 +64,7 @@ private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) { _downstreamRoute = new OkResponse(downstreamRoute); - _scopedRepository + ScopedRepository .Setup(x => x.Get(It.IsAny())) .Returns(_downstreamRoute); } diff --git a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs index 367b9559..fb312e21 100644 --- a/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/DownstreamRouteFinder/DownstreamRouteFinderMiddlewareTests.cs @@ -9,7 +9,6 @@ using Ocelot.DownstreamRouteFinder.Finder; using Ocelot.DownstreamRouteFinder.Middleware; using Ocelot.DownstreamRouteFinder.UrlMatcher; - using Ocelot.Infrastructure.RequestData; using Ocelot.Logging; using Ocelot.Responses; using TestStack.BDDfy; @@ -18,13 +17,11 @@ public class DownstreamRouteFinderMiddlewareTests : ServerHostedMiddlewareTest { private readonly Mock _downstreamRouteFinder; - private readonly Mock _scopedRepository; private Response _downstreamRoute; public DownstreamRouteFinderMiddlewareTests() { _downstreamRouteFinder = new Mock(); - _scopedRepository = new Mock(); GivenTheTestServerIsConfigured(); } @@ -49,7 +46,7 @@ services.AddSingleton(); services.AddLogging(); services.AddSingleton(_downstreamRouteFinder.Object); - services.AddSingleton(_scopedRepository.Object); + services.AddSingleton(ScopedRepository.Object); } protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) @@ -67,7 +64,7 @@ private void ThenTheScopedDataRepositoryIsCalledCorrectly() { - _scopedRepository + ScopedRepository .Verify(x => x.Add("DownstreamRoute", _downstreamRoute.Data), Times.Once()); } } diff --git a/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs b/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs index a538a9f8..1af70f71 100644 --- a/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/DownstreamUrlCreator/DownstreamUrlCreatorMiddlewareTests.cs @@ -23,7 +23,6 @@ public class DownstreamUrlCreatorMiddlewareTests : ServerHostedMiddlewareTest { private readonly Mock _downstreamUrlTemplateVariableReplacer; - private readonly Mock _scopedRepository; private readonly Mock _urlBuilder; private Response _downstreamRoute; private OkResponse _downstreamPath; @@ -32,12 +31,11 @@ public DownstreamUrlCreatorMiddlewareTests() { _downstreamUrlTemplateVariableReplacer = new Mock(); - _scopedRepository = new Mock(); _urlBuilder = new Mock(); _downstreamRequest = new HttpRequestMessage(HttpMethod.Get, "https://my.url/abc/?q=123"); - _scopedRepository + ScopedRepository .Setup(sr => sr.Get("DownstreamRequest")) .Returns(new OkResponse(_downstreamRequest)); @@ -67,7 +65,7 @@ services.AddSingleton(); services.AddLogging(); services.AddSingleton(_downstreamUrlTemplateVariableReplacer.Object); - services.AddSingleton(_scopedRepository.Object); + services.AddSingleton(ScopedRepository.Object); services.AddSingleton(_urlBuilder.Object); } @@ -79,7 +77,7 @@ private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) { _downstreamRoute = new OkResponse(downstreamRoute); - _scopedRepository + ScopedRepository .Setup(x => x.Get(It.IsAny())) .Returns(_downstreamRoute); } diff --git a/test/Ocelot.UnitTests/Headers/HttpRequestHeadersBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/Headers/HttpRequestHeadersBuilderMiddlewareTests.cs index 26a4e541..76a75d0a 100644 --- a/test/Ocelot.UnitTests/Headers/HttpRequestHeadersBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Headers/HttpRequestHeadersBuilderMiddlewareTests.cs @@ -11,7 +11,6 @@ using Ocelot.DownstreamRouteFinder.UrlMatcher; using Ocelot.Headers; using Ocelot.Headers.Middleware; - using Ocelot.Infrastructure.RequestData; using Ocelot.Logging; using Ocelot.Responses; using TestStack.BDDfy; @@ -19,18 +18,16 @@ public class HttpRequestHeadersBuilderMiddlewareTests : ServerHostedMiddlewareTest { - private readonly Mock _scopedRepository; private readonly Mock _addHeaders; private readonly HttpRequestMessage _downstreamRequest; private Response _downstreamRoute; public HttpRequestHeadersBuilderMiddlewareTests() { - _scopedRepository = new Mock(); _addHeaders = new Mock(); _downstreamRequest = new HttpRequestMessage(); - _scopedRepository + ScopedRepository .Setup(sr => sr.Get("DownstreamRequest")) .Returns(new OkResponse(_downstreamRequest)); @@ -62,7 +59,7 @@ services.AddSingleton(); services.AddLogging(); services.AddSingleton(_addHeaders.Object); - services.AddSingleton(_scopedRepository.Object); + services.AddSingleton(ScopedRepository.Object); } protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) @@ -73,7 +70,7 @@ private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) { _downstreamRoute = new OkResponse(downstreamRoute); - _scopedRepository + ScopedRepository .Setup(x => x.Get(It.IsAny())) .Returns(_downstreamRoute); } diff --git a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs index 6672a820..e483f31c 100644 --- a/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/LoadBalancer/LoadBalancerMiddlewareTests.cs @@ -8,7 +8,6 @@ namespace Ocelot.UnitTests.LoadBalancer using Ocelot.Configuration.Builder; using Ocelot.DownstreamRouteFinder; using Ocelot.Errors; - using Ocelot.Infrastructure.RequestData; using Ocelot.LoadBalancer.LoadBalancers; using Ocelot.LoadBalancer.Middleware; using Ocelot.Logging; @@ -21,7 +20,6 @@ namespace Ocelot.UnitTests.LoadBalancer public class LoadBalancerMiddlewareTests : ServerHostedMiddlewareTest { private readonly Mock _loadBalancerHouse; - private readonly Mock _scopedRepository; private readonly Mock _loadBalancer; private HostAndPort _hostAndPort; private OkResponse _downstreamRoute; @@ -32,12 +30,12 @@ namespace Ocelot.UnitTests.LoadBalancer public LoadBalancerMiddlewareTests() { _loadBalancerHouse = new Mock(); - _scopedRepository = new Mock(); _loadBalancer = new Mock(); _loadBalancerHouse = new Mock(); _downstreamRequest = new HttpRequestMessage(HttpMethod.Get, ""); - _scopedRepository + + ScopedRepository .Setup(sr => sr.Get("DownstreamRequest")) .Returns(new OkResponse(_downstreamRequest)); @@ -99,7 +97,7 @@ namespace Ocelot.UnitTests.LoadBalancer services.AddSingleton(); services.AddLogging(); services.AddSingleton(_loadBalancerHouse.Object); - services.AddSingleton(_scopedRepository.Object); + services.AddSingleton(ScopedRepository.Object); } protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) @@ -131,7 +129,7 @@ namespace Ocelot.UnitTests.LoadBalancer private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) { _downstreamRoute = new OkResponse(downstreamRoute); - _scopedRepository + ScopedRepository .Setup(x => x.Get(It.IsAny())) .Returns(_downstreamRoute); } @@ -157,28 +155,28 @@ namespace Ocelot.UnitTests.LoadBalancer private void ThenAnErrorStatingLoadBalancerCouldNotBeFoundIsSetOnPipeline() { - _scopedRepository + ScopedRepository .Verify(x => x.Add("OcelotMiddlewareError", true), Times.Once); - _scopedRepository + ScopedRepository .Verify(x => x.Add("OcelotMiddlewareErrors", _getLoadBalancerHouseError.Errors), Times.Once); } private void ThenAnErrorSayingReleaseFailedIsSetOnThePipeline() { - _scopedRepository + ScopedRepository .Verify(x => x.Add("OcelotMiddlewareError", true), Times.Once); - _scopedRepository + ScopedRepository .Verify(x => x.Add("OcelotMiddlewareErrors", It.IsAny>()), Times.Once); } private void ThenAnErrorStatingHostAndPortCouldNotBeFoundIsSetOnPipeline() { - _scopedRepository + ScopedRepository .Verify(x => x.Add("OcelotMiddlewareError", true), Times.Once); - _scopedRepository + ScopedRepository .Verify(x => x.Add("OcelotMiddlewareErrors", _getHostAndPortError.Errors), Times.Once); } diff --git a/test/Ocelot.UnitTests/QueryStrings/QueryStringBuilderMiddlewareTests.cs b/test/Ocelot.UnitTests/QueryStrings/QueryStringBuilderMiddlewareTests.cs index 5897cd85..4bbcfd2c 100644 --- a/test/Ocelot.UnitTests/QueryStrings/QueryStringBuilderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/QueryStrings/QueryStringBuilderMiddlewareTests.cs @@ -8,7 +8,6 @@ using Ocelot.Configuration.Builder; using Ocelot.DownstreamRouteFinder; using Ocelot.DownstreamRouteFinder.UrlMatcher; - using Ocelot.Infrastructure.RequestData; using Ocelot.Logging; using Ocelot.QueryStrings; using Ocelot.QueryStrings.Middleware; @@ -20,18 +19,16 @@ public class QueryStringBuilderMiddlewareTests : ServerHostedMiddlewareTest { - private readonly Mock _scopedRepository; private readonly Mock _addQueries; private readonly HttpRequestMessage _downstreamRequest; private Response _downstreamRoute; public QueryStringBuilderMiddlewareTests() { - _scopedRepository = new Mock(); _addQueries = new Mock(); _downstreamRequest = new HttpRequestMessage(); - _scopedRepository.Setup(sr => sr.Get("DownstreamRequest")) + ScopedRepository.Setup(sr => sr.Get("DownstreamRequest")) .Returns(new OkResponse(_downstreamRequest)); GivenTheTestServerIsConfigured(); @@ -62,7 +59,7 @@ services.AddSingleton(); services.AddLogging(); services.AddSingleton(_addQueries.Object); - services.AddSingleton(_scopedRepository.Object); + services.AddSingleton(ScopedRepository.Object); } protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) @@ -92,7 +89,7 @@ private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) { _downstreamRoute = new OkResponse(downstreamRoute); - _scopedRepository + ScopedRepository .Setup(x => x.Get(It.IsAny())) .Returns(_downstreamRoute); } diff --git a/test/Ocelot.UnitTests/RateLimit/ClientRateLimitMiddlewareTests.cs b/test/Ocelot.UnitTests/RateLimit/ClientRateLimitMiddlewareTests.cs index 9ff9c12c..1b73e233 100644 --- a/test/Ocelot.UnitTests/RateLimit/ClientRateLimitMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/RateLimit/ClientRateLimitMiddlewareTests.cs @@ -1,39 +1,30 @@ -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.TestHost; -using Microsoft.AspNetCore.Http; -using Moq; -using Ocelot.Infrastructure.RequestData; -using Ocelot.RateLimit; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Http; -using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; -using Ocelot.Logging; -using System.IO; -using Ocelot.RateLimit.Middleware; -using Ocelot.DownstreamRouteFinder; -using Ocelot.Responses; -using Xunit; -using TestStack.BDDfy; -using Ocelot.Configuration.Builder; -using Shouldly; -using Ocelot.Configuration; - -namespace Ocelot.UnitTests.RateLimit +namespace Ocelot.UnitTests.RateLimit { + using System.Collections.Generic; + using System.Net.Http; + using Microsoft.AspNetCore.Hosting; + using Microsoft.AspNetCore.Builder; + using Microsoft.AspNetCore.Http; + using Microsoft.Extensions.DependencyInjection; + using Moq; + using Ocelot.Configuration; + using Ocelot.Configuration.Builder; + using Ocelot.DownstreamRouteFinder; + using Ocelot.Logging; + using Ocelot.RateLimit; + using Ocelot.RateLimit.Middleware; + using Ocelot.Responses; + using Shouldly; + using TestStack.BDDfy; + using Xunit; + public class ClientRateLimitMiddlewareTests : ServerHostedMiddlewareTest { - private readonly Mock _scopedRepository; private OkResponse _downstreamRoute; private int responseStatusCode; public ClientRateLimitMiddlewareTests() { - _scopedRepository = new Mock(); - GivenTheTestServerIsConfigured(); } @@ -75,7 +66,7 @@ namespace Ocelot.UnitTests.RateLimit services.AddLogging(); services.AddMemoryCache(); services.AddSingleton(); - services.AddSingleton(_scopedRepository.Object); + services.AddSingleton(ScopedRepository.Object); } protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) @@ -91,7 +82,7 @@ namespace Ocelot.UnitTests.RateLimit private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) { _downstreamRoute = new OkResponse(downstreamRoute); - _scopedRepository + ScopedRepository .Setup(x => x.Get(It.IsAny())) .Returns(_downstreamRoute); } diff --git a/test/Ocelot.UnitTests/RequestId/RequestIdMiddlewareTests.cs b/test/Ocelot.UnitTests/RequestId/RequestIdMiddlewareTests.cs index 6ae91b68..a34290f1 100644 --- a/test/Ocelot.UnitTests/RequestId/RequestIdMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/RequestId/RequestIdMiddlewareTests.cs @@ -12,7 +12,6 @@ using Ocelot.Configuration.Builder; using Ocelot.DownstreamRouteFinder; using Ocelot.DownstreamRouteFinder.UrlMatcher; - using Ocelot.Infrastructure.RequestData; using Ocelot.Logging; using Ocelot.RequestId.Middleware; using Ocelot.Responses; @@ -22,7 +21,6 @@ public class RequestIdMiddlewareTests : ServerHostedMiddlewareTest { - private readonly Mock _scopedRepository; private readonly HttpRequestMessage _downstreamRequest; private Response _downstreamRoute; private string _value; @@ -32,8 +30,7 @@ { _downstreamRequest = new HttpRequestMessage(); - _scopedRepository = new Mock(); - _scopedRepository + ScopedRepository .Setup(sr => sr.Get("DownstreamRequest")) .Returns(new OkResponse(_downstreamRequest)); @@ -79,7 +76,7 @@ { services.AddSingleton(); services.AddLogging(); - services.AddSingleton(_scopedRepository.Object); + services.AddSingleton(ScopedRepository.Object); } protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) @@ -96,7 +93,7 @@ private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute) { _downstreamRoute = new OkResponse(downstreamRoute); - _scopedRepository + ScopedRepository .Setup(x => x.Get(It.IsAny())) .Returns(_downstreamRoute); } diff --git a/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs b/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs index 8d227dce..f5570f15 100644 --- a/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Requester/HttpRequesterMiddlewareTests.cs @@ -4,7 +4,6 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Moq; - using Ocelot.Infrastructure.RequestData; using Ocelot.Logging; using Ocelot.Requester; using Ocelot.Requester.Middleware; @@ -16,14 +15,12 @@ public class HttpRequesterMiddlewareTests : ServerHostedMiddlewareTest { private readonly Mock _requester; - private readonly Mock _scopedRepository; private OkResponse _response; private OkResponse _request; public HttpRequesterMiddlewareTests() { _requester = new Mock(); - _scopedRepository = new Mock(); GivenTheTestServerIsConfigured(); } @@ -44,7 +41,7 @@ services.AddSingleton(); services.AddLogging(); services.AddSingleton(_requester.Object); - services.AddSingleton(_scopedRepository.Object); + services.AddSingleton(ScopedRepository.Object); } protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) @@ -55,7 +52,7 @@ private void GivenTheRequestIs(Ocelot.Request.Request request) { _request = new OkResponse(request); - _scopedRepository + ScopedRepository .Setup(x => x.Get(It.IsAny())) .Returns(_request); } @@ -70,14 +67,14 @@ private void GivenTheScopedRepoReturns() { - _scopedRepository + ScopedRepository .Setup(x => x.Add(It.IsAny(), _response.Data)) .Returns(new OkResponse()); } private void ThenTheScopedRepoIsCalledCorrectly() { - _scopedRepository + ScopedRepository .Verify(x => x.Add("HttpResponseMessage", _response.Data), Times.Once()); } } diff --git a/test/Ocelot.UnitTests/Responder/ResponderMiddlewareTests.cs b/test/Ocelot.UnitTests/Responder/ResponderMiddlewareTests.cs index 36562abc..5c8a4ad9 100644 --- a/test/Ocelot.UnitTests/Responder/ResponderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Responder/ResponderMiddlewareTests.cs @@ -1,29 +1,27 @@ -using System.Net.Http; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.DependencyInjection; -using Moq; -using Ocelot.Infrastructure.RequestData; -using Ocelot.Logging; -using Ocelot.Responder; -using Ocelot.Responder.Middleware; -using Ocelot.Responses; -using TestStack.BDDfy; -using Xunit; -using Microsoft.AspNetCore.Builder; -using Shouldly; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using System.Collections.Generic; -using Ocelot.Errors; -using System.Net; -using Ocelot.Headers; - -namespace Ocelot.UnitTests.Responder +namespace Ocelot.UnitTests.Responder { + using System.Net.Http; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Builder; + using Microsoft.AspNetCore.Hosting; + using Microsoft.AspNetCore.Http; + using Microsoft.Extensions.DependencyInjection; + using Moq; + using Ocelot.Errors; + using Ocelot.Headers; + using Ocelot.Logging; + using Ocelot.Responder; + using Ocelot.Responder.Middleware; + using Ocelot.Responses; + using Shouldly; + using System.Collections.Generic; + using System.Net; + using TestStack.BDDfy; + using Xunit; + public class ResponderMiddlewareTests : ServerHostedMiddlewareTest { private readonly IHttpResponder _responder; - private readonly Mock _scopedRepository; private readonly Mock _codeMapper; private readonly Mock _outputHeaderRemover; private HttpStatusCode _httpStatusFromController; @@ -35,10 +33,10 @@ namespace Ocelot.UnitTests.Responder public ResponderMiddlewareTests() { _outputHeaderRemover = new Mock(); - _responder = new HttpContextResponder(_outputHeaderRemover.Object); - _scopedRepository = new Mock(); _codeMapper = new Mock(); + _responder = new HttpContextResponder(_outputHeaderRemover.Object); + GivenTheTestServerIsConfigured(); } @@ -71,7 +69,7 @@ namespace Ocelot.UnitTests.Responder services.AddLogging(); services.AddSingleton(_codeMapper.Object); services.AddSingleton(_responder); - services.AddSingleton(_scopedRepository.Object); + services.AddSingleton(ScopedRepository.Object); } protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) @@ -102,11 +100,11 @@ namespace Ocelot.UnitTests.Responder { _pipelineErrors = pipelineErrors; - _scopedRepository + ScopedRepository .Setup(x => x.Get("OcelotMiddlewareError")) .Returns(new OkResponse(_pipelineErrors.Count != 0)); - _scopedRepository + ScopedRepository .Setup(sr => sr.Get>("OcelotMiddlewareErrors")) .Returns(new OkResponse>(_pipelineErrors)); } @@ -114,7 +112,7 @@ namespace Ocelot.UnitTests.Responder private void GivenTheIncomingHttpResponseMessageIs(HttpResponseMessage response) { _response = new OkResponse(response); - _scopedRepository + ScopedRepository .Setup(x => x.Get(It.IsAny())) .Returns(_response); } diff --git a/test/Ocelot.UnitTests/HostedMiddlewareTest.cs b/test/Ocelot.UnitTests/ServerHostedMiddlewareTest.cs similarity index 89% rename from test/Ocelot.UnitTests/HostedMiddlewareTest.cs rename to test/Ocelot.UnitTests/ServerHostedMiddlewareTest.cs index 8409588d..29a012b9 100644 --- a/test/Ocelot.UnitTests/HostedMiddlewareTest.cs +++ b/test/Ocelot.UnitTests/ServerHostedMiddlewareTest.cs @@ -7,6 +7,8 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.AspNetCore.Builder; + using Moq; + using Ocelot.Infrastructure.RequestData; public abstract class ServerHostedMiddlewareTest : IDisposable { @@ -14,10 +16,12 @@ protected HttpClient Client { get; private set; } protected string Url { get; private set; } protected HttpResponseMessage ResponseMessage { get; private set; } + protected Mock ScopedRepository { get; private set; } public ServerHostedMiddlewareTest() { Url = "http://localhost:51879"; + ScopedRepository = new Mock(); } protected virtual void GivenTheTestServerIsConfigured() From ca4efa5e10651fb2d5c243aa136b56f4dac608cc Mon Sep 17 00:00:00 2001 From: Philip Wood Date: Tue, 18 Jul 2017 11:11:24 +0100 Subject: [PATCH 32/35] Back out of some of the functional changes to the ResponderMiddleware tests... I'll look at these again once the consolidation changes are merged. --- .../Responder/ResponderMiddlewareTests.cs | 87 ++--------- .../Responder/ResponderMiddlewareTestsV2.cs | 140 ------------------ 2 files changed, 11 insertions(+), 216 deletions(-) delete mode 100644 test/Ocelot.UnitTests/Responder/ResponderMiddlewareTestsV2.cs diff --git a/test/Ocelot.UnitTests/Responder/ResponderMiddlewareTests.cs b/test/Ocelot.UnitTests/Responder/ResponderMiddlewareTests.cs index 5c8a4ad9..3cfa00e5 100644 --- a/test/Ocelot.UnitTests/Responder/ResponderMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Responder/ResponderMiddlewareTests.cs @@ -1,62 +1,34 @@ namespace Ocelot.UnitTests.Responder { using System.Net.Http; - using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; - using Microsoft.AspNetCore.Hosting; - using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Moq; - using Ocelot.Errors; - using Ocelot.Headers; using Ocelot.Logging; using Ocelot.Responder; using Ocelot.Responder.Middleware; using Ocelot.Responses; - using Shouldly; - using System.Collections.Generic; - using System.Net; using TestStack.BDDfy; using Xunit; public class ResponderMiddlewareTests : ServerHostedMiddlewareTest { - private readonly IHttpResponder _responder; + private readonly Mock _responder; private readonly Mock _codeMapper; - private readonly Mock _outputHeaderRemover; - private HttpStatusCode _httpStatusFromController; - private string _contentFromController; - private OkResponse _response; - private List _pipelineErrors; public ResponderMiddlewareTests() { - _outputHeaderRemover = new Mock(); + _responder = new Mock(); _codeMapper = new Mock(); - _responder = new HttpContextResponder(_outputHeaderRemover.Object); - GivenTheTestServerIsConfigured(); } [Fact] - public void PipelineErrors() + public void should_not_return_any_errors() { - var responseMessage = new HttpResponseMessage(System.Net.HttpStatusCode.Continue); - - this.Given(x => x.GivenTheIncomingHttpResponseMessageIs(new HttpResponseMessage())) - .And(x => x.GivenThereArePipelineErrors()) - .And(x => x.GivenTheErrorWillBeMappedToAnHttpStatus()) - .When(x => x.WhenICallTheMiddleware()) - .Then(x => x.ThenThereAreErrors()) - .BDDfy(); - } - - [Fact] - public void NoPipelineErrors() - { - this.Given(x => x.GivenTheIncomingHttpResponseMessageIs(new HttpResponseMessage())) + this.Given(x => x.GivenTheHttpResponseMessageIs(new HttpResponseMessage())) .And(x => x.GivenThereAreNoPipelineErrors()) .When(x => x.WhenICallTheMiddleware()) .Then(x => x.ThenThereAreNoErrors()) @@ -68,48 +40,16 @@ services.AddSingleton(); services.AddLogging(); services.AddSingleton(_codeMapper.Object); - services.AddSingleton(_responder); + services.AddSingleton(_responder.Object); services.AddSingleton(ScopedRepository.Object); } protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) { app.UseResponderMiddleware(); - app.Run(SetControllerResponse); } - private async Task SetControllerResponse(HttpContext context) - { - _httpStatusFromController = HttpStatusCode.OK; - _contentFromController = "test response"; - context.Response.StatusCode = (int)_httpStatusFromController; - await context.Response.WriteAsync(_contentFromController); - } - - private void GivenThereAreNoPipelineErrors() - { - GivenThereArePipelineErrors(new List()); - } - - private void GivenThereArePipelineErrors() - { - GivenThereArePipelineErrors(new List() { new AnyError() }); - } - - private void GivenThereArePipelineErrors(List pipelineErrors) - { - _pipelineErrors = pipelineErrors; - - ScopedRepository - .Setup(x => x.Get("OcelotMiddlewareError")) - .Returns(new OkResponse(_pipelineErrors.Count != 0)); - - ScopedRepository - .Setup(sr => sr.Get>("OcelotMiddlewareErrors")) - .Returns(new OkResponse>(_pipelineErrors)); - } - - private void GivenTheIncomingHttpResponseMessageIs(HttpResponseMessage response) + private void GivenTheHttpResponseMessageIs(HttpResponseMessage response) { _response = new OkResponse(response); ScopedRepository @@ -117,21 +57,16 @@ .Returns(_response); } - private void GivenTheErrorWillBeMappedToAnHttpStatus() + private void GivenThereAreNoPipelineErrors() { - _codeMapper.Setup(cm => cm.Map(_pipelineErrors)) - .Returns((int)HttpStatusCode.InternalServerError); + ScopedRepository + .Setup(x => x.Get(It.IsAny())) + .Returns(new OkResponse(false)); } private void ThenThereAreNoErrors() { - ResponseMessage.StatusCode.ShouldBe(_httpStatusFromController); - ResponseMessage.Content.ReadAsStringAsync().Result.ShouldBe(_contentFromController); - } - - private void ThenThereAreErrors() - { - ResponseMessage.StatusCode.ShouldBe(System.Net.HttpStatusCode.BadRequest); + //todo a better assert? } } } diff --git a/test/Ocelot.UnitTests/Responder/ResponderMiddlewareTestsV2.cs b/test/Ocelot.UnitTests/Responder/ResponderMiddlewareTestsV2.cs deleted file mode 100644 index ff0bc036..00000000 --- a/test/Ocelot.UnitTests/Responder/ResponderMiddlewareTestsV2.cs +++ /dev/null @@ -1,140 +0,0 @@ -using System.Collections.Generic; -using System.Net.Http; -using Microsoft.AspNetCore.Http; -using Moq; -using Ocelot.Infrastructure.RequestData; -using Ocelot.Errors; -using Ocelot.Logging; -using Ocelot.Responder; -using Ocelot.Responder.Middleware; -using Ocelot.Responses; -using TestStack.BDDfy; -using Xunit; - -namespace Ocelot.UnitTests.Responder -{ - public class ResponderMiddlewareTestsV2 - { - private readonly ResponderMiddleware _middleware; - private readonly Mock _responder; - private readonly Mock _scopedRepository; - private readonly Mock _codeMapper; - private readonly Mock _next; - private readonly Mock _loggerFactory; - private readonly Mock _logger; - private readonly Mock _httpContext; - private OkResponse _response; - private int _mappedStatusCode; - private List _pipelineErrors; - - public ResponderMiddlewareTestsV2() - { - _responder = new Mock(); - _codeMapper = new Mock(); - _next = new Mock(); - _logger = new Mock(); - _scopedRepository = new Mock(); - _loggerFactory = new Mock(); - _httpContext = new Mock(); - - _loggerFactory - .Setup(lf => lf.CreateLogger()) - .Returns(_logger.Object); - - _middleware = new ResponderMiddleware(_next.Object, _responder.Object, _loggerFactory.Object, _scopedRepository.Object, _codeMapper.Object); - - GivenTheHttpResponseMessageIs(new HttpResponseMessage()); - } - - [Fact] - public void NoPipelineErrors() - { - this.Given(x => x.GivenThereAreNoPipelineErrors()) - .When(x => x.WhenICallTheMiddleware()) - .Then(_ => ThenTheNextMiddlewareIsCalled()) - .And(x => x.ThenThereAreNoErrorsOnTheHttpContext()) - .BDDfy(); - } - - [Fact] - public void PipelineErrors() - { - this.Given(_ => GivenThereArePipelineErrors()) - .And(_ => GivenTheErrorsCanBeMappedToAStatusCode()) - .When(_ => WhenICallTheMiddleware()) - .Then(_ => ThenTheNextMiddlewareIsCalled()) - .And(x => x.ThenTheErrorsAreLogged()) - .And(_ => ThenTheErrorsAreMappedToAnHttpStatus()) - .And(_ => ThenAnErrorResponseIsSetOnTheHttpContext()) - .BDDfy(); - } - - private void GivenTheHttpResponseMessageIs(HttpResponseMessage response) - { - _response = new OkResponse(response); - _scopedRepository - .Setup(x => x.Get(It.IsAny())) - .Returns(_response); - } - - private void GivenThereAreNoPipelineErrors() - { - GivenThereArePipelineErrors(new List()); - } - - private void GivenThereArePipelineErrors() - { - GivenThereArePipelineErrors(new List() { new AnyError() }); - } - - private void GivenThereArePipelineErrors(List pipelineErrors) - { - _pipelineErrors = pipelineErrors; - - _scopedRepository - .Setup(x => x.Get("OcelotMiddlewareError")) - .Returns(new OkResponse(_pipelineErrors.Count != 0)); - - _scopedRepository - .Setup(sr => sr.Get>("OcelotMiddlewareErrors")) - .Returns(new OkResponse>(_pipelineErrors)); - } - - private void GivenTheErrorsCanBeMappedToAStatusCode() - { - _mappedStatusCode = 500; //TODO: autofixture - _codeMapper.Setup(cm => cm.Map(It.IsAny>())) - .Returns(_mappedStatusCode); - } - - private void WhenICallTheMiddleware() - { - _middleware.Invoke(_httpContext.Object).GetAwaiter().GetResult(); - } - - private void ThenTheNextMiddlewareIsCalled() - { - _next.Verify(n => n(_httpContext.Object), Times.Once); - } - - private void ThenTheErrorsAreMappedToAnHttpStatus() - { - _codeMapper.Verify(cm => cm.Map(_pipelineErrors), Times.Once); - } - - private void ThenTheErrorsAreLogged() - { - _logger.Verify(l => l.LogError($"{_pipelineErrors.Count} pipeline errors found in ResponderMiddleware. Setting error response status code"), Times.Once); - } - - private void ThenThereAreNoErrorsOnTheHttpContext() - { - _responder.Verify(r => r.SetErrorResponseOnContext(It.IsAny(), It.IsAny()), Times.Never); - } - - private void ThenAnErrorResponseIsSetOnTheHttpContext() - { - _responder.Verify(r => r.SetErrorResponseOnContext(_httpContext.Object, _mappedStatusCode), Times.Once); - } - } -} From de5ae05bd647d5dc218a9d4829d64d40a959ede9 Mon Sep 17 00:00:00 2001 From: Philip Wood Date: Tue, 18 Jul 2017 11:57:48 +0100 Subject: [PATCH 33/35] Refactor ExceptionHandlerMiddleware tests to use base class. --- .../Errors/ExceptionHandlerMiddlewareTests.cs | 148 +++++++----------- 1 file changed, 55 insertions(+), 93 deletions(-) diff --git a/test/Ocelot.UnitTests/Errors/ExceptionHandlerMiddlewareTests.cs b/test/Ocelot.UnitTests/Errors/ExceptionHandlerMiddlewareTests.cs index ac786ec1..5bf848cd 100644 --- a/test/Ocelot.UnitTests/Errors/ExceptionHandlerMiddlewareTests.cs +++ b/test/Ocelot.UnitTests/Errors/ExceptionHandlerMiddlewareTests.cs @@ -1,125 +1,87 @@ -using System; -using System.IO; -using System.Net; -using System.Net.Http; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; -using Moq; -using Ocelot.Errors.Middleware; -using Ocelot.Infrastructure.RequestData; -using Ocelot.Logging; -using Shouldly; -using TestStack.BDDfy; -using Xunit; -using System.Threading.Tasks; - namespace Ocelot.UnitTests.Errors { - public class ExceptionHandlerMiddlewareTests + using System; + using System.Net; + using System.Threading.Tasks; + using Microsoft.AspNetCore.Builder; + using Microsoft.Extensions.DependencyInjection; + using Ocelot.Errors.Middleware; + using Ocelot.Logging; + using Shouldly; + using TestStack.BDDfy; + using Xunit; + using Microsoft.AspNetCore.Http; + + public class ExceptionHandlerMiddlewareTests : ServerHostedMiddlewareTest { - private readonly Mock _scopedRepository; - private readonly string _url; - private TestServer _server; - private HttpClient _client; - private HttpResponseMessage _result; + bool _shouldThrowAnException = false; public ExceptionHandlerMiddlewareTests() { - _url = "http://localhost:52879"; - _scopedRepository = new Mock(); + GivenTheTestServerIsConfigured(); } [Fact] - public void should_call_next_middleware() + public void NoDownstreamException() { - this.Given(_ => GivenASuccessfulRequest()) - .When(_ => WhenIMakeTheRequest()) + this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream()) + .When(_ => WhenICallTheMiddleware()) .Then(_ => ThenTheResponseIsOk()) .BDDfy(); } [Fact] - public void should_call_return_error() + public void DownstreamException() { - this.Given(_ => GivenAnError()) - .When(_ => WhenIMakeTheRequest()) + this.Given(_ => GivenAnExceptionWillBeThrownDownstream()) + .When(_ => WhenICallTheMiddleware()) .Then(_ => ThenTheResponseIsError()) .BDDfy(); } - private void GivenAnError() + protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services) { - var builder = new WebHostBuilder() - .ConfigureServices(x => - { - x.AddSingleton(); - x.AddLogging(); - x.AddSingleton(_scopedRepository.Object); - }) - .UseUrls(_url) - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseUrls(_url) - .Configure(app => - { - app.UseExceptionHandlerMiddleware(); - app.Use(async (context, next) => - { - await Task.CompletedTask; - throw new Exception("BOOM"); - }); - }); + services.AddSingleton(); + services.AddLogging(); + services.AddSingleton(ScopedRepository.Object); + } - _server = new TestServer(builder); - _client = _server.CreateClient(); + protected override void GivenTheTestServerPipelineIsConfigured(IApplicationBuilder app) + { + app.UseExceptionHandlerMiddleware(); + app.Run(DownstreamExceptionSimulator); + } + + private async Task DownstreamExceptionSimulator(HttpContext context) + { + await Task.CompletedTask; + + if (_shouldThrowAnException) + { + throw new Exception("BOOM"); + } + + context.Response.StatusCode = (int)HttpStatusCode.OK; + } + + private void GivenAnExceptionWillNotBeThrownDownstream() + { + _shouldThrowAnException = false; + } + + private void GivenAnExceptionWillBeThrownDownstream() + { + _shouldThrowAnException = true; } private void ThenTheResponseIsOk() { - _result.StatusCode.ShouldBe(HttpStatusCode.OK); + ResponseMessage.StatusCode.ShouldBe(HttpStatusCode.OK); } - private void ThenTheResponseIsError() + private void ThenTheResponseIsError() { - _result.StatusCode.ShouldBe(HttpStatusCode.InternalServerError); + ResponseMessage.StatusCode.ShouldBe(HttpStatusCode.InternalServerError); } - - private void WhenIMakeTheRequest() - { - _result = _client.GetAsync("/").Result; - } - - private void GivenASuccessfulRequest() - { - var builder = new WebHostBuilder() - .ConfigureServices(x => - { - x.AddSingleton(); - x.AddLogging(); - x.AddSingleton(_scopedRepository.Object); - }) - .UseUrls(_url) - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseUrls(_url) - .Configure(app => - { - app.UseExceptionHandlerMiddleware(); - app.Run(async context => - { - await Task.CompletedTask; - context.Response.StatusCode = 200; - }); - }); - - _server = new TestServer(builder); - _client = _server.CreateClient(); - } - - } } \ No newline at end of file From bd6d4e81bfee0ad090f2778e9ca818b26aaba8a6 Mon Sep 17 00:00:00 2001 From: Philip Wood Date: Tue, 18 Jul 2017 12:10:13 +0100 Subject: [PATCH 34/35] Upped minimum unit test coverage threshold --- build.cake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.cake b/build.cake index 6cacb0f0..9960c588 100644 --- a/build.cake +++ b/build.cake @@ -16,7 +16,7 @@ var artifactsDir = Directory("artifacts"); // unit testing var artifactsForUnitTestsDir = artifactsDir + Directory("UnitTests"); var unitTestAssemblies = @"./test/Ocelot.UnitTests/Ocelot.UnitTests.csproj"; -var minCodeCoverage = 75d; +var minCodeCoverage = 76.4d; var coverallsRepoToken = "coveralls-repo-token-ocelot"; var coverallsRepo = "https://coveralls.io/github/TomPallister/Ocelot"; From 15827c2e45364dd867e82bc2be6beb8ac2ec4f8c Mon Sep 17 00:00:00 2001 From: Philip Wood Date: Tue, 18 Jul 2017 22:57:00 +0100 Subject: [PATCH 35/35] Delete unused file --- .../Responder/HttpContextResponderTests.cs | 98 ------------------- 1 file changed, 98 deletions(-) delete mode 100644 test/Ocelot.UnitTests/Responder/HttpContextResponderTests.cs diff --git a/test/Ocelot.UnitTests/Responder/HttpContextResponderTests.cs b/test/Ocelot.UnitTests/Responder/HttpContextResponderTests.cs deleted file mode 100644 index ad62dcfc..00000000 --- a/test/Ocelot.UnitTests/Responder/HttpContextResponderTests.cs +++ /dev/null @@ -1,98 +0,0 @@ -using Microsoft.AspNetCore.Http; -using Moq; -using Ocelot.Headers; -using Ocelot.Responder; -using Shouldly; -using System; -using System.Collections.Generic; -using System.Net.Http; -using System.Text; -using TestStack.BDDfy; -using Xunit; -using System.IO; -using System.Net; -using System.Threading.Tasks; - -namespace Ocelot.UnitTests.Responder -{ - public class HttpContextResponderTests - { - readonly HttpContextResponder _responder; - - readonly Mock _removeOutputHeaders; - - HttpContext _httpContext; - - HttpResponseMessage _httpResponseMessage; - - public HttpContextResponderTests() - { - _removeOutputHeaders = new Mock(); - _httpContext = new DefaultHttpContext(); - _httpResponseMessage = new HttpResponseMessage(); - _httpResponseMessage.Content = new MyHttpContent(); - _responder = new HttpContextResponder(_removeOutputHeaders.Object); - } - - [Fact] - public void DoSomething() - { - this.Given(_ => GivenTheHttpResponseMessageHasHeader("abc","123")) - .And(_ => GivenTheHttpResponseMessageHasHeader("def", new[] { "456", "789" })) - .And(_ => GivenTheContextResponseHasHeader("abc", "123")) - .When(_ => WhenWeSetTheResponseOnAnHttpContext()) - .Then(_ => ThenSupportedHeadersAreAddedToTheContextResponse()) - .And(_ => ThenUnsupportedHeadersAreNotAddedToTheResponse()) - .BDDfy(); - } - - - private void GivenTheHttpResponseMessageHasHeader(string name, string value) - { - _httpResponseMessage.Headers.Add(name, value); - } - - private void GivenTheHttpResponseMessageHasHeader(string name, IEnumerable values) - { - _httpResponseMessage.Headers.Add(name, values); - } - - private void GivenTheContextResponseHasHeader(string name, string value) - { - _httpContext.Response.Headers.Add(name, value); - } - - private void WhenWeSetTheResponseOnAnHttpContext() - { - _responder.SetResponseOnHttpContext(_httpContext, _httpResponseMessage).GetAwaiter().GetResult(); - } - - private void ThenSupportedHeadersAreAddedToTheContextResponse() - { - _httpContext.Response.Headers.Count.ShouldBe(2); - _httpContext.Response.Headers.ShouldContain(h => h.Key == "abc" && h.Value == "123"); - _httpContext.Response.Headers.ShouldContain(h => h.Key == "def" && h.Value == "456, 789"); - } - - private void ThenUnsupportedHeadersAreNotAddedToTheResponse() - { - _removeOutputHeaders.Verify(roh => roh.Remove(_httpResponseMessage.Headers), Times.Once); - } - - - class MyHttpContent : HttpContent - { - protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) - { - return Task.CompletedTask; - } - - protected override bool TryComputeLength(out long length) - { - length = 0; - return true; - } - } - - } -}