hacked together load balancing reroutes in fileconfig (#211)

* hacked together load balancing reroutes in fileconfig

* some renaming and refactoring

* more renames

* hacked away the old config json

* test for issue 213

* renamed key

* dont share ports

* oops

* updated docs

* mvoed docs around

* port being used
This commit is contained in:
Tom Pallister
2018-01-31 20:34:55 +00:00
committed by GitHub
parent f572d1b0ca
commit 3ac9b3bd87
440 changed files with 29740 additions and 28464 deletions

View File

@ -1,285 +1,285 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Ocelot.LoadBalancer.LoadBalancers;
using Ocelot.Responses;
using Ocelot.Values;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.LoadBalancer
{
public class LeastConnectionTests
{
private HostAndPort _hostAndPort;
private Response<HostAndPort> _result;
private LeastConnection _leastConnection;
private List<Service> _services;
private Random _random;
public LeastConnectionTests()
{
_random = new Random();
}
[Fact]
public void should_be_able_to_lease_and_release_concurrently()
{
var serviceName = "products";
var availableServices = new List<Service>
{
new Service(serviceName, new HostAndPort("127.0.0.1", 80), string.Empty, string.Empty, new string[0]),
new Service(serviceName, new HostAndPort("127.0.0.2", 80), string.Empty, string.Empty, new string[0]),
};
_services = availableServices;
_leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName);
var tasks = new Task[100];
for(var i = 0; i < tasks.Length; i++)
{
tasks[i] = LeaseDelayAndRelease();
}
Task.WaitAll(tasks);
}
[Fact]
public void should_handle_service_returning_to_available()
{
var serviceName = "products";
var availableServices = new List<Service>
{
new Service(serviceName, new HostAndPort("127.0.0.1", 80), string.Empty, string.Empty, new string[0]),
new Service(serviceName, new HostAndPort("127.0.0.2", 80), string.Empty, string.Empty, new string[0]),
};
_leastConnection = new LeastConnection(() => Task.FromResult(availableServices), serviceName);
var hostAndPortOne = _leastConnection.Lease().Result;
hostAndPortOne.Data.DownstreamHost.ShouldBe("127.0.0.1");
var hostAndPortTwo = _leastConnection.Lease().Result;
hostAndPortTwo.Data.DownstreamHost.ShouldBe("127.0.0.2");
_leastConnection.Release(hostAndPortOne.Data);
_leastConnection.Release(hostAndPortTwo.Data);
availableServices = new List<Service>
{
new Service(serviceName, new HostAndPort("127.0.0.1", 80), string.Empty, string.Empty, new string[0]),
};
hostAndPortOne = _leastConnection.Lease().Result;
hostAndPortOne.Data.DownstreamHost.ShouldBe("127.0.0.1");
hostAndPortTwo = _leastConnection.Lease().Result;
hostAndPortTwo.Data.DownstreamHost.ShouldBe("127.0.0.1");
_leastConnection.Release(hostAndPortOne.Data);
_leastConnection.Release(hostAndPortTwo.Data);
availableServices = new List<Service>
{
new Service(serviceName, new HostAndPort("127.0.0.1", 80), string.Empty, string.Empty, new string[0]),
new Service(serviceName, new HostAndPort("127.0.0.2", 80), string.Empty, string.Empty, new string[0]),
};
hostAndPortOne = _leastConnection.Lease().Result;
hostAndPortOne.Data.DownstreamHost.ShouldBe("127.0.0.1");
hostAndPortTwo = _leastConnection.Lease().Result;
hostAndPortTwo.Data.DownstreamHost.ShouldBe("127.0.0.2");
_leastConnection.Release(hostAndPortOne.Data);
_leastConnection.Release(hostAndPortTwo.Data);
}
private async Task LeaseDelayAndRelease()
{
var hostAndPort = await _leastConnection.Lease();
await Task.Delay(_random.Next(1, 100));
_leastConnection.Release(hostAndPort.Data);
}
[Fact]
public void should_get_next_url()
{
var serviceName = "products";
var hostAndPort = new HostAndPort("localhost", 80);
var availableServices = new List<Service>
{
new Service(serviceName, hostAndPort, string.Empty, string.Empty, new string[0])
};
this.Given(x => x.GivenAHostAndPort(hostAndPort))
.And(x => x.GivenTheLoadBalancerStarts(availableServices, serviceName))
.When(x => x.WhenIGetTheNextHostAndPort())
.Then(x => x.ThenTheNextHostAndPortIsReturned())
.BDDfy();
}
[Fact]
public void should_serve_from_service_with_least_connections()
{
var serviceName = "products";
var availableServices = new List<Service>
{
new Service(serviceName, new HostAndPort("127.0.0.1", 80), string.Empty, string.Empty, new string[0]),
new Service(serviceName, new HostAndPort("127.0.0.2", 80), string.Empty, string.Empty, new string[0]),
new Service(serviceName, new HostAndPort("127.0.0.3", 80), string.Empty, string.Empty, new string[0])
};
_services = availableServices;
_leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName);
var response = _leastConnection.Lease().Result;
response.Data.DownstreamHost.ShouldBe(availableServices[0].HostAndPort.DownstreamHost);
response = _leastConnection.Lease().Result;
response.Data.DownstreamHost.ShouldBe(availableServices[1].HostAndPort.DownstreamHost);
response = _leastConnection.Lease().Result;
response.Data.DownstreamHost.ShouldBe(availableServices[2].HostAndPort.DownstreamHost);
}
[Fact]
public void should_build_connections_per_service()
{
var serviceName = "products";
var availableServices = new List<Service>
{
new Service(serviceName, new HostAndPort("127.0.0.1", 80), string.Empty, string.Empty, new string[0]),
new Service(serviceName, new HostAndPort("127.0.0.2", 80), string.Empty, string.Empty, new string[0]),
};
_services = availableServices;
_leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName);
var response = _leastConnection.Lease().Result;
response.Data.DownstreamHost.ShouldBe(availableServices[0].HostAndPort.DownstreamHost);
response = _leastConnection.Lease().Result;
response.Data.DownstreamHost.ShouldBe(availableServices[1].HostAndPort.DownstreamHost);
response = _leastConnection.Lease().Result;
response.Data.DownstreamHost.ShouldBe(availableServices[0].HostAndPort.DownstreamHost);
response = _leastConnection.Lease().Result;
response.Data.DownstreamHost.ShouldBe(availableServices[1].HostAndPort.DownstreamHost);
}
[Fact]
public void should_release_connection()
{
var serviceName = "products";
var availableServices = new List<Service>
{
new Service(serviceName, new HostAndPort("127.0.0.1", 80), string.Empty, string.Empty, new string[0]),
new Service(serviceName, new HostAndPort("127.0.0.2", 80), string.Empty, string.Empty, new string[0]),
};
_services = availableServices;
_leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName);
var response = _leastConnection.Lease().Result;
response.Data.DownstreamHost.ShouldBe(availableServices[0].HostAndPort.DownstreamHost);
response = _leastConnection.Lease().Result;
response.Data.DownstreamHost.ShouldBe(availableServices[1].HostAndPort.DownstreamHost);
response = _leastConnection.Lease().Result;
response.Data.DownstreamHost.ShouldBe(availableServices[0].HostAndPort.DownstreamHost);
response = _leastConnection.Lease().Result;
response.Data.DownstreamHost.ShouldBe(availableServices[1].HostAndPort.DownstreamHost);
//release this so 2 should have 1 connection and we should get 2 back as our next host and port
_leastConnection.Release(availableServices[1].HostAndPort);
response = _leastConnection.Lease().Result;
response.Data.DownstreamHost.ShouldBe(availableServices[1].HostAndPort.DownstreamHost);
}
[Fact]
public void should_return_error_if_services_are_null()
{
var serviceName = "products";
var hostAndPort = new HostAndPort("localhost", 80);
this.Given(x => x.GivenAHostAndPort(hostAndPort))
.And(x => x.GivenTheLoadBalancerStarts(null, serviceName))
.When(x => x.WhenIGetTheNextHostAndPort())
.Then(x => x.ThenServiceAreNullErrorIsReturned())
.BDDfy();
}
[Fact]
public void should_return_error_if_services_are_empty()
{
var serviceName = "products";
var hostAndPort = new HostAndPort("localhost", 80);
this.Given(x => x.GivenAHostAndPort(hostAndPort))
.And(x => x.GivenTheLoadBalancerStarts(new List<Service>(), serviceName))
.When(x => x.WhenIGetTheNextHostAndPort())
.Then(x => x.ThenServiceAreEmptyErrorIsReturned())
.BDDfy();
}
private void ThenServiceAreNullErrorIsReturned()
{
_result.IsError.ShouldBeTrue();
_result.Errors[0].ShouldBeOfType<ServicesAreNullError>();
}
private void ThenServiceAreEmptyErrorIsReturned()
{
_result.IsError.ShouldBeTrue();
_result.Errors[0].ShouldBeOfType<ServicesAreEmptyError>();
}
private void GivenTheLoadBalancerStarts(List<Service> services, string serviceName)
{
_services = services;
_leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName);
}
private void WhenTheLoadBalancerStarts(List<Service> services, string serviceName)
{
GivenTheLoadBalancerStarts(services, serviceName);
}
private void GivenAHostAndPort(HostAndPort hostAndPort)
{
_hostAndPort = hostAndPort;
}
private void WhenIGetTheNextHostAndPort()
{
_result = _leastConnection.Lease().Result;
}
private void ThenTheNextHostAndPortIsReturned()
{
_result.Data.DownstreamHost.ShouldBe(_hostAndPort.DownstreamHost);
_result.Data.DownstreamPort.ShouldBe(_hostAndPort.DownstreamPort);
}
}
}
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Ocelot.LoadBalancer.LoadBalancers;
using Ocelot.Responses;
using Ocelot.Values;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.LoadBalancer
{
public class LeastConnectionTests
{
private ServiceHostAndPort _hostAndPort;
private Response<ServiceHostAndPort> _result;
private LeastConnection _leastConnection;
private List<Service> _services;
private Random _random;
public LeastConnectionTests()
{
_random = new Random();
}
[Fact]
public void should_be_able_to_lease_and_release_concurrently()
{
var serviceName = "products";
var availableServices = new List<Service>
{
new Service(serviceName, new ServiceHostAndPort("127.0.0.1", 80), string.Empty, string.Empty, new string[0]),
new Service(serviceName, new ServiceHostAndPort("127.0.0.2", 80), string.Empty, string.Empty, new string[0]),
};
_services = availableServices;
_leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName);
var tasks = new Task[100];
for(var i = 0; i < tasks.Length; i++)
{
tasks[i] = LeaseDelayAndRelease();
}
Task.WaitAll(tasks);
}
[Fact]
public void should_handle_service_returning_to_available()
{
var serviceName = "products";
var availableServices = new List<Service>
{
new Service(serviceName, new ServiceHostAndPort("127.0.0.1", 80), string.Empty, string.Empty, new string[0]),
new Service(serviceName, new ServiceHostAndPort("127.0.0.2", 80), string.Empty, string.Empty, new string[0]),
};
_leastConnection = new LeastConnection(() => Task.FromResult(availableServices), serviceName);
var hostAndPortOne = _leastConnection.Lease().Result;
hostAndPortOne.Data.DownstreamHost.ShouldBe("127.0.0.1");
var hostAndPortTwo = _leastConnection.Lease().Result;
hostAndPortTwo.Data.DownstreamHost.ShouldBe("127.0.0.2");
_leastConnection.Release(hostAndPortOne.Data);
_leastConnection.Release(hostAndPortTwo.Data);
availableServices = new List<Service>
{
new Service(serviceName, new ServiceHostAndPort("127.0.0.1", 80), string.Empty, string.Empty, new string[0]),
};
hostAndPortOne = _leastConnection.Lease().Result;
hostAndPortOne.Data.DownstreamHost.ShouldBe("127.0.0.1");
hostAndPortTwo = _leastConnection.Lease().Result;
hostAndPortTwo.Data.DownstreamHost.ShouldBe("127.0.0.1");
_leastConnection.Release(hostAndPortOne.Data);
_leastConnection.Release(hostAndPortTwo.Data);
availableServices = new List<Service>
{
new Service(serviceName, new ServiceHostAndPort("127.0.0.1", 80), string.Empty, string.Empty, new string[0]),
new Service(serviceName, new ServiceHostAndPort("127.0.0.2", 80), string.Empty, string.Empty, new string[0]),
};
hostAndPortOne = _leastConnection.Lease().Result;
hostAndPortOne.Data.DownstreamHost.ShouldBe("127.0.0.1");
hostAndPortTwo = _leastConnection.Lease().Result;
hostAndPortTwo.Data.DownstreamHost.ShouldBe("127.0.0.2");
_leastConnection.Release(hostAndPortOne.Data);
_leastConnection.Release(hostAndPortTwo.Data);
}
private async Task LeaseDelayAndRelease()
{
var hostAndPort = await _leastConnection.Lease();
await Task.Delay(_random.Next(1, 100));
_leastConnection.Release(hostAndPort.Data);
}
[Fact]
public void should_get_next_url()
{
var serviceName = "products";
var hostAndPort = new ServiceHostAndPort("localhost", 80);
var availableServices = new List<Service>
{
new Service(serviceName, hostAndPort, string.Empty, string.Empty, new string[0])
};
this.Given(x => x.GivenAHostAndPort(hostAndPort))
.And(x => x.GivenTheLoadBalancerStarts(availableServices, serviceName))
.When(x => x.WhenIGetTheNextHostAndPort())
.Then(x => x.ThenTheNextHostAndPortIsReturned())
.BDDfy();
}
[Fact]
public void should_serve_from_service_with_least_connections()
{
var serviceName = "products";
var availableServices = new List<Service>
{
new Service(serviceName, new ServiceHostAndPort("127.0.0.1", 80), string.Empty, string.Empty, new string[0]),
new Service(serviceName, new ServiceHostAndPort("127.0.0.2", 80), string.Empty, string.Empty, new string[0]),
new Service(serviceName, new ServiceHostAndPort("127.0.0.3", 80), string.Empty, string.Empty, new string[0])
};
_services = availableServices;
_leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName);
var response = _leastConnection.Lease().Result;
response.Data.DownstreamHost.ShouldBe(availableServices[0].HostAndPort.DownstreamHost);
response = _leastConnection.Lease().Result;
response.Data.DownstreamHost.ShouldBe(availableServices[1].HostAndPort.DownstreamHost);
response = _leastConnection.Lease().Result;
response.Data.DownstreamHost.ShouldBe(availableServices[2].HostAndPort.DownstreamHost);
}
[Fact]
public void should_build_connections_per_service()
{
var serviceName = "products";
var availableServices = new List<Service>
{
new Service(serviceName, new ServiceHostAndPort("127.0.0.1", 80), string.Empty, string.Empty, new string[0]),
new Service(serviceName, new ServiceHostAndPort("127.0.0.2", 80), string.Empty, string.Empty, new string[0]),
};
_services = availableServices;
_leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName);
var response = _leastConnection.Lease().Result;
response.Data.DownstreamHost.ShouldBe(availableServices[0].HostAndPort.DownstreamHost);
response = _leastConnection.Lease().Result;
response.Data.DownstreamHost.ShouldBe(availableServices[1].HostAndPort.DownstreamHost);
response = _leastConnection.Lease().Result;
response.Data.DownstreamHost.ShouldBe(availableServices[0].HostAndPort.DownstreamHost);
response = _leastConnection.Lease().Result;
response.Data.DownstreamHost.ShouldBe(availableServices[1].HostAndPort.DownstreamHost);
}
[Fact]
public void should_release_connection()
{
var serviceName = "products";
var availableServices = new List<Service>
{
new Service(serviceName, new ServiceHostAndPort("127.0.0.1", 80), string.Empty, string.Empty, new string[0]),
new Service(serviceName, new ServiceHostAndPort("127.0.0.2", 80), string.Empty, string.Empty, new string[0]),
};
_services = availableServices;
_leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName);
var response = _leastConnection.Lease().Result;
response.Data.DownstreamHost.ShouldBe(availableServices[0].HostAndPort.DownstreamHost);
response = _leastConnection.Lease().Result;
response.Data.DownstreamHost.ShouldBe(availableServices[1].HostAndPort.DownstreamHost);
response = _leastConnection.Lease().Result;
response.Data.DownstreamHost.ShouldBe(availableServices[0].HostAndPort.DownstreamHost);
response = _leastConnection.Lease().Result;
response.Data.DownstreamHost.ShouldBe(availableServices[1].HostAndPort.DownstreamHost);
//release this so 2 should have 1 connection and we should get 2 back as our next host and port
_leastConnection.Release(availableServices[1].HostAndPort);
response = _leastConnection.Lease().Result;
response.Data.DownstreamHost.ShouldBe(availableServices[1].HostAndPort.DownstreamHost);
}
[Fact]
public void should_return_error_if_services_are_null()
{
var serviceName = "products";
var hostAndPort = new ServiceHostAndPort("localhost", 80);
this.Given(x => x.GivenAHostAndPort(hostAndPort))
.And(x => x.GivenTheLoadBalancerStarts(null, serviceName))
.When(x => x.WhenIGetTheNextHostAndPort())
.Then(x => x.ThenServiceAreNullErrorIsReturned())
.BDDfy();
}
[Fact]
public void should_return_error_if_services_are_empty()
{
var serviceName = "products";
var hostAndPort = new ServiceHostAndPort("localhost", 80);
this.Given(x => x.GivenAHostAndPort(hostAndPort))
.And(x => x.GivenTheLoadBalancerStarts(new List<Service>(), serviceName))
.When(x => x.WhenIGetTheNextHostAndPort())
.Then(x => x.ThenServiceAreEmptyErrorIsReturned())
.BDDfy();
}
private void ThenServiceAreNullErrorIsReturned()
{
_result.IsError.ShouldBeTrue();
_result.Errors[0].ShouldBeOfType<ServicesAreNullError>();
}
private void ThenServiceAreEmptyErrorIsReturned()
{
_result.IsError.ShouldBeTrue();
_result.Errors[0].ShouldBeOfType<ServicesAreEmptyError>();
}
private void GivenTheLoadBalancerStarts(List<Service> services, string serviceName)
{
_services = services;
_leastConnection = new LeastConnection(() => Task.FromResult(_services), serviceName);
}
private void WhenTheLoadBalancerStarts(List<Service> services, string serviceName)
{
GivenTheLoadBalancerStarts(services, serviceName);
}
private void GivenAHostAndPort(ServiceHostAndPort hostAndPort)
{
_hostAndPort = hostAndPort;
}
private void WhenIGetTheNextHostAndPort()
{
_result = _leastConnection.Lease().Result;
}
private void ThenTheNextHostAndPortIsReturned()
{
_result.Data.DownstreamHost.ShouldBe(_hostAndPort.DownstreamHost);
_result.Data.DownstreamPort.ShouldBe(_hostAndPort.DownstreamPort);
}
}
}

