Monitoring (#219)

* feat:  use Https://github.com/ButterflyAPM to monitor each API request monitoring metrics

* feat: using DiagnosticSource and Butterfly.OpenTracing

* refactor:refactor Ocelot tracing, merge code into OcelotDiagnosticListener

* refactor: move OcelotHttpTracingHandler to Requester

* fix: Requester\HttpClientBuilder.cs(10,14): error CS0234: The type or namespace name 'Tracing' does not exist in the namespace

* feat: add test should_set_up_tracing

* feat : Remove extraneous code

* feat: remove unused DiagnosticSource diagnostic

* fix : test UseTracing

* add test should_call_scoped_data_repository_QosProviderError

* add test should_return_any_errors

* add test HttpClientHttpRequesterTest

*  it should keep it can not be deleted
This commit is contained in:
geffzhang
2018-02-13 02:33:23 +08:00
committed by Tom Pallister
parent f179b7d0d0
commit ef3c4f614a
30 changed files with 1513 additions and 1211 deletions

View File

@ -471,7 +471,7 @@ namespace Ocelot.UnitTests.Configuration
{
var reRouteOptions = new ReRouteOptionsBuilder()
.Build();
var httpHandlerOptions = new HttpHandlerOptions(true, true);
var httpHandlerOptions = new HttpHandlerOptions(true, true,false);
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
{

View File

@ -23,7 +23,7 @@ namespace Ocelot.UnitTests.Configuration
public void should_create_options_with_useCookie_and_allowAutoRedirect_true_as_default()
{
var fileReRoute = new FileReRoute();
var expectedOptions = new HttpHandlerOptions(true, true);
var expectedOptions = new HttpHandlerOptions(true, true, false);
this.Given(x => GivenTheFollowing(fileReRoute))
.When(x => WhenICreateHttpHandlerOptions())
@ -39,11 +39,12 @@ namespace Ocelot.UnitTests.Configuration
HttpHandlerOptions = new FileHttpHandlerOptions
{
AllowAutoRedirect = false,
UseCookieContainer = false
UseCookieContainer = false,
UseTracing = false
}
};
var expectedOptions = new HttpHandlerOptions(false, false);
var expectedOptions = new HttpHandlerOptions(false, false, false);
this.Given(x => GivenTheFollowing(fileReRoute))
.When(x => WhenICreateHttpHandlerOptions())
@ -66,6 +67,7 @@ namespace Ocelot.UnitTests.Configuration
_httpHandlerOptions.ShouldNotBeNull();
_httpHandlerOptions.AllowAutoRedirect.ShouldBe(options.AllowAutoRedirect);
_httpHandlerOptions.UseCookieContainer.ShouldBe(options.UseCookieContainer);
_httpHandlerOptions.UseTracing.ShouldBe(options.UseTracing);
}
}
}

View File

