using System; using System.Collections.Generic; using System.Linq; using Moq; using Ocelot.Configuration; using Ocelot.Configuration.Builder; using Ocelot.Responses; using Ocelot.Values; using Shouldly; using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests { public class LoadBalancerFactoryTests { private ReRoute _reRoute; private LoadBalancerFactory _factory; private ILoadBalancer _result; private Mock _serviceProvider; public LoadBalancerFactoryTests() { _serviceProvider = new Mock(); _factory = new LoadBalancerFactory(_serviceProvider.Object); } [Fact] public void should_return_no_load_balancer() { var reRoute = new ReRouteBuilder() .Build(); this.Given(x => x.GivenAReRoute(reRoute)) .When(x => x.WhenIGetTheLoadBalancer()) .Then(x => x.ThenTheLoadBalancerIsReturned()) .BDDfy(); } [Fact] public void should_return_round_robin_load_balancer() { var reRoute = new ReRouteBuilder() .WithLoadBalancer("RoundRobin") .Build(); this.Given(x => x.GivenAReRoute(reRoute)) .When(x => x.WhenIGetTheLoadBalancer()) .Then(x => x.ThenTheLoadBalancerIsReturned()) .BDDfy(); } [Fact] public void should_return_round_least_connection_balancer() { var reRoute = new ReRouteBuilder() .WithLoadBalancer("LeastConnection") .Build(); this.Given(x => x.GivenAReRoute(reRoute)) .When(x => x.WhenIGetTheLoadBalancer()) .Then(x => x.ThenTheLoadBalancerIsReturned()) .BDDfy(); } [Fact] public void should_call_service_provider() { var reRoute = new ReRouteBuilder() .WithLoadBalancer("RoundRobin") .Build(); this.Given(x => x.GivenAReRoute(reRoute)) .When(x => x.WhenIGetTheLoadBalancer()) .Then(x => x.ThenTheServiceProviderIsCalledCorrectly(reRoute)) .BDDfy(); } private void ThenTheServiceProviderIsCalledCorrectly(ReRoute reRoute) { _serviceProvider .Verify(x => x.Get(), Times.Once); } private void GivenAReRoute(ReRoute reRoute) { _reRoute = reRoute; } private void WhenIGetTheLoadBalancer() { _result = _factory.Get(_reRoute); } private void ThenTheLoadBalancerIsReturned() { _result.ShouldBeOfType(); } } public class NoLoadBalancerTests { private List _services; private NoLoadBalancer _loadBalancer; private Response _result; [Fact] public void should_return_host_and_port() { var hostAndPort = new HostAndPort("127.0.0.1", 80); var services = new List { new Service("product", hostAndPort) }; this.Given(x => x.GivenServices(services)) .When(x => x.WhenIGetTheNextHostAndPort()) .Then(x => x.ThenTheHostAndPortIs(hostAndPort)) .BDDfy(); } private void GivenServices(List services) { _services = services; } private void WhenIGetTheNextHostAndPort() { _loadBalancer = new NoLoadBalancer(_services); _result = _loadBalancer.Lease(); } private void ThenTheHostAndPortIs(HostAndPort expected) { _result.Data.ShouldBe(expected); } } public class NoLoadBalancer : ILoadBalancer { private List _services; public NoLoadBalancer(List services) { _services = services; } public Response Lease() { var service = _services.FirstOrDefault(); return new OkResponse(service.HostAndPort); } public Response Release(HostAndPort hostAndPort) { return new OkResponse(); } } public interface ILoadBalancerFactory { ILoadBalancer Get(ReRoute reRoute); } public class LoadBalancerFactory : ILoadBalancerFactory { private Ocelot.ServiceDiscovery.IServiceProvider _serviceProvider; public LoadBalancerFactory(Ocelot.ServiceDiscovery.IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public ILoadBalancer Get(ReRoute reRoute) { switch (reRoute.LoadBalancer) { case "RoundRobin": return new RoundRobinLoadBalancer(_serviceProvider.Get()); case "LeastConnection": return new LeastConnectionLoadBalancer(() => _serviceProvider.Get(), reRoute.ServiceName); default: return new NoLoadBalancer(_serviceProvider.Get()); } } } }