View File

@ -1,125 +1,125 @@
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.LoadBalancer.LoadBalancers;
using Ocelot.ServiceDiscovery;
using Shouldly;
using System.Collections.Generic;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.LoadBalancer
{
public class LoadBalancerFactoryTests
{
private ReRoute _reRoute;
private LoadBalancerFactory _factory;
private ILoadBalancer _result;
private Mock<IServiceDiscoveryProviderFactory> _serviceProviderFactory;
private Mock<IServiceDiscoveryProvider> _serviceProvider;
private ServiceProviderConfiguration _serviceProviderConfig;
public LoadBalancerFactoryTests()
{
_serviceProviderFactory = new Mock<IServiceDiscoveryProviderFactory>();
_serviceProvider = new Mock<IServiceDiscoveryProvider>();
_factory = new LoadBalancerFactory(_serviceProviderFactory.Object);
}
[Fact]
public void should_return_no_load_balancer()
{
var reRoute = new ReRouteBuilder()
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build();
this.Given(x => x.GivenAReRoute(reRoute))
.And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build()))
.And(x => x.GivenTheServiceProviderFactoryReturns())
.When(x => x.WhenIGetTheLoadBalancer())
.Then(x => x.ThenTheLoadBalancerIsReturned<NoLoadBalancer>())
.BDDfy();
}
[Fact]
public void should_return_round_robin_load_balancer()
{
var reRoute = new ReRouteBuilder()
.WithLoadBalancer("RoundRobin")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build();
this.Given(x => x.GivenAReRoute(reRoute))
.And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build()))
.And(x => x.GivenTheServiceProviderFactoryReturns())
.When(x => x.WhenIGetTheLoadBalancer())
.Then(x => x.ThenTheLoadBalancerIsReturned<RoundRobin>())
.BDDfy();
}
[Fact]
public void should_return_round_least_connection_balancer()
{
var reRoute = new ReRouteBuilder()
.WithLoadBalancer("LeastConnection")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build();
this.Given(x => x.GivenAReRoute(reRoute))
.And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build()))
.And(x => x.GivenTheServiceProviderFactoryReturns())
.When(x => x.WhenIGetTheLoadBalancer())
.Then(x => x.ThenTheLoadBalancerIsReturned<LeastConnection>())
.BDDfy();
}
[Fact]
public void should_call_service_provider()
{
var reRoute = new ReRouteBuilder()
.WithLoadBalancer("RoundRobin")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build();
this.Given(x => x.GivenAReRoute(reRoute))
.And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build()))
.And(x => x.GivenTheServiceProviderFactoryReturns())
.When(x => x.WhenIGetTheLoadBalancer())
.Then(x => x.ThenTheServiceProviderIsCalledCorrectly())
.BDDfy();
}
private void GivenAServiceProviderConfig(ServiceProviderConfiguration serviceProviderConfig)
{
_serviceProviderConfig = serviceProviderConfig;
}
private void GivenTheServiceProviderFactoryReturns()
{
_serviceProviderFactory
.Setup(x => x.Get(It.IsAny<ServiceProviderConfiguration>(), It.IsAny<ReRoute>()))
.Returns(_serviceProvider.Object);
}
private void ThenTheServiceProviderIsCalledCorrectly()
{
_serviceProviderFactory
.Verify(x => x.Get(It.IsAny<ServiceProviderConfiguration>(), It.IsAny<ReRoute>()), Times.Once);
}
private void GivenAReRoute(ReRoute reRoute)
{
_reRoute = reRoute;
}
private void WhenIGetTheLoadBalancer()
{
_result = _factory.Get(_reRoute, _serviceProviderConfig).Result;
}
private void ThenTheLoadBalancerIsReturned<T>()
{
_result.ShouldBeOfType<T>();
}
}
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.LoadBalancer.LoadBalancers;
using Ocelot.ServiceDiscovery;
using Shouldly;
using System.Collections.Generic;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.LoadBalancer
{
public class LoadBalancerFactoryTests
{
private ReRoute _reRoute;
private LoadBalancerFactory _factory;
private ILoadBalancer _result;
private Mock<IServiceDiscoveryProviderFactory> _serviceProviderFactory;
private Mock<IServiceDiscoveryProvider> _serviceProvider;
private ServiceProviderConfiguration _serviceProviderConfig;
public LoadBalancerFactoryTests()
{
_serviceProviderFactory = new Mock<IServiceDiscoveryProviderFactory>();
_serviceProvider = new Mock<IServiceDiscoveryProvider>();
_factory = new LoadBalancerFactory(_serviceProviderFactory.Object);
}
[Fact]
public void should_return_no_load_balancer()
{
var reRoute = new ReRouteBuilder()
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build();
this.Given(x => x.GivenAReRoute(reRoute))
.And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build()))
.And(x => x.GivenTheServiceProviderFactoryReturns())
.When(x => x.WhenIGetTheLoadBalancer())
.Then(x => x.ThenTheLoadBalancerIsReturned<NoLoadBalancer>())
.BDDfy();
}
[Fact]
public void should_return_round_robin_load_balancer()
{
var reRoute = new ReRouteBuilder()
.WithLoadBalancer("RoundRobin")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build();
this.Given(x => x.GivenAReRoute(reRoute))
.And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build()))
.And(x => x.GivenTheServiceProviderFactoryReturns())
.When(x => x.WhenIGetTheLoadBalancer())
.Then(x => x.ThenTheLoadBalancerIsReturned<RoundRobin>())
.BDDfy();
}
[Fact]
public void should_return_round_least_connection_balancer()
{
var reRoute = new ReRouteBuilder()
.WithLoadBalancer("LeastConnection")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build();
this.Given(x => x.GivenAReRoute(reRoute))
.And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build()))
.And(x => x.GivenTheServiceProviderFactoryReturns())
.When(x => x.WhenIGetTheLoadBalancer())
.Then(x => x.ThenTheLoadBalancerIsReturned<LeastConnection>())
.BDDfy();
}
[Fact]
public void should_call_service_provider()
{
var reRoute = new ReRouteBuilder()
.WithLoadBalancer("RoundRobin")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build();
this.Given(x => x.GivenAReRoute(reRoute))
.And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build()))
.And(x => x.GivenTheServiceProviderFactoryReturns())
.When(x => x.WhenIGetTheLoadBalancer())
.Then(x => x.ThenTheServiceProviderIsCalledCorrectly())
.BDDfy();
}
private void GivenAServiceProviderConfig(ServiceProviderConfiguration serviceProviderConfig)
{
_serviceProviderConfig = serviceProviderConfig;
}
private void GivenTheServiceProviderFactoryReturns()
{
_serviceProviderFactory
.Setup(x => x.Get(It.IsAny<ServiceProviderConfiguration>(), It.IsAny<ReRoute>()))
.Returns(_serviceProvider.Object);
}
private void ThenTheServiceProviderIsCalledCorrectly()
{
_serviceProviderFactory
.Verify(x => x.Get(It.IsAny<ServiceProviderConfiguration>(), It.IsAny<ReRoute>()), Times.Once);
}
private void GivenAReRoute(ReRoute reRoute)
{
_reRoute = reRoute;
}
private void WhenIGetTheLoadBalancer()
{
_result = _factory.Get(_reRoute, _serviceProviderConfig).Result;
}
private void ThenTheLoadBalancerIsReturned<T>()
{
_result.ShouldBeOfType<T>();
}
}
}