@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using CacheManager.Core;
using CacheManager.Core;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Internal;
using Microsoft.Extensions.Configuration;
@ -13,8 +8,11 @@ using Ocelot.Configuration;
using Ocelot.Configuration.File;
using Ocelot.Configuration.Setter;
using Ocelot.DependencyInjection;
using Ocelot.Logging;
using Ocelot.Requester;
using Shouldly;
using System;
using System.Collections.Generic;
using System.Linq;
using TestStack.BDDfy;
using Xunit;
@ -96,6 +94,16 @@ namespace Ocelot.UnitTests.DependencyInjection
.BDDfy();
}
[Fact]
public void should_set_up_tracing()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => WhenISetUpOpentracing())
.When(x => WhenIAccessOcelotHttpTracingHandler())
.BDDfy();
}
[Fact]
public void should_set_up_without_passing_in_config()
{
@ -193,6 +201,24 @@ namespace Ocelot.UnitTests.DependencyInjection
}
}
private void WhenISetUpOpentracing()
{
try
{
_ocelotBuilder.AddOpenTracing(
option =>
{
option.CollectorUrl = "http://localhost:9618";
option.Service = "Ocelot.ManualTest";
}
);
}
catch (Exception e)
{
_ex = e;
}
}
private void WhenIAccessLoggerFactory()
{
try
@ -205,6 +231,18 @@ namespace Ocelot.UnitTests.DependencyInjection
}
}
private void WhenIAccessOcelotHttpTracingHandler()
{
try
{
var tracingHandler = _serviceProvider.GetService<OcelotHttpTracingHandler>();
}
catch (Exception e)
{
_ex = e;
}
}
private void WhenIValidateScopes()
{
try

View File

@ -17,6 +17,7 @@
using Ocelot.Requester.QoS;
using Ocelot.Configuration;
using Microsoft.AspNetCore.Builder;
using Ocelot.Errors;
public class HttpRequestBuilderMiddlewareTests : ServerHostedMiddlewareTest
{
@ -51,18 +52,39 @@
new ReRouteBuilder()
.WithRequestIdKey("LSRequestId")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.WithHttpHandlerOptions(new HttpHandlerOptions(true, true))
.WithHttpHandlerOptions(new HttpHandlerOptions(true, true,false))
.Build());
this.Given(x => x.GivenTheDownStreamUrlIs("any old string"))
.And(x => x.GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(new NoQoSProvider())))
.And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
.And(x => x.GivenTheRequestBuilderReturns(new Ocelot.Request.Request(new HttpRequestMessage(), true, new NoQoSProvider(), false, false)))
.And(x => x.GivenTheRequestBuilderReturns(new Ocelot.Request.Request(new HttpRequestMessage(), true, new NoQoSProvider(), false, false,false)))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly())
.BDDfy();
}
[Fact]
public void should_call_scoped_data_repository_QosProviderError()
{
var downstreamRoute = new DownstreamRoute(new List<PlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithRequestIdKey("LSRequestId")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.WithHttpHandlerOptions(new HttpHandlerOptions(true, true, true))
.Build());
this.Given(x => x.GivenTheDownStreamUrlIs("any old string"))
.And(x => x.GivenTheQosProviderHouseReturns(new ErrorResponse<IQoSProvider>(It.IsAny<Error>())))
.And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
.And(x => x.GivenTheRequestBuilderReturns(new Ocelot.Request.Request(new HttpRequestMessage(), true, new NoQoSProvider(), false, false, false)))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheScopedDataRepositoryQosProviderError())
.BDDfy();
}
protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services)
{
services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
@ -109,7 +131,9 @@
It.IsAny<bool>(),
It.IsAny<IQoSProvider>(),
It.IsAny<bool>(),
It.IsAny<bool>()))
It.IsAny<bool>(),
It.IsAny<bool>()
))
.ReturnsAsync(_request);
}
@ -118,5 +142,11 @@
_scopedRepository
.Verify(x => x.Add("Request", _request.Data), Times.Once());
}
private void ThenTheScopedDataRepositoryQosProviderError()
{
_scopedRepository
.Verify(x => x.Add("OcelotMiddlewareError", true), Times.Once());
}
}
}

View File

@ -1,79 +1,86 @@
namespace Ocelot.UnitTests.Request
{
using System.Net.Http;
using Ocelot.Request.Builder;
using Ocelot.Requester.QoS;
using Ocelot.Responses;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
public class HttpRequestCreatorTests
{
private readonly IRequestCreator _requestCreator;
private readonly bool _isQos;
private readonly IQoSProvider _qoSProvider;
private readonly HttpRequestMessage _requestMessage;
private readonly bool _useCookieContainer;
private readonly bool _allowAutoRedirect;
private Response<Ocelot.Request.Request> _response;
public HttpRequestCreatorTests()
{
_requestCreator = new HttpRequestCreator();
_isQos = true;
_qoSProvider = new NoQoSProvider();
_useCookieContainer = false;
_allowAutoRedirect = false;
_requestMessage = new HttpRequestMessage();
}
[Fact]
public void ShouldBuildRequest()
{
this.When(x => x.WhenIBuildARequest())
.Then(x => x.ThenTheRequestContainsTheRequestMessage())
.Then(x => x.ThenTheRequestContainsTheIsQos())
.Then(x => x.ThenTheRequestContainsTheQosProvider())
.Then(x => x.ThenTheRequestContainsUseCookieContainer())
.Then(x => x.ThenTheRequestContainsAllowAutoRedirect())
.BDDfy();
}
private void WhenIBuildARequest()
{
_response = _requestCreator.Build(_requestMessage,
_isQos, _qoSProvider, _useCookieContainer, _allowAutoRedirect)
.GetAwaiter()
.GetResult();
}
private void ThenTheRequestContainsTheRequestMessage()
{
_response.Data.HttpRequestMessage.ShouldBe(_requestMessage);
}
private void ThenTheRequestContainsTheIsQos()
{
_response.Data.IsQos.ShouldBe(_isQos);
}
private void ThenTheRequestContainsTheQosProvider()
{
_response.Data.QosProvider.ShouldBe(_qoSProvider);
}
namespace Ocelot.UnitTests.Request
{
using System.Net.Http;
using Ocelot.Request.Builder;
using Ocelot.Requester.QoS;
using Ocelot.Responses;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
public class HttpRequestCreatorTests
{
private readonly IRequestCreator _requestCreator;
private readonly bool _isQos;
private readonly IQoSProvider _qoSProvider;
private readonly HttpRequestMessage _requestMessage;
private readonly bool _useCookieContainer;
private readonly bool _allowAutoRedirect;
private readonly bool _useTracing;
private Response<Ocelot.Request.Request> _response;
public HttpRequestCreatorTests()
{
_requestCreator = new HttpRequestCreator();
_isQos = true;
_qoSProvider = new NoQoSProvider();
_useCookieContainer = false;
_allowAutoRedirect = false;
_useTracing = false;
_requestMessage = new HttpRequestMessage();
}
[Fact]
public void ShouldBuildRequest()
{
this.When(x => x.WhenIBuildARequest())
.Then(x => x.ThenTheRequestContainsTheRequestMessage())
.Then(x => x.ThenTheRequestContainsTheIsQos())
.Then(x => x.ThenTheRequestContainsTheQosProvider())
.Then(x => x.ThenTheRequestContainsUseCookieContainer())
.Then(x => x.ThenTheRequestContainsUseTracing())
.Then(x => x.ThenTheRequestContainsAllowAutoRedirect())
.BDDfy();
}
private void WhenIBuildARequest()
{
_response = _requestCreator.Build(_requestMessage,
_isQos, _qoSProvider, _useCookieContainer, _allowAutoRedirect, _useTracing)
.GetAwaiter()
.GetResult();
}
private void ThenTheRequestContainsTheRequestMessage()
{
_response.Data.HttpRequestMessage.ShouldBe(_requestMessage);
}
private void ThenTheRequestContainsTheIsQos()
{
_response.Data.IsQos.ShouldBe(_isQos);
}
private void ThenTheRequestContainsTheQosProvider()
{
_response.Data.QosProvider.ShouldBe(_qoSProvider);
}
private void ThenTheRequestContainsUseCookieContainer()
{
_response.Data.UseCookieContainer.ShouldBe(_useCookieContainer);
}
}
private void ThenTheRequestContainsUseTracing()
{
_response.Data.IsTracing.ShouldBe(_useTracing);
}
private void ThenTheRequestContainsAllowAutoRedirect()
{
_response.Data.AllowAutoRedirect.ShouldBe(_allowAutoRedirect);
}
}
}
}
}
}

