Merge pull request #20 from geffzhang/develop

merge newest code
This commit is contained in:
geffzhang 2017-04-03 21:06:00 +08:00 committed by GitHub
commit 34325d7969
18 changed files with 358 additions and 166 deletions

View File

@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Http;
using Ocelot.Authentication.Handler.Factory; using Ocelot.Authentication.Handler.Factory;
using Ocelot.Configuration; using Ocelot.Configuration;
using Ocelot.Errors; using Ocelot.Errors;
using Ocelot.Infrastructure.Extensions;
using Ocelot.Infrastructure.RequestData; using Ocelot.Infrastructure.RequestData;
using Ocelot.Logging; using Ocelot.Logging;
using Ocelot.Middleware; using Ocelot.Middleware;
@ -33,47 +34,57 @@ namespace Ocelot.Authentication.Middleware
public async Task Invoke(HttpContext context) public async Task Invoke(HttpContext context)
{ {
_logger.LogDebug("started authentication"); _logger.TraceMiddlewareEntry();
if (IsAuthenticatedRoute(DownstreamRoute.ReRoute)) if (IsAuthenticatedRoute(DownstreamRoute.ReRoute))
{ {
_logger.LogDebug($"{context.Request.Path} is an authenticated route. {MiddlwareName} checking if client is authenticated");
var authenticationHandler = _authHandlerFactory.Get(_app, DownstreamRoute.ReRoute.AuthenticationOptions); var authenticationHandler = _authHandlerFactory.Get(_app, DownstreamRoute.ReRoute.AuthenticationOptions);
if (!authenticationHandler.IsError) if (authenticationHandler.IsError)
{ {
_logger.LogDebug("calling authentication handler for ReRoute"); _logger.LogError($"Error getting authentication handler for {context.Request.Path}. {authenticationHandler.Errors.ToErrorString()}");
await authenticationHandler.Data.Handler.Handle(context);
}
else
{
_logger.LogDebug("there was an error getting authentication handler for ReRoute");
SetPipelineError(authenticationHandler.Errors); SetPipelineError(authenticationHandler.Errors);
_logger.TraceMiddlewareCompleted();
return;
} }
await authenticationHandler.Data.Handler.Handle(context);
if (context.User.Identity.IsAuthenticated) if (context.User.Identity.IsAuthenticated)
{ {
_logger.LogDebug("the user was authenticated"); _logger.LogDebug($"Client has been authenticated for {context.Request.Path}");
await _next.Invoke(context); _logger.TraceInvokeNext();
await _next.Invoke(context);
_logger.LogDebug("succesfully called next middleware"); _logger.TraceInvokeNextCompleted();
_logger.TraceMiddlewareCompleted();
} }
else else
{ {
_logger.LogDebug("the user was not authenticated"); var error = new List<Error>
{
new UnauthenticatedError(
$"Request for authenticated route {context.Request.Path} by {context.User.Identity.Name} was unauthenticated")
};
SetPipelineError(new List<Error> { new UnauthenticatedError($"Request for authenticated route {context.Request.Path} by {context.User.Identity.Name} was unauthenticated") }); _logger.LogError($"Client has NOT been authenticated for {context.Request.Path} and pipeline error set. {error.ToErrorString()}");
SetPipelineError(error);
_logger.TraceMiddlewareCompleted();
return;
} }
} }
else else
{ {
_logger.LogDebug("calling next middleware"); _logger.LogTrace($"No authentication needed for {context.Request.Path}");
await _next.Invoke(context); _logger.TraceInvokeNext();
await _next.Invoke(context);
_logger.LogDebug("succesfully called next middleware"); _logger.TraceInvokeNextCompleted();
_logger.TraceMiddlewareCompleted();
} }
} }
@ -83,3 +94,4 @@ namespace Ocelot.Authentication.Middleware
} }
} }
} }

View File