View File

@ -1,165 +1,165 @@
using System;
using System.Threading.Tasks;
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.LoadBalancer.LoadBalancers;
using Ocelot.Responses;
using Ocelot.Values;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.LoadBalancer
{
public class LoadBalancerHouseTests
{
private ReRoute _reRoute;
private ILoadBalancer _loadBalancer;
private readonly LoadBalancerHouse _loadBalancerHouse;
private Response _addResult;
private Response<ILoadBalancer> _getResult;
private string _key;
private Mock<ILoadBalancerFactory> _factory;
private ServiceProviderConfiguration _serviceProviderConfig;
public LoadBalancerHouseTests()
{
_factory = new Mock<ILoadBalancerFactory>();
_loadBalancerHouse = new LoadBalancerHouse(_factory.Object);
}
[Fact]
public void should_store_load_balancer_on_first_request()
{
var reRoute = new ReRouteBuilder().WithReRouteKey("test").Build();
this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
.Then(x => x.ThenItIsAdded())
.BDDfy();
}
[Fact]
public void should_not_store_load_balancer_on_second_request()
{
var reRoute = new ReRouteBuilder().WithLoadBalancer("FakeLoadBalancer").WithReRouteKey("test").Build();
this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
.When(x => x.WhenWeGetTheLoadBalancer(reRoute))
.Then(x => x.ThenItIsReturned())
.BDDfy();
}
[Fact]
public void should_store_load_balancers_by_key()
{
var reRoute = new ReRouteBuilder().WithReRouteKey("test").Build();
var reRouteTwo = new ReRouteBuilder().WithReRouteKey("testtwo").Build();
this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
.And(x => x.GivenThereIsALoadBalancer(reRouteTwo, new FakeRoundRobinLoadBalancer()))
.When(x => x.WhenWeGetTheLoadBalancer(reRoute))
.Then(x => x.ThenTheLoadBalancerIs<FakeLoadBalancer>())
.When(x => x.WhenWeGetTheLoadBalancer(reRouteTwo))
.Then(x => x.ThenTheLoadBalancerIs<FakeRoundRobinLoadBalancer>())
.BDDfy();
}
[Fact]
public void should_return_error_if_exception()
{
var reRoute = new ReRouteBuilder().Build();
this.When(x => x.WhenWeGetTheLoadBalancer(reRoute))
.Then(x => x.ThenAnErrorIsReturned())
.BDDfy();
}
[Fact]
public void should_get_new_load_balancer_if_reroute_load_balancer_has_changed()
{
var reRoute = new ReRouteBuilder().WithLoadBalancer("FakeLoadBalancer").WithReRouteKey("test").Build();
var reRouteTwo = new ReRouteBuilder().WithLoadBalancer("LeastConnection").WithReRouteKey("test").Build();
this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
.When(x => x.WhenWeGetTheLoadBalancer(reRoute))
.Then(x => x.ThenTheLoadBalancerIs<FakeLoadBalancer>())
.When(x => x.WhenIGetTheReRouteWithTheSameKeyButDifferentLoadBalancer(reRouteTwo))
.Then(x => x.ThenTheLoadBalancerIs<LeastConnection>())
.BDDfy();
}
private void WhenIGetTheReRouteWithTheSameKeyButDifferentLoadBalancer(ReRoute reRoute)
{
_reRoute = reRoute;
_factory.Setup(x => x.Get(_reRoute, _serviceProviderConfig)).ReturnsAsync(new LeastConnection(null, null));
_getResult = _loadBalancerHouse.Get(_reRoute, _serviceProviderConfig).Result;
}
private void ThenAnErrorIsReturned()
{
_getResult.IsError.ShouldBeTrue();
_getResult.Errors[0].ShouldBeOfType<UnableToFindLoadBalancerError>();
}
private void ThenTheLoadBalancerIs<T>()
{
_getResult.Data.ShouldBeOfType<T>();
}
private void ThenItIsAdded()
{
_getResult.IsError.ShouldBe(false);
_getResult.ShouldBeOfType<OkResponse<ILoadBalancer>>();
_getResult.Data.ShouldBe(_loadBalancer);
_factory.Verify(x => x.Get(_reRoute, _serviceProviderConfig), Times.Once);
}
private void GivenThereIsALoadBalancer(ReRoute reRoute, ILoadBalancer loadBalancer)
{
_reRoute = reRoute;
_loadBalancer = loadBalancer;
_factory.Setup(x => x.Get(_reRoute, _serviceProviderConfig)).ReturnsAsync(loadBalancer);
_getResult = _loadBalancerHouse.Get(reRoute, _serviceProviderConfig).Result;
}
private void WhenWeGetTheLoadBalancer(ReRoute reRoute)
{
_getResult = _loadBalancerHouse.Get(reRoute, _serviceProviderConfig).Result;
}
private void ThenItIsReturned()
{
_getResult.Data.ShouldBe(_loadBalancer);
_factory.Verify(x => x.Get(_reRoute, _serviceProviderConfig), Times.Once);
}
class FakeLoadBalancer : ILoadBalancer
{
public Task<Response<HostAndPort>> Lease()
{
throw new NotImplementedException();
}
public void Release(HostAndPort hostAndPort)
{
throw new NotImplementedException();
}
}
class FakeRoundRobinLoadBalancer : ILoadBalancer
{
public Task<Response<HostAndPort>> Lease()
{
throw new NotImplementedException();
}
public void Release(HostAndPort hostAndPort)
{
throw new NotImplementedException();
}
}
}
}
using System;
using System.Threading.Tasks;
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.LoadBalancer.LoadBalancers;
using Ocelot.Responses;
using Ocelot.Values;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.LoadBalancer
{
public class LoadBalancerHouseTests
{
private ReRoute _reRoute;
private ILoadBalancer _loadBalancer;
private readonly LoadBalancerHouse _loadBalancerHouse;
private Response _addResult;
private Response<ILoadBalancer> _getResult;
private string _key;
private Mock<ILoadBalancerFactory> _factory;
private ServiceProviderConfiguration _serviceProviderConfig;
public LoadBalancerHouseTests()
{
_factory = new Mock<ILoadBalancerFactory>();
_loadBalancerHouse = new LoadBalancerHouse(_factory.Object);
}
[Fact]
public void should_store_load_balancer_on_first_request()
{
var reRoute = new ReRouteBuilder().WithReRouteKey("test").Build();
this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
.Then(x => x.ThenItIsAdded())
.BDDfy();
}
[Fact]
public void should_not_store_load_balancer_on_second_request()
{
var reRoute = new ReRouteBuilder().WithLoadBalancer("FakeLoadBalancer").WithReRouteKey("test").Build();
this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
.When(x => x.WhenWeGetTheLoadBalancer(reRoute))
.Then(x => x.ThenItIsReturned())
.BDDfy();
}
[Fact]
public void should_store_load_balancers_by_key()
{
var reRoute = new ReRouteBuilder().WithReRouteKey("test").Build();
var reRouteTwo = new ReRouteBuilder().WithReRouteKey("testtwo").Build();
this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
.And(x => x.GivenThereIsALoadBalancer(reRouteTwo, new FakeRoundRobinLoadBalancer()))
.When(x => x.WhenWeGetTheLoadBalancer(reRoute))
.Then(x => x.ThenTheLoadBalancerIs<FakeLoadBalancer>())
.When(x => x.WhenWeGetTheLoadBalancer(reRouteTwo))
.Then(x => x.ThenTheLoadBalancerIs<FakeRoundRobinLoadBalancer>())
.BDDfy();
}
[Fact]
public void should_return_error_if_exception()
{
var reRoute = new ReRouteBuilder().Build();
this.When(x => x.WhenWeGetTheLoadBalancer(reRoute))
.Then(x => x.ThenAnErrorIsReturned())
.BDDfy();
}
[Fact]
public void should_get_new_load_balancer_if_reroute_load_balancer_has_changed()
{
var reRoute = new ReRouteBuilder().WithLoadBalancer("FakeLoadBalancer").WithReRouteKey("test").Build();
var reRouteTwo = new ReRouteBuilder().WithLoadBalancer("LeastConnection").WithReRouteKey("test").Build();
this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
.When(x => x.WhenWeGetTheLoadBalancer(reRoute))
.Then(x => x.ThenTheLoadBalancerIs<FakeLoadBalancer>())
.When(x => x.WhenIGetTheReRouteWithTheSameKeyButDifferentLoadBalancer(reRouteTwo))
.Then(x => x.ThenTheLoadBalancerIs<LeastConnection>())
.BDDfy();
}
private void WhenIGetTheReRouteWithTheSameKeyButDifferentLoadBalancer(ReRoute reRoute)
{
_reRoute = reRoute;
_factory.Setup(x => x.Get(_reRoute, _serviceProviderConfig)).ReturnsAsync(new LeastConnection(null, null));
_getResult = _loadBalancerHouse.Get(_reRoute, _serviceProviderConfig).Result;
}
private void ThenAnErrorIsReturned()
{
_getResult.IsError.ShouldBeTrue();
_getResult.Errors[0].ShouldBeOfType<UnableToFindLoadBalancerError>();
}
private void ThenTheLoadBalancerIs<T>()
{
_getResult.Data.ShouldBeOfType<T>();
}
private void ThenItIsAdded()
{
_getResult.IsError.ShouldBe(false);
_getResult.ShouldBeOfType<OkResponse<ILoadBalancer>>();
_getResult.Data.ShouldBe(_loadBalancer);
_factory.Verify(x => x.Get(_reRoute, _serviceProviderConfig), Times.Once);
}
private void GivenThereIsALoadBalancer(ReRoute reRoute, ILoadBalancer loadBalancer)
{
_reRoute = reRoute;
_loadBalancer = loadBalancer;
_factory.Setup(x => x.Get(_reRoute, _serviceProviderConfig)).ReturnsAsync(loadBalancer);
_getResult = _loadBalancerHouse.Get(reRoute, _serviceProviderConfig).Result;
}
private void WhenWeGetTheLoadBalancer(ReRoute reRoute)
{
_getResult = _loadBalancerHouse.Get(reRoute, _serviceProviderConfig).Result;
}
private void ThenItIsReturned()
{
_getResult.Data.ShouldBe(_loadBalancer);
_factory.Verify(x => x.Get(_reRoute, _serviceProviderConfig), Times.Once);
}
class FakeLoadBalancer : ILoadBalancer
{
public Task<Response<ServiceHostAndPort>> Lease()
{
throw new NotImplementedException();
}
public void Release(ServiceHostAndPort hostAndPort)
{
throw new NotImplementedException();
}
}
class FakeRoundRobinLoadBalancer : ILoadBalancer
{
public Task<Response<ServiceHostAndPort>> Lease()
{
throw new NotImplementedException();
}
public void Release(ServiceHostAndPort hostAndPort)
{
throw new NotImplementedException();
}
}
}
}