View File

@ -0,0 +1,76 @@
using Microsoft.Extensions.DependencyInjection;
using Moq;
using Ocelot.Logging;
using Ocelot.Requester;
using Ocelot.Requester.QoS;
using Ocelot.Responses;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Requester
{
public class HttpClientHttpRequesterTest
{
private readonly Mock<IHttpClientCache> _cacheHandlers;
private Mock<IServiceProvider> _serviceProvider;
private Response<HttpResponseMessage> _response;
private readonly HttpClientHttpRequester _httpClientRequester;
private Ocelot.Request.Request _request;
private Mock<IOcelotLoggerFactory> _loggerFactory;
private Mock<IOcelotLogger> _logger;
public HttpClientHttpRequesterTest()
{
_serviceProvider = new Mock<IServiceProvider>();
_logger = new Mock<IOcelotLogger>();
_loggerFactory = new Mock<IOcelotLoggerFactory>();
_loggerFactory
.Setup(x => x.CreateLogger<HttpClientHttpRequester>())
.Returns(_logger.Object);
_cacheHandlers = new Mock<IHttpClientCache>();
_httpClientRequester = new HttpClientHttpRequester(_loggerFactory.Object, _cacheHandlers.Object, _serviceProvider.Object);
}
[Fact]
public void should_call_request_correctly()
{
this.Given(x=>x.GivenTheRequestIs(new Ocelot.Request.Request(new HttpRequestMessage() { RequestUri = new Uri("http://www.bbc.co.uk") }, false, new NoQoSProvider(), false, false, false)))
.When(x=>x.WhenIGetResponse())
.Then(x => x.ThenTheResponseIsCalledCorrectly())
.BDDfy();
}
[Fact]
public void should_call_request_UnableToCompleteRequest()
{
this.Given(x => x.GivenTheRequestIs(new Ocelot.Request.Request(new HttpRequestMessage() { RequestUri = new Uri("http://localhost:60080") }, false, new NoQoSProvider(), false, false, false)))
.When(x => x.WhenIGetResponse())
.Then(x => x.ThenTheResponseIsCalledError())
.BDDfy();
}
private void GivenTheRequestIs(Ocelot.Request.Request request)
{
_request = request;
}
private void WhenIGetResponse()
{
_response = _httpClientRequester.GetResponse(_request).Result;
}
private void ThenTheResponseIsCalledCorrectly()
{
Assert.True(_response.IsError == false);
}
private void ThenTheResponseIsCalledError()
{
Assert.True(_response.IsError == true);
}
}
}

View File

