started adding consul acceptance test

This commit is contained in:
Tom Gardham-Pallister 2017-02-03 22:50:57 +00:00
parent b0ff2fd317
commit 9828c3b427
18 changed files with 234 additions and 79 deletions

View File

@ -42,8 +42,8 @@ var nugetFeedStableSymbolsUploadUrl = "https://www.nuget.org/api/v2/package";
// internal build variables - don't change these. // internal build variables - don't change these.
var releaseTag = ""; var releaseTag = "";
var buildVersion = committedVersion;
var committedVersion = "0.0.0-dev"; var committedVersion = "0.0.0-dev";
var buildVersion = committedVersion;
var target = Argument("target", "Default"); var target = Argument("target", "Default");
@ -264,7 +264,7 @@ private string GetNuGetVersionForCommit()
/// Updates project version in all of our projects /// Updates project version in all of our projects
private void PersistVersion(string version) private void PersistVersion(string version)
{ {
Information(string.Format("We'll search all project.json files for {0} and replace with {1}...", committedVersion, version)); //Information(string.Format("We'll search all project.json files for {0} and replace with {1}...", committedVersion, version));
var projectJsonFiles = GetFiles("./**/project.json"); var projectJsonFiles = GetFiles("./**/project.json");

View File

@ -11,7 +11,8 @@ namespace Ocelot.Configuration
List<ClaimToThing> claimsToClaims, Dictionary<string, string> routeClaimsRequirement, bool isAuthorised, List<ClaimToThing> claimsToQueries, List<ClaimToThing> claimsToClaims, Dictionary<string, string> routeClaimsRequirement, bool isAuthorised, List<ClaimToThing> claimsToQueries,
string requestIdKey, bool isCached, CacheOptions fileCacheOptions, string serviceName, bool useServiceDiscovery, string requestIdKey, bool isCached, CacheOptions fileCacheOptions, string serviceName, bool useServiceDiscovery,
string serviceDiscoveryProvider, string serviceDiscoveryAddress, string serviceDiscoveryProvider, string serviceDiscoveryAddress,
string downstreamScheme, string loadBalancer, string downstreamHost, int downstreamPort, string loadBalancerKey) string downstreamScheme, string loadBalancer, string downstreamHost, int downstreamPort,
string loadBalancerKey)
{ {
LoadBalancerKey = loadBalancerKey; LoadBalancerKey = loadBalancerKey;
LoadBalancer = loadBalancer; LoadBalancer = loadBalancer;

View File

@ -61,7 +61,7 @@ namespace Ocelot.DependencyInjection
{ {
services.AddMvcCore().AddJsonFormatters(); services.AddMvcCore().AddJsonFormatters();
services.AddLogging(); services.AddLogging();
services.AddSingleton<IServiceProviderFactory, ServiceProviderFactory>(); services.AddSingleton<IServiceDiscoveryProviderFactory, ServiceDiscoveryProviderFactory>();
services.AddSingleton<ILoadBalancerFactory, LoadBalancerFactory>(); services.AddSingleton<ILoadBalancerFactory, LoadBalancerFactory>();
services.AddSingleton<ILoadBalancerHouse, LoadBalancerHouse>(); services.AddSingleton<ILoadBalancerHouse, LoadBalancerHouse>();
services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>(); services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();

View File

@ -24,7 +24,7 @@
DownstreamHostNullOrEmptyError, DownstreamHostNullOrEmptyError,
ServicesAreNullError, ServicesAreNullError,
ServicesAreEmptyError, ServicesAreEmptyError,
UnableToFindServiceProviderError, UnableToFindServiceDiscoveryProviderError,
UnableToFindLoadBalancerError UnableToFindLoadBalancerError
} }
} }

View File