View File

@ -1,209 +1,209 @@
namespace Ocelot.UnitTests.LoadBalancer
{
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.Configuration.Provider;
using Ocelot.DownstreamRouteFinder;
using Ocelot.Errors;
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<ILoadBalancerHouse> _loadBalancerHouse;
private readonly Mock<ILoadBalancer> _loadBalancer;
private HostAndPort _hostAndPort;
private OkResponse<DownstreamRoute> _downstreamRoute;
private ErrorResponse<ILoadBalancer> _getLoadBalancerHouseError;
private ErrorResponse<HostAndPort> _getHostAndPortError;
private HttpRequestMessage _downstreamRequest;
private ServiceProviderConfiguration _config;
public LoadBalancerMiddlewareTests()
{
_loadBalancerHouse = new Mock<ILoadBalancerHouse>();
_loadBalancer = new Mock<ILoadBalancer>();
_loadBalancerHouse = new Mock<ILoadBalancerHouse>();
_downstreamRequest = new HttpRequestMessage(HttpMethod.Get, "");
ScopedRepository
.Setup(sr => sr.Get<HttpRequestMessage>("DownstreamRequest"))
.Returns(new OkResponse<HttpRequestMessage>(_downstreamRequest));
GivenTheTestServerIsConfigured();
}
[Fact]
public void should_call_scoped_data_repository_correctly()
{
var downstreamRoute = new DownstreamRoute(new List<Ocelot.DownstreamRouteFinder.UrlMatcher.PlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build());
var serviceProviderConfig = new ServiceProviderConfigurationBuilder()
.Build();
this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123"))
.And(x => GivenTheConfigurationIs(serviceProviderConfig))
.And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
.And(x => x.GivenTheLoadBalancerHouseReturns())
.And(x => x.GivenTheLoadBalancerReturns())
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamUrlIsReplacedWith("http://127.0.0.1:80/abc?q=123"))
.BDDfy();
}
[Fact]
public void should_set_pipeline_error_if_cannot_get_load_balancer()
{
var downstreamRoute = new DownstreamRoute(new List<Ocelot.DownstreamRouteFinder.UrlMatcher.PlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build());
var serviceProviderConfig = new ServiceProviderConfigurationBuilder()
.Build();
this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123"))
.And(x => GivenTheConfigurationIs(serviceProviderConfig))
.And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
.And(x => x.GivenTheLoadBalancerHouseReturnsAnError())
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenAnErrorStatingLoadBalancerCouldNotBeFoundIsSetOnPipeline())
.BDDfy();
}
[Fact]
public void should_set_pipeline_error_if_cannot_get_least()
{
var downstreamRoute = new DownstreamRoute(new List<Ocelot.DownstreamRouteFinder.UrlMatcher.PlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build());
var serviceProviderConfig = new ServiceProviderConfigurationBuilder()
.Build();
this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123"))
.And(x => GivenTheConfigurationIs(serviceProviderConfig))
.And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
.And(x => x.GivenTheLoadBalancerHouseReturns())
.And(x => x.GivenTheLoadBalancerReturnsAnError())
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenAnErrorStatingHostAndPortCouldNotBeFoundIsSetOnPipeline())
.BDDfy();
}
private void GivenTheConfigurationIs(ServiceProviderConfiguration config)
{
_config = config;
ScopedRepository
.Setup(x => x.Get<ServiceProviderConfiguration>("ServiceProviderConfiguration")).Returns(new OkResponse<ServiceProviderConfiguration>(config));
}
protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services)
{
services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
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);
}
private void GivenTheLoadBalancerReturnsAnError()
{
_getHostAndPortError = new ErrorResponse<HostAndPort>(new List<Error>() { new ServicesAreNullError($"services were null for bah") });
_loadBalancer
.Setup(x => x.Lease())
.ReturnsAsync(_getHostAndPortError);
}
private void GivenTheLoadBalancerReturns()
{
_hostAndPort = new HostAndPort("127.0.0.1", 80);
_loadBalancer
.Setup(x => x.Lease())
.ReturnsAsync(new OkResponse<HostAndPort>(_hostAndPort));
}
private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute)
{
_downstreamRoute = new OkResponse<DownstreamRoute>(downstreamRoute);
ScopedRepository
.Setup(x => x.Get<DownstreamRoute>(It.IsAny<string>()))
.Returns(_downstreamRoute);
}
private void GivenTheLoadBalancerHouseReturns()
{
_loadBalancerHouse
.Setup(x => x.Get(It.IsAny<ReRoute>(), It.IsAny<ServiceProviderConfiguration>()))
.ReturnsAsync(new OkResponse<ILoadBalancer>(_loadBalancer.Object));
}
private void GivenTheLoadBalancerHouseReturnsAnError()
{
_getLoadBalancerHouseError = new ErrorResponse<ILoadBalancer>(new List<Ocelot.Errors.Error>()
{
new UnableToFindLoadBalancerError($"unabe to find load balancer for bah")
});
_loadBalancerHouse
.Setup(x => x.Get(It.IsAny<ReRoute>(), It.IsAny<ServiceProviderConfiguration>()))
.ReturnsAsync(_getLoadBalancerHouseError);
}
private void ThenAnErrorStatingLoadBalancerCouldNotBeFoundIsSetOnPipeline()
{
ScopedRepository
.Verify(x => x.Add("OcelotMiddlewareError", true), Times.Once);
ScopedRepository
.Verify(x => x.Add("OcelotMiddlewareErrors", _getLoadBalancerHouseError.Errors), Times.Once);
}
private void ThenAnErrorSayingReleaseFailedIsSetOnThePipeline()
{
ScopedRepository
.Verify(x => x.Add("OcelotMiddlewareError", true), Times.Once);
ScopedRepository
.Verify(x => x.Add("OcelotMiddlewareErrors", It.IsAny<List<Error>>()), Times.Once);
}
private void ThenAnErrorStatingHostAndPortCouldNotBeFoundIsSetOnPipeline()
{
ScopedRepository
.Verify(x => x.Add("OcelotMiddlewareError", true), Times.Once);
ScopedRepository
.Verify(x => x.Add("OcelotMiddlewareErrors", _getHostAndPortError.Errors), Times.Once);
}
private void ThenTheDownstreamUrlIsReplacedWith(string expectedUri)
{
_downstreamRequest.RequestUri.OriginalString.ShouldBe(expectedUri);
}
}
}
namespace Ocelot.UnitTests.LoadBalancer
{
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.Configuration.Provider;
using Ocelot.DownstreamRouteFinder;
using Ocelot.Errors;
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<ILoadBalancerHouse> _loadBalancerHouse;
private readonly Mock<ILoadBalancer> _loadBalancer;
private ServiceHostAndPort _hostAndPort;
private OkResponse<DownstreamRoute> _downstreamRoute;
private ErrorResponse<ILoadBalancer> _getLoadBalancerHouseError;
private ErrorResponse<ServiceHostAndPort> _getHostAndPortError;
private HttpRequestMessage _downstreamRequest;
private ServiceProviderConfiguration _config;
public LoadBalancerMiddlewareTests()
{
_loadBalancerHouse = new Mock<ILoadBalancerHouse>();
_loadBalancer = new Mock<ILoadBalancer>();
_loadBalancerHouse = new Mock<ILoadBalancerHouse>();
_downstreamRequest = new HttpRequestMessage(HttpMethod.Get, "");
ScopedRepository
.Setup(sr => sr.Get<HttpRequestMessage>("DownstreamRequest"))
.Returns(new OkResponse<HttpRequestMessage>(_downstreamRequest));
GivenTheTestServerIsConfigured();
}
[Fact]
public void should_call_scoped_data_repository_correctly()
{
var downstreamRoute = new DownstreamRoute(new List<Ocelot.DownstreamRouteFinder.UrlMatcher.PlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build());
var serviceProviderConfig = new ServiceProviderConfigurationBuilder()
.Build();
this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123"))
.And(x => GivenTheConfigurationIs(serviceProviderConfig))
.And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
.And(x => x.GivenTheLoadBalancerHouseReturns())
.And(x => x.GivenTheLoadBalancerReturns())
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamUrlIsReplacedWith("http://127.0.0.1:80/abc?q=123"))
.BDDfy();
}
[Fact]
public void should_set_pipeline_error_if_cannot_get_load_balancer()
{
var downstreamRoute = new DownstreamRoute(new List<Ocelot.DownstreamRouteFinder.UrlMatcher.PlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build());
var serviceProviderConfig = new ServiceProviderConfigurationBuilder()
.Build();
this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123"))
.And(x => GivenTheConfigurationIs(serviceProviderConfig))
.And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
.And(x => x.GivenTheLoadBalancerHouseReturnsAnError())
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenAnErrorStatingLoadBalancerCouldNotBeFoundIsSetOnPipeline())
.BDDfy();
}
[Fact]
public void should_set_pipeline_error_if_cannot_get_least()
{
var downstreamRoute = new DownstreamRoute(new List<Ocelot.DownstreamRouteFinder.UrlMatcher.PlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build());
var serviceProviderConfig = new ServiceProviderConfigurationBuilder()
.Build();
this.Given(x => x.GivenTheDownStreamUrlIs("http://my.url/abc?q=123"))
.And(x => GivenTheConfigurationIs(serviceProviderConfig))
.And(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
.And(x => x.GivenTheLoadBalancerHouseReturns())
.And(x => x.GivenTheLoadBalancerReturnsAnError())
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenAnErrorStatingHostAndPortCouldNotBeFoundIsSetOnPipeline())
.BDDfy();
}
private void GivenTheConfigurationIs(ServiceProviderConfiguration config)
{
_config = config;
ScopedRepository
.Setup(x => x.Get<ServiceProviderConfiguration>("ServiceProviderConfiguration")).Returns(new OkResponse<ServiceProviderConfiguration>(config));
}
protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services)
{
services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
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);
}
private void GivenTheLoadBalancerReturnsAnError()
{
_getHostAndPortError = new ErrorResponse<ServiceHostAndPort>(new List<Error>() { new ServicesAreNullError($"services were null for bah") });
_loadBalancer
.Setup(x => x.Lease())
.ReturnsAsync(_getHostAndPortError);
}
private void GivenTheLoadBalancerReturns()
{
_hostAndPort = new ServiceHostAndPort("127.0.0.1", 80);
_loadBalancer
.Setup(x => x.Lease())
.ReturnsAsync(new OkResponse<ServiceHostAndPort>(_hostAndPort));
}
private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute)
{
_downstreamRoute = new OkResponse<DownstreamRoute>(downstreamRoute);
ScopedRepository
.Setup(x => x.Get<DownstreamRoute>(It.IsAny<string>()))
.Returns(_downstreamRoute);
}
private void GivenTheLoadBalancerHouseReturns()
{
_loadBalancerHouse
.Setup(x => x.Get(It.IsAny<ReRoute>(), It.IsAny<ServiceProviderConfiguration>()))
.ReturnsAsync(new OkResponse<ILoadBalancer>(_loadBalancer.Object));
}
private void GivenTheLoadBalancerHouseReturnsAnError()
{
_getLoadBalancerHouseError = new ErrorResponse<ILoadBalancer>(new List<Ocelot.Errors.Error>()
{
new UnableToFindLoadBalancerError($"unabe to find load balancer for bah")
});
_loadBalancerHouse
.Setup(x => x.Get(It.IsAny<ReRoute>(), It.IsAny<ServiceProviderConfiguration>()))
.ReturnsAsync(_getLoadBalancerHouseError);
}
private void ThenAnErrorStatingLoadBalancerCouldNotBeFoundIsSetOnPipeline()
{
ScopedRepository
.Verify(x => x.Add("OcelotMiddlewareError", true), Times.Once);
ScopedRepository
.Verify(x => x.Add("OcelotMiddlewareErrors", _getLoadBalancerHouseError.Errors), Times.Once);
}
private void ThenAnErrorSayingReleaseFailedIsSetOnThePipeline()
{
ScopedRepository
.Verify(x => x.Add("OcelotMiddlewareError", true), Times.Once);
ScopedRepository
.Verify(x => x.Add("OcelotMiddlewareErrors", It.IsAny<List<Error>>()), Times.Once);
}
private void ThenAnErrorStatingHostAndPortCouldNotBeFoundIsSetOnPipeline()
{
ScopedRepository
.Verify(x => x.Add("OcelotMiddlewareError", true), Times.Once);
ScopedRepository
.Verify(x => x.Add("OcelotMiddlewareErrors", _getHostAndPortError.Errors), Times.Once);
}
private void ThenTheDownstreamUrlIsReplacedWith(string expectedUri)
{
_downstreamRequest.RequestUri.OriginalString.ShouldBe(expectedUri);
}
}
}