@ -9,6 +9,7 @@ using Ocelot.Configuration.File;
using Ocelot.Configuration.Parser; using Ocelot.Configuration.Parser;
using Ocelot.Configuration.Validator; using Ocelot.Configuration.Validator;
using Ocelot.LoadBalancer.LoadBalancers; using Ocelot.LoadBalancer.LoadBalancers;
using Ocelot.Logging;
using Ocelot.Requester.QoS; using Ocelot.Requester.QoS;
using Ocelot.Responses; using Ocelot.Responses;
using Ocelot.Utilities; using Ocelot.Utilities;
@ -22,7 +23,7 @@ namespace Ocelot.Configuration.Creator
{ {
private readonly IOptions<FileConfiguration> _options; private readonly IOptions<FileConfiguration> _options;
private readonly IConfigurationValidator _configurationValidator; private readonly IConfigurationValidator _configurationValidator;
private readonly ILogger<FileOcelotConfigurationCreator> _logger; private readonly IOcelotLogger _logger;
private readonly ILoadBalancerFactory _loadBalanceFactory; private readonly ILoadBalancerFactory _loadBalanceFactory;
private readonly ILoadBalancerHouse _loadBalancerHouse; private readonly ILoadBalancerHouse _loadBalancerHouse;
private readonly IQoSProviderFactory _qoSProviderFactory; private readonly IQoSProviderFactory _qoSProviderFactory;
@ -39,7 +40,7 @@ namespace Ocelot.Configuration.Creator
public FileOcelotConfigurationCreator( public FileOcelotConfigurationCreator(
IOptions<FileConfiguration> options, IOptions<FileConfiguration> options,
IConfigurationValidator configurationValidator, IConfigurationValidator configurationValidator,
ILogger<FileOcelotConfigurationCreator> logger, IOcelotLoggerFactory loggerFactory,
ILoadBalancerFactory loadBalancerFactory, ILoadBalancerFactory loadBalancerFactory,
ILoadBalancerHouse loadBalancerHouse, ILoadBalancerHouse loadBalancerHouse,
IQoSProviderFactory qoSProviderFactory, IQoSProviderFactory qoSProviderFactory,
@ -64,7 +65,7 @@ namespace Ocelot.Configuration.Creator
_qosProviderHouse = qosProviderHouse; _qosProviderHouse = qosProviderHouse;
_options = options; _options = options;
_configurationValidator = configurationValidator; _configurationValidator = configurationValidator;
_logger = logger; _logger = loggerFactory.CreateLogger<FileOcelotConfigurationCreator>();
_claimsToThingCreator = claimsToThingCreator; _claimsToThingCreator = claimsToThingCreator;
_serviceProviderConfigCreator = serviceProviderConfigCreator; _serviceProviderConfigCreator = serviceProviderConfigCreator;
_qosOptionsCreator = qosOptionsCreator; _qosOptionsCreator = qosOptionsCreator;

View File

@ -1,6 +1,9 @@
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Ocelot.DownstreamRouteFinder.Finder; using Ocelot.DownstreamRouteFinder.Finder;
using Ocelot.Infrastructure.Extensions;
using Ocelot.Infrastructure.RequestData; using Ocelot.Infrastructure.RequestData;
using Ocelot.Logging; using Ocelot.Logging;
using Ocelot.Middleware; using Ocelot.Middleware;
@ -27,7 +30,7 @@ namespace Ocelot.DownstreamRouteFinder.Middleware
public async Task Invoke(HttpContext context) public async Task Invoke(HttpContext context)
{ {
_logger.LogDebug("started calling downstream route finder middleware"); _logger.TraceMiddlewareEntry();
var upstreamUrlPath = context.Request.Path.ToString().SetLastCharacterAs('/'); var upstreamUrlPath = context.Request.Path.ToString().SetLastCharacterAs('/');
@ -37,9 +40,11 @@ namespace Ocelot.DownstreamRouteFinder.Middleware
if (downstreamRoute.IsError) if (downstreamRoute.IsError)
{ {
_logger.LogDebug("IDownstreamRouteFinder returned an error, setting pipeline error"); _logger.LogError($"{MiddlwareName} setting pipeline errors. IDownstreamRouteFinder returned {downstreamRoute.Errors.ToErrorString()}");
SetPipelineError(downstreamRoute.Errors); SetPipelineError(downstreamRoute.Errors);
_logger.TraceMiddlewareCompleted();
return; return;
} }
@ -47,12 +52,12 @@ namespace Ocelot.DownstreamRouteFinder.Middleware
SetDownstreamRouteForThisRequest(downstreamRoute.Data); SetDownstreamRouteForThisRequest(downstreamRoute.Data);
_logger.LogDebug("calling next middleware"); _logger.TraceInvokeNext();
await _next.Invoke(context); await _next.Invoke(context);
_logger.LogDebug("succesfully called next middleware"); _logger.TraceInvokeNextCompleted();
_logger.TraceMiddlewareCompleted();
} }
} }
} }