@ -5,19 +5,20 @@ namespace Ocelot.LoadBalancer.LoadBalancers
{ {
public class LoadBalancerFactory : ILoadBalancerFactory public class LoadBalancerFactory : ILoadBalancerFactory
{ {
private readonly IServiceProviderFactory _serviceProviderFactory; private readonly IServiceDiscoveryProviderFactory _serviceProviderFactory;
public LoadBalancerFactory(IServiceProviderFactory serviceProviderFactory) public LoadBalancerFactory(IServiceDiscoveryProviderFactory serviceProviderFactory)
{ {
_serviceProviderFactory = serviceProviderFactory; _serviceProviderFactory = serviceProviderFactory;
} }
public ILoadBalancer Get(ReRoute reRoute) public ILoadBalancer Get(ReRoute reRoute)
{ {
var serviceConfig = new ServiceConfiguraion( var serviceConfig = new ServiceProviderConfiguraion(
reRoute.ServiceName, reRoute.ServiceName,
reRoute.DownstreamHost, reRoute.DownstreamHost,
reRoute.DownstreamPort, reRoute.DownstreamPort,
reRoute.UseServiceDiscovery); reRoute.UseServiceDiscovery,
reRoute.ServiceDiscoveryProvider);
var serviceProvider = _serviceProviderFactory.Get(serviceConfig); var serviceProvider = _serviceProviderFactory.Get(serviceConfig);

View File

@ -3,7 +3,7 @@ using Ocelot.Values;
namespace Ocelot.ServiceDiscovery namespace Ocelot.ServiceDiscovery
{ {
public class ConfigurationServiceProvider : IServiceProvider public class ConfigurationServiceProvider : IServiceDiscoveryProvider
{ {
private List<Service> _services; private List<Service> _services;

View File

@ -3,7 +3,7 @@ using Ocelot.Values;
namespace Ocelot.ServiceDiscovery namespace Ocelot.ServiceDiscovery
{ {
public interface IServiceProvider public interface IServiceDiscoveryProvider
{ {
List<Service> Get(); List<Service> Get();
} }

View File

@ -0,0 +1,9 @@
using System;
namespace Ocelot.ServiceDiscovery
{
public interface IServiceDiscoveryProviderFactory
{
IServiceDiscoveryProvider Get(ServiceProviderConfiguraion serviceConfig);
}
}

View File

@ -1,9 +0,0 @@
using System;
namespace Ocelot.ServiceDiscovery
{
public interface IServiceProviderFactory
{
IServiceProvider Get(ServiceConfiguraion serviceConfig);
}
}

View File

@ -0,0 +1,18 @@
using System.Collections.Generic;
using Ocelot.Values;
namespace Ocelot.ServiceDiscovery
{
public class ServiceDiscoveryProviderFactory : IServiceDiscoveryProviderFactory
{
public IServiceDiscoveryProvider Get(ServiceProviderConfiguraion serviceConfig)
{
var services = new List<Service>()
{
new Service(serviceConfig.ServiceName, new HostAndPort(serviceConfig.DownstreamHost, serviceConfig.DownstreamPort))
};
return new ConfigurationServiceProvider(services);
}
}
}

View File

@ -0,0 +1,21 @@
namespace Ocelot.ServiceDiscovery
{
public class ServiceProviderConfiguraion
{
public ServiceProviderConfiguraion(string serviceName, string downstreamHost,
int downstreamPort, bool useServiceDiscovery, string serviceDiscoveryProvider)
{
ServiceName = serviceName;
DownstreamHost = downstreamHost;
DownstreamPort = downstreamPort;
UseServiceDiscovery = useServiceDiscovery;
ServiceDiscoveryProvider = serviceDiscoveryProvider;
}
public string ServiceName { get; }
public string DownstreamHost { get; }
public int DownstreamPort { get; }
public bool UseServiceDiscovery { get; }
public string ServiceDiscoveryProvider {get;}
}
}

View File

@ -1,34 +0,0 @@
using System.Collections.Generic;
using Ocelot.Values;
namespace Ocelot.ServiceDiscovery
{
public class ServiceProviderFactory : IServiceProviderFactory
{
public IServiceProvider Get(ServiceConfiguraion serviceConfig)
{
var services = new List<Service>()
{
new Service(serviceConfig.ServiceName, new HostAndPort(serviceConfig.DownstreamHost, serviceConfig.DownstreamPort))
};
return new ConfigurationServiceProvider(services);
}
}
public class ServiceConfiguraion
{
public ServiceConfiguraion(string serviceName, string downstreamHost, int downstreamPort, bool useServiceDiscovery)
{
ServiceName = serviceName;
DownstreamHost = downstreamHost;
DownstreamPort = downstreamPort;
UseServiceDiscovery = useServiceDiscovery;
}
public string ServiceName { get; }
public string DownstreamHost { get; }
public int DownstreamPort { get; }
public bool UseServiceDiscovery { get; }
}
}

View File

@ -0,0 +1,12 @@
using Ocelot.Errors;
namespace Ocelot.ServiceDiscovery
{
public class UnableToFindServiceDiscoveryProviderError : Error
{
public UnableToFindServiceDiscoveryProviderError(string message)
: base(message, OcelotErrorCode.UnableToFindServiceDiscoveryProviderError)
{
}
}
}

View File

@ -1,12 +0,0 @@
using Ocelot.Errors;
namespace Ocelot.ServiceDiscovery
{
public class UnableToFindServiceProviderError : Error
{
public UnableToFindServiceProviderError(string message)
: base(message, OcelotErrorCode.UnableToFindServiceProviderError)
{
}
}
}

View File

@ -0,0 +1,135 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.AcceptanceTests
{
public class ServiceDiscoveryTests : IDisposable
{
private IWebHost _builder;
private IWebHost _fakeConsulBuilder;
private readonly Steps _steps;
public ServiceDiscoveryTests()
{
_steps = new Steps();
}
[Fact]
public void should_use_service_discovery_and_load_balance_request()
{
var serviceName = "product";
var downstreamServiceOneUrl = "http://localhost:51879";
var downstreamServiceTwoUrl = "http://localhost:51880";
var fakeConsulServiceDiscoveryUrl = "http://localhost:9500";
var downstreamServiceOneCounter = 0;
var downstreamServiceTwoCounter = 0;
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
UpstreamTemplate = "/",
UpstreamHttpMethod = "Get",
ServiceName = serviceName,
LoadBalancer = "LeastConnection",
}
},
GlobalConfiguration = new FileGlobalConfiguration()
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Provider = "Consul"
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn(downstreamServiceOneUrl, 200, downstreamServiceOneCounter))
.And(x => x.GivenThereIsAServiceRunningOn(downstreamServiceTwoUrl, 200, downstreamServiceTwoCounter))
.And(x => x.GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl))
.And(x => x.GivenTheServicesAreRegisteredWithConsul(serviceName, downstreamServiceOneUrl, downstreamServiceTwoUrl))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimes("/", 50))
.Then(x => x.ThenTheTwoServicesShouldHaveBeenCalledTimes(50, downstreamServiceOneCounter, downstreamServiceTwoCounter))
.And(x => x.ThenBothServicesCalledRealisticAmountOfTimes(downstreamServiceOneCounter,downstreamServiceTwoCounter))
.BDDfy();
}
private void ThenBothServicesCalledRealisticAmountOfTimes(int counterOne, int counterTwo)
{
counterOne.ShouldBeGreaterThan(10);
counterTwo.ShouldBeGreaterThan(10);
}
private void ThenTheTwoServicesShouldHaveBeenCalledTimes(int expected, int counterOne, int counterTwo)
{
var total = counterOne + counterTwo;
total.ShouldBe(expected);
}
private void GivenTheServicesAreRegisteredWithConsul(string serviceName, params string[] urls)
{
//register these services with fake consul
}
private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url)
{
_fakeConsulBuilder = new WebHostBuilder()
.UseUrls(url)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseUrls(url)
.Configure(app =>
{
app.Run(async context =>
{
//do consul shit
});
})
.Build();
_fakeConsulBuilder.Start();
}
private void GivenThereIsAServiceRunningOn(string url, int statusCode, int counter)
{
_builder = new WebHostBuilder()
.UseUrls(url)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseUrls(url)
.Configure(app =>
{
app.Run(async context =>
{
counter++;
context.Response.StatusCode = statusCode;
});
})
.Build();
_builder.Start();
}
public void Dispose()
{
_builder?.Dispose();
_steps.Dispose();
}
}
}

View File

@ -5,6 +5,7 @@ using System.Linq;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Threading.Tasks;
using CacheManager.Core; using CacheManager.Core;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost; using Microsoft.AspNetCore.TestHost;
@ -153,6 +154,18 @@ namespace Ocelot.AcceptanceTests
_response = _ocelotClient.GetAsync(url).Result; _response = _ocelotClient.GetAsync(url).Result;
} }
public void WhenIGetUrlOnTheApiGatewayMultipleTimes(string url, int times)
{
var tasks = new Task[times];
for (int i = 0; i < times; i++)
{
tasks[i] = _ocelotClient.GetAsync(url);
}
Task.WaitAll(tasks);
}
public void WhenIGetUrlOnTheApiGateway(string url, string requestId) public void WhenIGetUrlOnTheApiGateway(string url, string requestId)
{ {
_ocelotClient.DefaultRequestHeaders.TryAddWithoutValidation(RequestIdKey, requestId); _ocelotClient.DefaultRequestHeaders.TryAddWithoutValidation(RequestIdKey, requestId);

View File

@ -14,20 +14,20 @@ namespace Ocelot.UnitTests.LoadBalancer
private ReRoute _reRoute; private ReRoute _reRoute;
private LoadBalancerFactory _factory; private LoadBalancerFactory _factory;
private ILoadBalancer _result; private ILoadBalancer _result;
private Mock<IServiceProviderFactory> _serviceProviderFactory; private Mock<IServiceDiscoveryProviderFactory> _serviceProviderFactory;
private Mock<IServiceProvider> _serviceProvider; private Mock<IServiceDiscoveryProvider> _serviceProvider;
public LoadBalancerFactoryTests() public LoadBalancerFactoryTests()
{ {
_serviceProviderFactory = new Mock<IServiceProviderFactory>(); _serviceProviderFactory = new Mock<IServiceDiscoveryProviderFactory>();
_serviceProvider = new Mock<IServiceProvider>(); _serviceProvider = new Mock<IServiceDiscoveryProvider>();
_factory = new LoadBalancerFactory(_serviceProviderFactory.Object); _factory = new LoadBalancerFactory(_serviceProviderFactory.Object);
} }
private void GivenTheServiceProviderFactoryReturns() private void GivenTheServiceProviderFactoryReturns()
{ {
_serviceProviderFactory _serviceProviderFactory
.Setup(x => x.Get(It.IsAny<ServiceConfiguraion>())) .Setup(x => x.Get(It.IsAny<ServiceProviderConfiguraion>()))
.Returns(_serviceProvider.Object); .Returns(_serviceProvider.Object);
} }
@ -89,7 +89,7 @@ namespace Ocelot.UnitTests.LoadBalancer
private void ThenTheServiceProviderIsCalledCorrectly() private void ThenTheServiceProviderIsCalledCorrectly()
{ {
_serviceProviderFactory _serviceProviderFactory
.Verify(x => x.Get(It.IsAny<ServiceConfiguraion>()), Times.Once); .Verify(x => x.Get(It.IsAny<ServiceProviderConfiguraion>()), Times.Once);
} }
private void GivenAReRoute(ReRoute reRoute) private void GivenAReRoute(ReRoute reRoute)

View File

@ -7,19 +7,19 @@ namespace Ocelot.UnitTests.ServiceDiscovery
{ {
public class ServiceProviderFactoryTests public class ServiceProviderFactoryTests
{ {
private ServiceConfiguraion _serviceConfig; private ServiceProviderConfiguraion _serviceConfig;
private IServiceProvider _result; private IServiceDiscoveryProvider _result;
private readonly ServiceProviderFactory _factory; private readonly ServiceDiscoveryProviderFactory _factory;
public ServiceProviderFactoryTests() public ServiceProviderFactoryTests()
{ {
_factory = new ServiceProviderFactory(); _factory = new ServiceDiscoveryProviderFactory();
} }
[Fact] [Fact]
public void should_return_no_service_provider() public void should_return_no_service_provider()
{ {
var serviceConfig = new ServiceConfiguraion("product", "127.0.0.1", 80, false); var serviceConfig = new ServiceProviderConfiguraion("product", "127.0.0.1", 80, false, "Does not matter");
this.Given(x => x.GivenTheReRoute(serviceConfig)) this.Given(x => x.GivenTheReRoute(serviceConfig))
.When(x => x.WhenIGetTheServiceProvider()) .When(x => x.WhenIGetTheServiceProvider())
@ -27,7 +27,7 @@ namespace Ocelot.UnitTests.ServiceDiscovery
.BDDfy(); .BDDfy();
} }
private void GivenTheReRoute(ServiceConfiguraion serviceConfig) private void GivenTheReRoute(ServiceProviderConfiguraion serviceConfig)
{ {
_serviceConfig = serviceConfig; _serviceConfig = serviceConfig;
} }