View File

@ -1,48 +1,48 @@
using System.Collections.Generic;
using Ocelot.LoadBalancer.LoadBalancers;
using Ocelot.Responses;
using Ocelot.Values;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.LoadBalancer
{
public class NoLoadBalancerTests
{
private List<Service> _services;
private NoLoadBalancer _loadBalancer;
private Response<HostAndPort> _result;
[Fact]
public void should_return_host_and_port()
{
var hostAndPort = new HostAndPort("127.0.0.1", 80);
var services = new List<Service>
{
new Service("product", hostAndPort, string.Empty, string.Empty, new string[0])
};
this.Given(x => x.GivenServices(services))
.When(x => x.WhenIGetTheNextHostAndPort())
.Then(x => x.ThenTheHostAndPortIs(hostAndPort))
.BDDfy();
}
private void GivenServices(List<Service> services)
{
_services = services;
}
private void WhenIGetTheNextHostAndPort()
{
_loadBalancer = new NoLoadBalancer(_services);
_result = _loadBalancer.Lease().Result;
}
private void ThenTheHostAndPortIs(HostAndPort expected)
{
_result.Data.ShouldBe(expected);
}
}
}
using System.Collections.Generic;
using Ocelot.LoadBalancer.LoadBalancers;
using Ocelot.Responses;
using Ocelot.Values;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.LoadBalancer
{
public class NoLoadBalancerTests
{
private List<Service> _services;
private NoLoadBalancer _loadBalancer;
private Response<ServiceHostAndPort> _result;
[Fact]
public void should_return_host_and_port()
{
var hostAndPort = new ServiceHostAndPort("127.0.0.1", 80);
var services = new List<Service>
{
new Service("product", hostAndPort, string.Empty, string.Empty, new string[0])
};
this.Given(x => x.GivenServices(services))
.When(x => x.WhenIGetTheNextHostAndPort())
.Then(x => x.ThenTheHostAndPortIs(hostAndPort))
.BDDfy();
}
private void GivenServices(List<Service> services)
{
_services = services;
}
private void WhenIGetTheNextHostAndPort()
{
_loadBalancer = new NoLoadBalancer(_services);
_result = _loadBalancer.Lease().Result;
}
private void ThenTheHostAndPortIs(ServiceHostAndPort expected)
{
_result.Data.ShouldBe(expected);
}
}
}