View File

@ -6,6 +6,9 @@ using Ocelot.Logging;
namespace Ocelot.Errors.Middleware namespace Ocelot.Errors.Middleware
{ {
/// <summary>
/// Catches all unhandled exceptions thrown by middleware, logs and returns a 500
/// </summary>
public class ExceptionHandlerMiddleware public class ExceptionHandlerMiddleware
{ {
private readonly RequestDelegate _next; private readonly RequestDelegate _next;

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Extensions.Primitives;
using Ocelot.Errors;
namespace Ocelot.Infrastructure.Extensions
{
public static class ErrorListExtensions
{
public static string ToErrorString(this List<Error> errors)
{
var listOfErrorStrings = errors.Select(x => "Error Code: " + x.Code.ToString() + " Message: " + x.Message);
return string.Join(" ", listOfErrorStrings);
}
}
}

View File

@ -0,0 +1,52 @@
using System;
using Microsoft.Extensions.Logging;
using Ocelot.Infrastructure.RequestData;
namespace Ocelot.Logging
{
public class AspDotNetLogger : IOcelotLogger
{
private readonly ILogger _logger;
private readonly IRequestScopedDataRepository _scopedDataRepository;
public string Name { get; }
public AspDotNetLogger(ILogger logger, IRequestScopedDataRepository scopedDataRepository, string typeName)
{
Name = typeName;
_logger = logger;
_scopedDataRepository = scopedDataRepository;
}
public void LogTrace(string message, params object[] args)
{
_logger.LogTrace(GetMessageWithOcelotRequestId(message), args);
}
public void LogDebug(string message, params object[] args)
{
_logger.LogDebug(GetMessageWithOcelotRequestId(message), args);
}
public void LogError(string message, Exception exception)
{
_logger.LogError(GetMessageWithOcelotRequestId(message), exception);
}
public void LogError(string message, params object[] args)
{
_logger.LogError(GetMessageWithOcelotRequestId(message), args);
}
private string GetMessageWithOcelotRequestId(string message)
{
var requestId = _scopedDataRepository.Get<string>("RequestId");
if (requestId == null || requestId.IsError)
{
return $"{message} : OcelotRequestId - not set";
}
return $"{message} : OcelotRequestId - {requestId.Data}";
}
}
}

View File

@ -0,0 +1,23 @@
using Microsoft.Extensions.Logging;
using Ocelot.Infrastructure.RequestData;
namespace Ocelot.Logging
{
public class AspDotNetLoggerFactory : IOcelotLoggerFactory
{
private readonly ILoggerFactory _loggerFactory;
private readonly IRequestScopedDataRepository _scopedDataRepository;
public AspDotNetLoggerFactory(ILoggerFactory loggerFactory, IRequestScopedDataRepository scopedDataRepository)
{
_loggerFactory = loggerFactory;
_scopedDataRepository = scopedDataRepository;
}
public IOcelotLogger CreateLogger<T>()
{
var logger = _loggerFactory.CreateLogger<T>();
return new AspDotNetLogger(logger, _scopedDataRepository, typeof(T).Name);
}
}
}

View File

@ -1,6 +1,4 @@
using System; using System;
using Microsoft.Extensions.Logging;
using Ocelot.Infrastructure.RequestData;
namespace Ocelot.Logging namespace Ocelot.Logging
{ {
@ -8,62 +6,19 @@ namespace Ocelot.Logging
{ {
IOcelotLogger CreateLogger<T>(); IOcelotLogger CreateLogger<T>();
} }
/// <summary>
public class AspDotNetLoggerFactory : IOcelotLoggerFactory /// Thin wrapper around the DotNet core logging framework, used to allow the scopedDataRepository to be injected giving access to the Ocelot RequestId
{ /// </summary>
private readonly ILoggerFactory _loggerFactory;
private readonly IRequestScopedDataRepository _scopedDataRepository;
public AspDotNetLoggerFactory(ILoggerFactory loggerFactory, IRequestScopedDataRepository scopedDataRepository)
{
_loggerFactory = loggerFactory;
_scopedDataRepository = scopedDataRepository;
}
public IOcelotLogger CreateLogger<T>()
{
var logger = _loggerFactory.CreateLogger<T>();
return new AspDotNetLogger(logger, _scopedDataRepository);
}
}
public interface IOcelotLogger public interface IOcelotLogger
{ {
void LogTrace(string message, params object[] args);
void LogDebug(string message, params object[] args); void LogDebug(string message, params object[] args);
void LogError(string message, Exception exception); void LogError(string message, Exception exception);
} void LogError(string message, params object[] args);
public class AspDotNetLogger : IOcelotLogger /// <summary>
{ /// The name of the type the logger has been built for.
private readonly ILogger _logger; /// </summary>
private readonly IRequestScopedDataRepository _scopedDataRepository; string Name { get; }
public AspDotNetLogger(ILogger logger, IRequestScopedDataRepository scopedDataRepository)
{
_logger = logger;
_scopedDataRepository = scopedDataRepository;
}
public void LogDebug(string message, params object[] args)
{
_logger.LogDebug(GetMessageWithOcelotRequestId(message), args);
}
public void LogError(string message, Exception exception)
{
_logger.LogError(GetMessageWithOcelotRequestId(message), exception);
}
private string GetMessageWithOcelotRequestId(string message)
{
var requestId = _scopedDataRepository.Get<string>("RequestId");
if (requestId != null && !requestId.IsError)
{
return $"{message} : OcelotRequestId - {requestId.Data}";
}
return $"{message} : OcelotRequestId - not set";
}
} }
} }

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Ocelot.Logging
{
public static class OcelotLoggerExtensions
{
public static void TraceMiddlewareEntry(this IOcelotLogger logger)
{
logger.LogTrace($"entered {logger.Name}");
}
public static void TraceInvokeNext(this IOcelotLogger logger)
{
logger.LogTrace($"invoking next middleware from {logger.Name}");
}
public static void TraceInvokeNextCompleted(this IOcelotLogger logger)
{
logger.LogTrace($"returned to {logger.Name} after next middleware completed");
}
public static void TraceMiddlewareCompleted(this IOcelotLogger logger)
{
logger.LogTrace($"completed {logger.Name}");
}
}
}

View File

@ -14,8 +14,11 @@ namespace Ocelot.Middleware
protected OcelotMiddleware(IRequestScopedDataRepository requestScopedDataRepository) protected OcelotMiddleware(IRequestScopedDataRepository requestScopedDataRepository)
{ {
_requestScopedDataRepository = requestScopedDataRepository; _requestScopedDataRepository = requestScopedDataRepository;
MiddlwareName = this.GetType().Name;
} }
public string MiddlwareName { get; }
public bool PipelineError public bool PipelineError
{ {
get get

View File

@ -31,12 +31,18 @@ namespace Ocelot.RateLimit.Middleware
public async Task Invoke(HttpContext context) public async Task Invoke(HttpContext context)
{ {
_logger.LogDebug("started calling RateLimit middleware"); _logger.TraceMiddlewareEntry();
var options = DownstreamRoute.ReRoute.RateLimitOptions; var options = DownstreamRoute.ReRoute.RateLimitOptions;
// check if rate limiting is enabled // check if rate limiting is enabled
if (!DownstreamRoute.ReRoute.EnableEndpointRateLimiting) if (!DownstreamRoute.ReRoute.EnableEndpointRateLimiting)
{ {
await _next.Invoke(context); _logger.LogDebug($"EndpointRateLimiting is not enabled for {DownstreamRoute.ReRoute.DownstreamPathTemplate}");
_logger.TraceInvokeNext();
await _next.Invoke(context);
_logger.TraceInvokeNextCompleted();
_logger.TraceMiddlewareCompleted();
return; return;
} }
// compute identity from request // compute identity from request
@ -45,7 +51,12 @@ namespace Ocelot.RateLimit.Middleware
// check white list // check white list
if (IsWhitelisted(identity, options)) if (IsWhitelisted(identity, options))
{ {
await _next.Invoke(context); _logger.LogDebug($"{DownstreamRoute.ReRoute.DownstreamPathTemplate} is white listed from rate limiting");
_logger.TraceInvokeNext();
await _next.Invoke(context);
_logger.TraceInvokeNextCompleted();
_logger.TraceMiddlewareCompleted();
return; return;
} }
@ -66,6 +77,7 @@ namespace Ocelot.RateLimit.Middleware
// break execution // break execution
await ReturnQuotaExceededResponse(context, options, retryAfter); await ReturnQuotaExceededResponse(context, options, retryAfter);
_logger.TraceMiddlewareCompleted();
return; return;
} }
} }
@ -76,7 +88,10 @@ namespace Ocelot.RateLimit.Middleware
context.Response.OnStarting(SetRateLimitHeaders, state: headers); context.Response.OnStarting(SetRateLimitHeaders, state: headers);
} }
await _next.Invoke(context); _logger.TraceInvokeNext();
await _next.Invoke(context);
_logger.TraceInvokeNextCompleted();
_logger.TraceMiddlewareCompleted();
} }
public virtual ClientRequestIdentity SetIdentity(HttpContext httpContext, RateLimitOptions option) public virtual ClientRequestIdentity SetIdentity(HttpContext httpContext, RateLimitOptions option)

