diff --git a/Ocelot.sln b/Ocelot.sln index b59c188a2..ba34e163e 100644 --- a/Ocelot.sln +++ b/Ocelot.sln @@ -86,6 +86,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "open-tracing", "open-tracin EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OcelotOpenTracing", "samples\OcelotOpenTracing\OcelotOpenTracing.csproj", "{C9427E78-4281-4F59-A66E-17C0B66550E5}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ocelot.Common", "src\Ocelot.Common\Ocelot.Common.csproj", "{C86E258D-156D-4164-BE3D-06324CB3991A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -188,6 +190,10 @@ Global {C9427E78-4281-4F59-A66E-17C0B66550E5}.Debug|Any CPU.Build.0 = Debug|Any CPU {C9427E78-4281-4F59-A66E-17C0B66550E5}.Release|Any CPU.ActiveCfg = Release|Any CPU {C9427E78-4281-4F59-A66E-17C0B66550E5}.Release|Any CPU.Build.0 = Release|Any CPU + {C86E258D-156D-4164-BE3D-06324CB3991A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C86E258D-156D-4164-BE3D-06324CB3991A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C86E258D-156D-4164-BE3D-06324CB3991A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C86E258D-156D-4164-BE3D-06324CB3991A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -224,6 +230,7 @@ Global {11C622AD-8C0A-4CF4-811B-3DBB76550797} = {5CFB79B7-C9DC-45A4-9A75-625D92471702} {731C6A8A-69ED-445C-A132-C638AA93F9C7} = {8FA0CBA0-0338-48EB-B37F-83CA5022237C} {C9427E78-4281-4F59-A66E-17C0B66550E5} = {731C6A8A-69ED-445C-A132-C638AA93F9C7} + {C86E258D-156D-4164-BE3D-06324CB3991A} = {5CFB79B7-C9DC-45A4-9A75-625D92471702} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {21476EFF-778A-4F97-8A56-D1AF1CEC0C48} diff --git a/src/Ocelot.Common/Ocelot.Common.csproj b/src/Ocelot.Common/Ocelot.Common.csproj new file mode 100644 index 000000000..cfadb03dd --- /dev/null +++ b/src/Ocelot.Common/Ocelot.Common.csproj @@ -0,0 +1,9 @@ + + + + net7.0 + enable + enable + + + diff --git a/src/Ocelot.Common/Utils/Constants.cs b/src/Ocelot.Common/Utils/Constants.cs new file mode 100644 index 000000000..28c71bab4 --- /dev/null +++ b/src/Ocelot.Common/Utils/Constants.cs @@ -0,0 +1,8 @@ +namespace Ocelot.Common.Utils +{ + public static class Constants + { + public const string ServiceFabric = "ServiceFabric"; + public const string ConsulServiceDiscoveryProvider = "consul"; + } +} diff --git a/src/Ocelot.Provider.Consul/Consul.cs b/src/Ocelot.Provider.Consul/Consul.cs index 2e73f5271..138aac52b 100644 --- a/src/Ocelot.Provider.Consul/Consul.cs +++ b/src/Ocelot.Provider.Consul/Consul.cs @@ -1,16 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -using global::Consul; - +using Consul; using Ocelot.Infrastructure.Extensions; - using Ocelot.Logging; - using Ocelot.ServiceDiscovery.Providers; - +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; using Ocelot.Values; namespace Ocelot.Provider.Consul @@ -71,12 +66,10 @@ private static Service BuildService(ServiceEntry serviceEntry, Node serviceNode) private static bool IsValid(ServiceEntry serviceEntry) { - if (string.IsNullOrEmpty(serviceEntry.Service.Address) || serviceEntry.Service.Address.Contains("http://") || serviceEntry.Service.Address.Contains("https://") || serviceEntry.Service.Port <= 0) - { - return false; - } - - return true; + return !string.IsNullOrEmpty(serviceEntry.Service.Address) + && !serviceEntry.Service.Address.Contains("http://") + && !serviceEntry.Service.Address.Contains("https://") + && serviceEntry.Service.Port > 0; } private static string GetVersionFromStrings(IEnumerable strings) diff --git a/src/Ocelot.Provider.Consul/ConsulProviderFactory.cs b/src/Ocelot.Provider.Consul/ConsulProviderFactory.cs index 9392f461b..4c7d406e8 100644 --- a/src/Ocelot.Provider.Consul/ConsulProviderFactory.cs +++ b/src/Ocelot.Provider.Consul/ConsulProviderFactory.cs @@ -1,29 +1,46 @@ -using Ocelot.Logging; - -using Microsoft.Extensions.DependencyInjection; - +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.DependencyInjection; +using Ocelot.Logging; using Ocelot.ServiceDiscovery; -namespace Ocelot.Provider.Consul +namespace Ocelot.Provider.Consul; + +public static class ConsulProviderFactory { - public static class ConsulProviderFactory - { - public static ServiceDiscoveryFinderDelegate Get = (provider, config, route) => - { - var factory = provider.GetService(); + private static readonly List ServiceDiscoveryProviders = new(); + private static readonly object LockObject = new(); - var consulFactory = provider.GetService(); + public static ServiceDiscoveryFinderDelegate Get = (provider, config, route) => + { + var factory = provider.GetService(); + var consulFactory = provider.GetService(); + var consulRegistryConfiguration = new ConsulRegistryConfiguration(config.Scheme, config.Host, config.Port, + route.ServiceName, config.Token); + var consulServiceDiscoveryProvider = new Consul(consulRegistryConfiguration, factory, consulFactory); - var consulRegistryConfiguration = new ConsulRegistryConfiguration(config.Scheme, config.Host, config.Port, route.ServiceName, config.Token); + if (string.Compare(config.Type, "PollConsul", StringComparison.OrdinalIgnoreCase) != 0) + { + return consulServiceDiscoveryProvider; + } - var consulServiceDiscoveryProvider = new Consul(consulRegistryConfiguration, factory, consulFactory); + lock (LockObject) + { + var discoveryProvider = ServiceDiscoveryProviders.FirstOrDefault(x => x.ServiceName == route.ServiceName); - if (config.Type?.ToLower() == "pollconsul") + if (discoveryProvider != null) { - return new PollConsul(config.PollingInterval, factory, consulServiceDiscoveryProvider); + return discoveryProvider; } - return consulServiceDiscoveryProvider; - }; - } + discoveryProvider = new PollConsul( + config.PollingInterval, route.ServiceName, factory, + consulServiceDiscoveryProvider); + + ServiceDiscoveryProviders.Add(discoveryProvider); + + return discoveryProvider; + } + }; } diff --git a/src/Ocelot.Provider.Consul/PollConsul.cs b/src/Ocelot.Provider.Consul/PollConsul.cs index b5ac65d86..d42edbd9d 100644 --- a/src/Ocelot.Provider.Consul/PollConsul.cs +++ b/src/Ocelot.Provider.Consul/PollConsul.cs @@ -1,53 +1,62 @@ using Ocelot.Logging; using Ocelot.ServiceDiscovery.Providers; -using Ocelot.Values; using System; using System.Collections.Generic; -using System.Threading; +using System.Linq; using System.Threading.Tasks; +using Ocelot.Values; -namespace Ocelot.Provider.Consul; - -public sealed class PollConsul : IServiceDiscoveryProvider, IDisposable +namespace Ocelot.Provider.Consul { - private readonly IOcelotLogger _logger; - private readonly IServiceDiscoveryProvider _consulServiceDiscoveryProvider; - private Timer _timer; - private bool _polling; - private List _services; - - public PollConsul(int pollingInterval, IOcelotLoggerFactory factory, IServiceDiscoveryProvider consulServiceDiscoveryProvider) + public sealed class PollConsul : IServiceDiscoveryProvider { - _logger = factory.CreateLogger(); - _consulServiceDiscoveryProvider = consulServiceDiscoveryProvider; - _services = new List(); + private readonly IOcelotLogger _logger; + private readonly IServiceDiscoveryProvider _consulServiceDiscoveryProvider; - _timer = new Timer(async x => + private readonly int _pollingInterval; + private DateTime _lastUpdateTime; + private readonly object _lockObject = new(); + + private List _services; + + public PollConsul(int pollingInterval, string serviceName, IOcelotLoggerFactory factory, IServiceDiscoveryProvider consulServiceDiscoveryProvider) { - if (_polling) + _logger = factory.CreateLogger(); + _consulServiceDiscoveryProvider = consulServiceDiscoveryProvider; + _pollingInterval = pollingInterval; + ServiceName = serviceName; + _services = new List(); + + //initializing with update time = DateTime.MinValue + //polling will occur then. + _lastUpdateTime = DateTime.MinValue; + } + + public string ServiceName { get; } + + /// + /// Getting the services, but, if first call, + /// retrieving the services and then starting the timer. + /// + /// the service list. + public Task> Get() + { + lock (_lockObject) { - return; - } + var refreshTime = _lastUpdateTime.AddMilliseconds(_pollingInterval); - _polling = true; - await Poll(); - _polling = false; - }, null, pollingInterval, pollingInterval); - } - - public void Dispose() - { - _timer?.Dispose(); - _timer = null; - } + //checking if any services available + if (refreshTime >= DateTime.UtcNow && _services.Any()) + { + return Task.FromResult(_services); + } - public Task> Get() - { - return Task.FromResult(_services); - } + _logger.LogInformation($"Retrieving new client information for service: {ServiceName}"); + _services = _consulServiceDiscoveryProvider.Get().Result; + _lastUpdateTime = DateTime.UtcNow; - private async Task Poll() - { - _services = await _consulServiceDiscoveryProvider.Get(); + return Task.FromResult(_services); + } + } } } diff --git a/src/Ocelot/Configuration/Creator/ServiceProviderConfigurationCreator.cs b/src/Ocelot/Configuration/Creator/ServiceProviderConfigurationCreator.cs index ee6c9a7ae..9ebdb1f80 100644 --- a/src/Ocelot/Configuration/Creator/ServiceProviderConfigurationCreator.cs +++ b/src/Ocelot/Configuration/Creator/ServiceProviderConfigurationCreator.cs @@ -1,3 +1,4 @@ +using Ocelot.Common.Utils; using Ocelot.Configuration.Builder; using Ocelot.Configuration.File; @@ -12,7 +13,7 @@ public ServiceProviderConfiguration Create(FileGlobalConfiguration globalConfigu var host = globalConfiguration?.ServiceDiscoveryProvider?.Host ?? "localhost"; var type = !string.IsNullOrEmpty(globalConfiguration?.ServiceDiscoveryProvider?.Type) ? globalConfiguration?.ServiceDiscoveryProvider?.Type - : "consul"; + : Constants.ConsulServiceDiscoveryProvider; var pollingInterval = globalConfiguration?.ServiceDiscoveryProvider?.PollingInterval ?? 0; var k8snamespace = globalConfiguration?.ServiceDiscoveryProvider?.Namespace ?? string.Empty; diff --git a/src/Ocelot/Configuration/Validator/FileConfigurationFluentValidator.cs b/src/Ocelot/Configuration/Validator/FileConfigurationFluentValidator.cs index 1d900c59a..1ec920eef 100644 --- a/src/Ocelot/Configuration/Validator/FileConfigurationFluentValidator.cs +++ b/src/Ocelot/Configuration/Validator/FileConfigurationFluentValidator.cs @@ -7,6 +7,7 @@ using Ocelot.Errors; using Ocelot.Configuration.File; +using Ocelot.Common.Utils; using FluentValidation; @@ -20,7 +21,6 @@ namespace Ocelot.Configuration.Validator { public class FileConfigurationFluentValidator : AbstractValidator, IConfigurationValidator { - private const string Servicefabric = "servicefabric"; private readonly List _serviceDiscoveryFinderDelegates; public FileConfigurationFluentValidator(IServiceProvider provider, RouteFluentValidator routeFluentValidator, FileGlobalConfigurationFluentValidator fileGlobalConfigurationFluentValidator) @@ -71,14 +71,14 @@ public FileConfigurationFluentValidator(IServiceProvider provider, RouteFluentVa private bool HaveServiceDiscoveryProviderRegistered(FileRoute route, FileServiceDiscoveryProvider serviceDiscoveryProvider) { return string.IsNullOrEmpty(route.ServiceName) || - serviceDiscoveryProvider?.Type?.ToLower() == Servicefabric || + serviceDiscoveryProvider?.Type?.ToLower() == Constants.ServiceFabric.ToLower() || _serviceDiscoveryFinderDelegates.Any(); } private bool HaveServiceDiscoveryProviderRegistered(FileServiceDiscoveryProvider serviceDiscoveryProvider) { return serviceDiscoveryProvider == null || - serviceDiscoveryProvider?.Type?.ToLower() == Servicefabric || + serviceDiscoveryProvider?.Type?.ToLower() == Constants.ServiceFabric.ToLower() || string.IsNullOrEmpty(serviceDiscoveryProvider.Type) || _serviceDiscoveryFinderDelegates.Any(); } diff --git a/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs b/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs index 4db8f5d96..814556476 100644 --- a/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs +++ b/src/Ocelot/DownstreamUrlCreator/Middleware/DownstreamUrlCreatorMiddleware.cs @@ -1,16 +1,16 @@ -using System; -using System.Collections.Generic; -using System.Text.RegularExpressions; -using System.Threading.Tasks; - -using Ocelot.Configuration; - -using Ocelot.DownstreamRouteFinder.UrlMatcher; - -using Ocelot.Logging; - -using Microsoft.AspNetCore.Http; - +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +using Ocelot.Configuration; + +using Ocelot.DownstreamRouteFinder.UrlMatcher; + +using Ocelot.Logging; + +using Microsoft.AspNetCore.Http; +using Ocelot.Common.Utils; using Ocelot.Middleware; using Ocelot.Request.Middleware; @@ -150,7 +150,7 @@ private static bool ContainsQueryString(DownstreamPath dsPath) private static bool ServiceFabricRequest(IInternalConfiguration config, DownstreamRoute downstreamRoute) { - return config.ServiceProviderConfiguration.Type?.ToLower() == "servicefabric" && downstreamRoute.UseServiceDiscovery; + return config.ServiceProviderConfiguration.Type?.ToLower() == Constants.ServiceFabric.ToLower() && downstreamRoute.UseServiceDiscovery; } } } diff --git a/src/Ocelot/Ocelot.csproj b/src/Ocelot/Ocelot.csproj index 29063e93d..3b9db17c2 100644 --- a/src/Ocelot/Ocelot.csproj +++ b/src/Ocelot/Ocelot.csproj @@ -36,6 +36,10 @@ all + + + + diff --git a/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs b/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs index ed04c3532..a46f056f7 100644 --- a/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs +++ b/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs @@ -1,12 +1,12 @@ -using System; -using System.Collections.Generic; - -using Ocelot.ServiceDiscovery.Configuration; - -using Ocelot.Logging; - -using Microsoft.Extensions.DependencyInjection; - +using System; +using System.Collections.Generic; + +using Ocelot.ServiceDiscovery.Configuration; + +using Ocelot.Logging; + +using Microsoft.Extensions.DependencyInjection; +using Ocelot.Common.Utils; using Ocelot.Configuration; using Ocelot.ServiceDiscovery.Providers; @@ -51,7 +51,7 @@ public Response Get(ServiceProviderConfiguration serv private Response GetServiceDiscoveryProvider(ServiceProviderConfiguration config, DownstreamRoute route) { - if (config.Type?.ToLower() == "servicefabric") + if (config.Type?.ToLower() == Constants.ServiceFabric.ToLower()) { var sfConfig = new ServiceFabricConfiguration(config.Host, config.Port, route.ServiceName); return new OkResponse(new ServiceFabricServiceDiscoveryProvider(sfConfig)); diff --git a/test/Ocelot.UnitTests/Consul/ConsulFileConfigurationRepositoryTests.cs b/test/Ocelot.UnitTests/Consul/ConsulFileConfigurationRepositoryTests.cs index 9d4d29bad..85235e9e4 100644 --- a/test/Ocelot.UnitTests/Consul/ConsulFileConfigurationRepositoryTests.cs +++ b/test/Ocelot.UnitTests/Consul/ConsulFileConfigurationRepositoryTests.cs @@ -1,19 +1,19 @@ -using global::Consul; -using Microsoft.Extensions.Options; -using Moq; -using Newtonsoft.Json; -using Ocelot.Cache; -using Ocelot.Configuration.File; -using Ocelot.Logging; -using Ocelot.Provider.Consul; -using Ocelot.Responses; -using Shouldly; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using TestStack.BDDfy; +using global::Consul; +using Microsoft.Extensions.Options; +using Moq; +using Newtonsoft.Json; +using Ocelot.Cache; +using Ocelot.Configuration.File; +using Ocelot.Logging; +using Ocelot.Provider.Consul; +using Ocelot.Responses; +using Shouldly; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using TestStack.BDDfy; using Xunit; namespace Ocelot.UnitTests.Consul diff --git a/test/Ocelot.UnitTests/Consul/PollingConsulServiceDiscoveryProviderTests.cs b/test/Ocelot.UnitTests/Consul/PollingConsulServiceDiscoveryProviderTests.cs index b3780fd21..8eaf2d028 100644 --- a/test/Ocelot.UnitTests/Consul/PollingConsulServiceDiscoveryProviderTests.cs +++ b/test/Ocelot.UnitTests/Consul/PollingConsulServiceDiscoveryProviderTests.cs @@ -42,6 +42,17 @@ public void should_return_service_from_consul() .BDDfy(); } + [Fact] + public void should_return_service_from_consul_without_delay() + { + var service = new Service(string.Empty, new ServiceHostAndPort(string.Empty, 0), string.Empty, string.Empty, new List()); + + this.Given(x => GivenConsulReturns(service)) + .When(x => WhenIGetTheServicesWithoutDelay(1)) + .Then(x => ThenTheCountIs(1)) + .BDDfy(); + } + private void GivenConsulReturns(Service service) { _services.Add(service); @@ -55,28 +66,38 @@ private void ThenTheCountIs(int count) private void WhenIGetTheServices(int expected) { - using (var provider = new PollConsul(_delay, _factory.Object, _consulServiceDiscoveryProvider.Object)) + var provider = new PollConsul(_delay, "test", _factory.Object, _consulServiceDiscoveryProvider.Object); + var result = Wait.WaitFor(3000).Until(() => { - var result = Wait.WaitFor(3000).Until(() => + try + { + _result = provider.Get().GetAwaiter().GetResult(); + return _result.Count == expected; + } + catch (Exception) { - try - { - _result = provider.Get().GetAwaiter().GetResult(); - if (_result.Count == expected) - { - return true; - } + return false; + } + }); - return false; - } - catch (Exception) - { - return false; - } - }); + result.ShouldBeTrue(); + } - result.ShouldBeTrue(); + private void WhenIGetTheServicesWithoutDelay(int expected) + { + var provider = new PollConsul(_delay, "test2", _factory.Object, _consulServiceDiscoveryProvider.Object); + bool result; + try + { + _result = provider.Get().GetAwaiter().GetResult(); + result = _result.Count == expected; + } + catch (Exception) + { + result = false; } + + result.ShouldBeTrue(); } } } diff --git a/test/Ocelot.UnitTests/Consul/ProviderFactoryTests.cs b/test/Ocelot.UnitTests/Consul/ProviderFactoryTests.cs index 7b3085c53..f4265b5b7 100644 --- a/test/Ocelot.UnitTests/Consul/ProviderFactoryTests.cs +++ b/test/Ocelot.UnitTests/Consul/ProviderFactoryTests.cs @@ -1,56 +1,117 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using System.Linq; +using Microsoft.Extensions.DependencyInjection; using Moq; using Ocelot.Configuration; using Ocelot.Configuration.Builder; using Ocelot.Logging; using Ocelot.Provider.Consul; +using Ocelot.ServiceDiscovery.Providers; using Shouldly; -using System; -using Xunit; - -namespace Ocelot.UnitTests.Consul -{ - public class ProviderFactoryTests - { - private readonly IServiceProvider _provider; - - public ProviderFactoryTests() - { - var services = new ServiceCollection(); - var loggerFactory = new Mock(); - var logger = new Mock(); - loggerFactory.Setup(x => x.CreateLogger()).Returns(logger.Object); - loggerFactory.Setup(x => x.CreateLogger()).Returns(logger.Object); - var consulFactory = new Mock(); - services.AddSingleton(consulFactory.Object); - services.AddSingleton(loggerFactory.Object); - _provider = services.BuildServiceProvider(); - } - - [Fact] - public void should_return_ConsulServiceDiscoveryProvider() - { - var route = new DownstreamRouteBuilder() - .WithServiceName(string.Empty) - .Build(); - - var provider = ConsulProviderFactory.Get(_provider, new ServiceProviderConfiguration(string.Empty, string.Empty, string.Empty, 1, string.Empty, string.Empty, 1), route); - provider.ShouldBeOfType(); - } - - [Fact] - public void should_return_PollingConsulServiceDiscoveryProvider() - { - var stopsPollerFromPolling = 10000; - - var route = new DownstreamRouteBuilder() - .WithServiceName(string.Empty) - .Build(); - - var provider = ConsulProviderFactory.Get(_provider, new ServiceProviderConfiguration("pollconsul", "http", string.Empty, 1, string.Empty, string.Empty, stopsPollerFromPolling), route); - var pollProvider = provider as PollConsul; - pollProvider.ShouldNotBeNull(); - pollProvider.Dispose(); - } - } +using Xunit; + +namespace Ocelot.UnitTests.Consul; + +public class ProviderFactoryTests +{ + private readonly IServiceProvider _provider; + + public ProviderFactoryTests() + { + var services = new ServiceCollection(); + var loggerFactory = new Mock(); + var logger = new Mock(); + loggerFactory.Setup(x => x.CreateLogger()).Returns(logger.Object); + loggerFactory.Setup(x => x.CreateLogger()).Returns(logger.Object); + var consulFactory = new Mock(); + services.AddSingleton(consulFactory.Object); + services.AddSingleton(loggerFactory.Object); + _provider = services.BuildServiceProvider(); + } + + [Fact] + public void should_return_ConsulServiceDiscoveryProvider() + { + var route = new DownstreamRouteBuilder() + .WithServiceName(string.Empty) + .Build(); + + var provider = ConsulProviderFactory.Get(_provider, + new ServiceProviderConfiguration(string.Empty, string.Empty, string.Empty, 1, string.Empty, string.Empty, + 1), route); + provider.ShouldBeOfType(); + } + + [Fact] + public void should_return_PollingConsulServiceDiscoveryProvider() + { + var provider = DummyPollingConsulServiceFactory(string.Empty); + var pollProvider = provider as PollConsul; + pollProvider.ShouldNotBeNull(); + } + + [Fact] + public void should_return_SameProviderForGivenServiceName() + { + var provider = DummyPollingConsulServiceFactory("test"); + var provider2 = DummyPollingConsulServiceFactory("test"); + + provider.ShouldBeEquivalentTo(provider2); + + var pollProvider = provider as PollConsul; + pollProvider.ShouldNotBeNull(); + + var pollProvider2 = provider2 as PollConsul; + pollProvider2.ShouldNotBeNull(); + + pollProvider.ServiceName.ShouldBeEquivalentTo(pollProvider2.ServiceName); + } + + [Theory] + [InlineData(new object[] { new[] { "service1", "service2", "service3", "service4" } })] + public void should_return_ProviderAccordingToServiceName(string[] serviceNames) + { + var providersList = serviceNames.Select(DummyPollingConsulServiceFactory).ToList(); + + foreach (var serviceName in serviceNames) + { + var currentProvider = DummyPollingConsulServiceFactory(serviceName); + providersList.ShouldContain(currentProvider); + } + + var convertedProvidersList = providersList.Select(x => x as PollConsul).ToList(); + + foreach (var convertedProvider in convertedProvidersList) + { + convertedProvider.ShouldNotBeNull(); + } + + foreach (var serviceName in serviceNames) + { + var cProvider = DummyPollingConsulServiceFactory(serviceName); + var convertedCProvider = cProvider as PollConsul; + + convertedCProvider.ShouldNotBeNull(); + + var matchingProviders = convertedProvidersList.Where(x => x.ServiceName == convertedCProvider.ServiceName) + .ToList(); + matchingProviders.ShouldHaveSingleItem(); + + matchingProviders.First().ShouldNotBeNull(); + matchingProviders.First().ServiceName.ShouldBeEquivalentTo(convertedCProvider.ServiceName); + } + } + + private IServiceDiscoveryProvider DummyPollingConsulServiceFactory(string serviceName) + { + var stopsFromPolling = 10000; + + var route = new DownstreamRouteBuilder() + .WithServiceName(serviceName) + .Build(); + + return ConsulProviderFactory.Get(_provider, + new ServiceProviderConfiguration("pollconsul", "http", string.Empty, 1, string.Empty, string.Empty, + stopsFromPolling), route); + } }