View File

@ -1,69 +1,69 @@
using System.Collections.Generic;
using System.Diagnostics;
using Ocelot.LoadBalancer.LoadBalancers;
using Ocelot.Responses;
using Ocelot.Values;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
using System.Threading.Tasks;
namespace Ocelot.UnitTests.LoadBalancer
{
public class RoundRobinTests
{
private readonly RoundRobin _roundRobin;
private readonly List<Service> _services;
private Response<HostAndPort> _hostAndPort;
public RoundRobinTests()
{
_services = new List<Service>
{
new Service("product", new HostAndPort("127.0.0.1", 5000), string.Empty, string.Empty, new string[0]),
new Service("product", new HostAndPort("127.0.0.1", 5001), string.Empty, string.Empty, new string[0]),
new Service("product", new HostAndPort("127.0.0.1", 5001), string.Empty, string.Empty, new string[0])
};
_roundRobin = new RoundRobin(() => Task.FromResult(_services));
}
[Fact]
public void should_get_next_address()
{
this.Given(x => x.GivenIGetTheNextAddress())
.Then(x => x.ThenTheNextAddressIndexIs(0))
.Given(x => x.GivenIGetTheNextAddress())
.Then(x => x.ThenTheNextAddressIndexIs(1))
.Given(x => x.GivenIGetTheNextAddress())
.Then(x => x.ThenTheNextAddressIndexIs(2))
.BDDfy();
}
[Fact]
public void should_go_back_to_first_address_after_finished_last()
{
var stopWatch = Stopwatch.StartNew();
while (stopWatch.ElapsedMilliseconds < 1000)
{
var address = _roundRobin.Lease().Result;
address.Data.ShouldBe(_services[0].HostAndPort);
address = _roundRobin.Lease().Result;
address.Data.ShouldBe(_services[1].HostAndPort);
address = _roundRobin.Lease().Result;
address.Data.ShouldBe(_services[2].HostAndPort);
}
}
private void GivenIGetTheNextAddress()
{
_hostAndPort = _roundRobin.Lease().Result;
}
private void ThenTheNextAddressIndexIs(int index)
{
_hostAndPort.Data.ShouldBe(_services[index].HostAndPort);
}
}
}
using System.Collections.Generic;
using System.Diagnostics;
using Ocelot.LoadBalancer.LoadBalancers;
using Ocelot.Responses;
using Ocelot.Values;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
using System.Threading.Tasks;
namespace Ocelot.UnitTests.LoadBalancer
{
public class RoundRobinTests
{
private readonly RoundRobin _roundRobin;
private readonly List<Service> _services;
private Response<ServiceHostAndPort> _hostAndPort;
public RoundRobinTests()
{
_services = new List<Service>
{
new Service("product", new ServiceHostAndPort("127.0.0.1", 5000), string.Empty, string.Empty, new string[0]),
new Service("product", new ServiceHostAndPort("127.0.0.1", 5001), string.Empty, string.Empty, new string[0]),
new Service("product", new ServiceHostAndPort("127.0.0.1", 5001), string.Empty, string.Empty, new string[0])
};
_roundRobin = new RoundRobin(() => Task.FromResult(_services));
}
[Fact]
public void should_get_next_address()
{
this.Given(x => x.GivenIGetTheNextAddress())
.Then(x => x.ThenTheNextAddressIndexIs(0))
.Given(x => x.GivenIGetTheNextAddress())
.Then(x => x.ThenTheNextAddressIndexIs(1))
.Given(x => x.GivenIGetTheNextAddress())
.Then(x => x.ThenTheNextAddressIndexIs(2))
.BDDfy();
}
[Fact]
public void should_go_back_to_first_address_after_finished_last()
{
var stopWatch = Stopwatch.StartNew();
while (stopWatch.ElapsedMilliseconds < 1000)
{
var address = _roundRobin.Lease().Result;
address.Data.ShouldBe(_services[0].HostAndPort);
address = _roundRobin.Lease().Result;
address.Data.ShouldBe(_services[1].HostAndPort);
address = _roundRobin.Lease().Result;
address.Data.ShouldBe(_services[2].HostAndPort);
}
}
private void GivenIGetTheNextAddress()
{
_hostAndPort = _roundRobin.Lease().Result;
}
private void ThenTheNextAddressIndexIs(int index)
{
_hostAndPort.Data.ShouldBe(_services[index].HostAndPort);
}
}
}