View File

@ -26,17 +26,16 @@ namespace Ocelot.RequestId.Middleware
public async Task Invoke(HttpContext context) public async Task Invoke(HttpContext context)
{ {
_logger.LogDebug("started calling request id middleware"); _logger.TraceMiddlewareEntry();
SetOcelotRequestId(context); SetOcelotRequestId(context);
_logger.LogDebug("set request id"); _logger.LogDebug("set requestId");
_logger.LogDebug("calling next middleware"); _logger.TraceInvokeNext();
await _next.Invoke(context);
await _next.Invoke(context); _logger.TraceInvokeNextCompleted();
_logger.TraceMiddlewareCompleted();
_logger.LogDebug("succesfully called next middleware");
} }
private void SetOcelotRequestId(HttpContext context) private void SetOcelotRequestId(HttpContext context)

View File

@ -26,6 +26,11 @@ namespace Ocelot.Responder
return 503; return 503;
} }
if (errors.Any(e => e.Code == OcelotErrorCode.UnableToFindDownstreamRouteError))
{
return 404;
}
return 404; return 404;
} }
} }

View File

@ -1,7 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Ocelot.Errors; using Ocelot.Errors;
using Ocelot.Infrastructure.RequestData; using Ocelot.Infrastructure.RequestData;
using Ocelot.Logging; using Ocelot.Logging;
@ -9,6 +8,9 @@ using Ocelot.Middleware;
namespace Ocelot.Responder.Middleware namespace Ocelot.Responder.Middleware
{ {
/// <summary>
/// Completes and returns the request and request body, if any pipeline errors occured then sets the appropriate HTTP status code instead.
/// </summary>
public class ResponderMiddleware : OcelotMiddleware public class ResponderMiddleware : OcelotMiddleware
{ {
private readonly RequestDelegate _next; private readonly RequestDelegate _next;
@ -21,7 +23,7 @@ namespace Ocelot.Responder.Middleware
IOcelotLoggerFactory loggerFactory, IOcelotLoggerFactory loggerFactory,
IRequestScopedDataRepository requestScopedDataRepository, IRequestScopedDataRepository requestScopedDataRepository,
IErrorsToHttpStatusCodeMapper codeMapper) IErrorsToHttpStatusCodeMapper codeMapper)
: base(requestScopedDataRepository) :base(requestScopedDataRepository)
{ {
_next = next; _next = next;
_responder = responder; _responder = responder;
@ -32,28 +34,24 @@ namespace Ocelot.Responder.Middleware
public async Task Invoke(HttpContext context) public async Task Invoke(HttpContext context)
{ {
_logger.LogDebug("started error responder middleware"); _logger.TraceMiddlewareEntry();
_logger.TraceInvokeNext();
await _next.Invoke(context); await _next.Invoke(context);
_logger.TraceInvokeNextCompleted();
_logger.LogDebug("calling next middleware");
if (PipelineError) if (PipelineError)
{ {
_logger.LogDebug("there is a pipeline error, getting errors");
var errors = PipelineErrors; var errors = PipelineErrors;
_logger.LogError($"{errors.Count} pipeline errors found in {MiddlwareName}. Setting error response status code");
_logger.LogDebug("received errors setting error response");
SetErrorResponse(context, errors); SetErrorResponse(context, errors);
} }
else else
{ {
_logger.LogDebug("no pipeline error, setting response"); _logger.LogDebug("no pipeline errors, setting and returning completed response");
await _responder.SetResponseOnHttpContext(context, HttpResponseMessage); await _responder.SetResponseOnHttpContext(context, HttpResponseMessage);
} }
_logger.TraceMiddlewareCompleted();
} }
private void SetErrorResponse(HttpContext context, List<Error> errors) private void SetErrorResponse(HttpContext context, List<Error> errors)

View File

@ -2,7 +2,7 @@
"Logging": { "Logging": {
"IncludeScopes": true, "IncludeScopes": true,
"LogLevel": { "LogLevel": {
"Default": "Debug", "Default": "Error",
"System": "Information", "System": "Information",
"Microsoft": "Information" "Microsoft": "Information"
} }

View File

@ -2,7 +2,7 @@
"Logging": { "Logging": {
"IncludeScopes": true, "IncludeScopes": true,
"LogLevel": { "LogLevel": {
"Default": "Debug", "Default": "Trace",
"System": "Information", "System": "Information",
"Microsoft": "Information" "Microsoft": "Information"
} }

View File

@ -8,6 +8,7 @@ using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File; using Ocelot.Configuration.File;
using Ocelot.Configuration.Validator; using Ocelot.Configuration.Validator;
using Ocelot.LoadBalancer.LoadBalancers; using Ocelot.LoadBalancer.LoadBalancers;
using Ocelot.Logging;
using Ocelot.Requester.QoS; using Ocelot.Requester.QoS;
using Ocelot.Responses; using Ocelot.Responses;
using Shouldly; using Shouldly;
@ -22,7 +23,7 @@ namespace Ocelot.UnitTests.Configuration
private readonly Mock<IConfigurationValidator> _validator; private readonly Mock<IConfigurationValidator> _validator;
private Response<IOcelotConfiguration> _config; private Response<IOcelotConfiguration> _config;
private FileConfiguration _fileConfiguration; private FileConfiguration _fileConfiguration;
private readonly Mock<ILogger<FileOcelotConfigurationCreator>> _logger; private readonly Mock<IOcelotLoggerFactory> _logger;
private readonly FileOcelotConfigurationCreator _ocelotConfigurationCreator; private readonly FileOcelotConfigurationCreator _ocelotConfigurationCreator;
private readonly Mock<ILoadBalancerFactory> _loadBalancerFactory; private readonly Mock<ILoadBalancerFactory> _loadBalancerFactory;
private readonly Mock<ILoadBalancerHouse> _loadBalancerHouse; private readonly Mock<ILoadBalancerHouse> _loadBalancerHouse;
@ -44,7 +45,7 @@ namespace Ocelot.UnitTests.Configuration
_qosProviderFactory = new Mock<IQoSProviderFactory>(); _qosProviderFactory = new Mock<IQoSProviderFactory>();
_qosProviderHouse = new Mock<IQosProviderHouse>(); _qosProviderHouse = new Mock<IQosProviderHouse>();
_qosProvider = new Mock<IQoSProvider>(); _qosProvider = new Mock<IQoSProvider>();
_logger = new Mock<ILogger<FileOcelotConfigurationCreator>>(); _logger = new Mock<IOcelotLoggerFactory>();
_validator = new Mock<IConfigurationValidator>(); _validator = new Mock<IConfigurationValidator>();
_fileConfig = new Mock<IOptions<FileConfiguration>>(); _fileConfig = new Mock<IOptions<FileConfiguration>>();
_loadBalancerFactory = new Mock<ILoadBalancerFactory>(); _loadBalancerFactory = new Mock<ILoadBalancerFactory>();

View File

@ -0,0 +1,73 @@
using Microsoft.AspNetCore.Http;
using Ocelot.Infrastructure.RequestData;
using Ocelot.Responses;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Infrastructure
{
public class HttpDataRepositoryTests
{
private HttpContext _httpContext;
private IHttpContextAccessor _httpContextAccessor;
private HttpDataRepository _httpDataRepository;
private object _result;
public HttpDataRepositoryTests()
{
_httpContext = new DefaultHttpContext();
_httpContextAccessor = new HttpContextAccessor{HttpContext = _httpContext};
_httpDataRepository = new HttpDataRepository(_httpContextAccessor);
}
//TODO - Additional tests -> Type mistmatch aka Add string, request int
//TODO - Additional tests -> HttpContent null. This should never happen
[Fact]
public void Get_returns_correct_key_from_http_context()
{
this.Given(x => x.GivenAHttpContextContaining("key", "string"))
.When(x => x.GetIsCalledWithKey<string>("key"))
.Then(x => x.ThenTheResultIsAnOkResponse<string>("string"))
.BDDfy();
}
[Fact]
public void Get_returns_error_response_if_the_key_is_not_found() //Therefore does not return null
{
this.Given(x => x.GivenAHttpContextContaining("key", "string"))
.When(x => x.GetIsCalledWithKey<string>("keyDoesNotExist"))
.Then(x => x.ThenTheResultIsAnErrorReposnse<string>("string1"))
.BDDfy();
}
private void GivenAHttpContextContaining(string key, object o)
{
_httpContext.Items.Add(key, o);
}
private void GetIsCalledWithKey<T>(string key)
{
_result = _httpDataRepository.Get<T>(key);
}
private void ThenTheResultIsAnErrorReposnse<T>(object resultValue)
{
_result.ShouldBeOfType<ErrorResponse<T>>();
((ErrorResponse<T>) _result).Data.ShouldBeNull();
((ErrorResponse<T>)_result).IsError.ShouldBe(true);
((ErrorResponse<T>) _result).Errors.ShouldHaveSingleItem()
.ShouldBeOfType<CannotFindDataError>()
.Message.ShouldStartWith("Unable to find data for key: ");
}
private void ThenTheResultIsAnOkResponse<T>(object resultValue)
{
_result.ShouldBeOfType<OkResponse<T>>();
((OkResponse<T>)_result).Data.ShouldBe(resultValue);
}
}
}