@ -1,81 +1,81 @@
namespace Ocelot.UnitTests.Requester
{
using System.Net.Http;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Moq;
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<IHttpRequester> _requester;
private OkResponse<HttpResponseMessage> _response;
private OkResponse<Ocelot.Request.Request> _request;
public HttpRequesterMiddlewareTests()
{
_requester = new Mock<IHttpRequester>();
GivenTheTestServerIsConfigured();
}
[Fact]
public void should_call_scoped_data_repository_correctly()
{
this.Given(x => x.GivenTheRequestIs(new Ocelot.Request.Request(new HttpRequestMessage(),true, new NoQoSProvider(), false, false)))
.And(x => x.GivenTheRequesterReturns(new HttpResponseMessage()))
.And(x => x.GivenTheScopedRepoReturns())
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheScopedRepoIsCalledCorrectly())
.BDDfy();
}
protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services)
{
services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
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<Ocelot.Request.Request>(request);
ScopedRepository
.Setup(x => x.Get<Ocelot.Request.Request>(It.IsAny<string>()))
.Returns(_request);
}
private void GivenTheRequesterReturns(HttpResponseMessage response)
{
_response = new OkResponse<HttpResponseMessage>(response);
_requester
.Setup(x => x.GetResponse(It.IsAny<Ocelot.Request.Request>()))
.ReturnsAsync(_response);
}
private void GivenTheScopedRepoReturns()
{
ScopedRepository
.Setup(x => x.Add(It.IsAny<string>(), _response.Data))
.Returns(new OkResponse());
}
private void ThenTheScopedRepoIsCalledCorrectly()
{
ScopedRepository
.Verify(x => x.Add("HttpResponseMessage", _response.Data), Times.Once());
}
}
}
namespace Ocelot.UnitTests.Requester
{
using System.Net.Http;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Moq;
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<IHttpRequester> _requester;
private OkResponse<HttpResponseMessage> _response;
private OkResponse<Ocelot.Request.Request> _request;
public HttpRequesterMiddlewareTests()
{
_requester = new Mock<IHttpRequester>();
GivenTheTestServerIsConfigured();
}
[Fact]
public void should_call_scoped_data_repository_correctly()
{
this.Given(x => x.GivenTheRequestIs(new Ocelot.Request.Request(new HttpRequestMessage(),true, new NoQoSProvider(), false, false,false)))
.And(x => x.GivenTheRequesterReturns(new HttpResponseMessage()))
.And(x => x.GivenTheScopedRepoReturns())
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheScopedRepoIsCalledCorrectly())
.BDDfy();
}
protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services)
{
services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
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<Ocelot.Request.Request>(request);
ScopedRepository
.Setup(x => x.Get<Ocelot.Request.Request>(It.IsAny<string>()))
.Returns(_request);
}
private void GivenTheRequesterReturns(HttpResponseMessage response)
{
_response = new OkResponse<HttpResponseMessage>(response);
_requester
.Setup(x => x.GetResponse(It.IsAny<Ocelot.Request.Request>()))
.ReturnsAsync(_response);
}
private void GivenTheScopedRepoReturns()
{
ScopedRepository
.Setup(x => x.Add(It.IsAny<string>(), _response.Data))
.Returns(new OkResponse());
}
private void ThenTheScopedRepoIsCalledCorrectly()
{
ScopedRepository
.Verify(x => x.Add("HttpResponseMessage", _response.Data), Times.Once());
}
}
}

View File

@ -1,10 +1,14 @@
namespace Ocelot.UnitTests.Responder
{
using System.Collections.Generic;
using System.Net.Http;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using Ocelot.DownstreamRouteFinder.Finder;
using Ocelot.Errors;
using Ocelot.Logging;
using Ocelot.Requester;
using Ocelot.Responder;
using Ocelot.Responder.Middleware;
using Ocelot.Responses;
@ -35,6 +39,17 @@
.BDDfy();
}
[Fact]
public void should_return_any_errors()
{
this.Given(x => x.GivenTheHttpResponseMessageIs(new HttpResponseMessage()))
.And(x => x.GivenThereArePipelineErrors(new UnableToFindDownstreamRouteError()))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenThereAreNoErrors())
.BDDfy();
}
protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services)
{
services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
@ -68,5 +83,14 @@
{
//todo a better assert?
}
private void GivenThereArePipelineErrors(Error error)
{
ScopedRepository
.Setup(x => x.Get<bool>("OcelotMiddlewareError"))
.Returns(new OkResponse<bool>(true));
ScopedRepository.Setup(x => x.Get<List<Error>>("OcelotMiddlewareErrors"))
.Returns(new OkResponse<List<Error>>(new List<Error>() { error }));
}
}
}