diff --git a/src/Ocelot/Configuration/Repository/ConsulFileConfigurationRepository.cs b/src/Ocelot/Configuration/Repository/ConsulFileConfigurationRepository.cs deleted file mode 100644 index d8a352a7f..000000000 --- a/src/Ocelot/Configuration/Repository/ConsulFileConfigurationRepository.cs +++ /dev/null @@ -1,97 +0,0 @@ -namespace Ocelot.Configuration.Repository -{ - using System; - using System.Text; - using System.Threading.Tasks; - using Consul; - using Newtonsoft.Json; - using Ocelot.Configuration.File; - using Ocelot.Infrastructure.Consul; - using Ocelot.Logging; - using Ocelot.Responses; - using Ocelot.ServiceDiscovery.Configuration; - - public class ConsulFileConfigurationRepository : IFileConfigurationRepository - { - private readonly IConsulClient _consul; - private readonly string _configurationKey; - private readonly Cache.IOcelotCache _cache; - private readonly IOcelotLogger _logger; - - public ConsulFileConfigurationRepository( - Cache.IOcelotCache cache, - IInternalConfigurationRepository repo, - IConsulClientFactory factory, - IOcelotLoggerFactory loggerFactory) - { - _logger = loggerFactory.CreateLogger(); - _cache = cache; - - var internalConfig = repo.Get(); - - _configurationKey = "InternalConfiguration"; - - string token = null; - - if (!internalConfig.IsError) - { - token = internalConfig.Data.ServiceProviderConfiguration.Token; - _configurationKey = !string.IsNullOrEmpty(internalConfig.Data.ServiceProviderConfiguration.ConfigurationKey) ? - internalConfig.Data.ServiceProviderConfiguration.ConfigurationKey : _configurationKey; - } - - var config = new ConsulRegistryConfiguration(internalConfig.Data.ServiceProviderConfiguration.Host, - internalConfig.Data.ServiceProviderConfiguration.Port, _configurationKey, token); - - _consul = factory.Get(config); - } - - public async Task> Get() - { - var config = _cache.Get(_configurationKey, _configurationKey); - - if (config != null) - { - return new OkResponse(config); - } - - var queryResult = await _consul.KV.Get(_configurationKey); - - if (queryResult.Response == null) - { - return new OkResponse(null); - } - - var bytes = queryResult.Response.Value; - - var json = Encoding.UTF8.GetString(bytes); - - var consulConfig = JsonConvert.DeserializeObject(json); - - return new OkResponse(consulConfig); - } - - public async Task Set(FileConfiguration ocelotConfiguration) - { - var json = JsonConvert.SerializeObject(ocelotConfiguration, Formatting.Indented); - - var bytes = Encoding.UTF8.GetBytes(json); - - var kvPair = new KVPair(_configurationKey) - { - Value = bytes - }; - - var result = await _consul.KV.Put(kvPair); - - if (result.Response) - { - _cache.AddAndDelete(_configurationKey, ocelotConfiguration, TimeSpan.FromSeconds(3), _configurationKey); - - return new OkResponse(); - } - - return new ErrorResponse(new UnableToSetConfigInConsulError($"Unable to set FileConfiguration in consul, response status code from consul was {result.StatusCode}")); - } - } -} diff --git a/src/Ocelot/DependencyInjection/IOcelotBuilder.cs b/src/Ocelot/DependencyInjection/IOcelotBuilder.cs index 21e52f0bc..2a5abd050 100644 --- a/src/Ocelot/DependencyInjection/IOcelotBuilder.cs +++ b/src/Ocelot/DependencyInjection/IOcelotBuilder.cs @@ -10,8 +10,8 @@ namespace Ocelot.DependencyInjection public interface IOcelotBuilder { IServiceCollection Services { get; } + IConfiguration Configuration { get; } - IOcelotBuilder AddStoreOcelotConfigurationInConsul(); IOcelotAdministrationBuilder AddAdministration(string path, string secret); @@ -22,6 +22,7 @@ IOcelotBuilder AddDelegatingHandler(bool global = false) IOcelotBuilder AddSingletonDefinedAggregator() where T : class, IDefinedAggregator; + IOcelotBuilder AddTransientDefinedAggregator() where T : class, IDefinedAggregator; } diff --git a/src/Ocelot/DependencyInjection/OcelotBuilder.cs b/src/Ocelot/DependencyInjection/OcelotBuilder.cs index 727241a0a..d6d87c333 100644 --- a/src/Ocelot/DependencyInjection/OcelotBuilder.cs +++ b/src/Ocelot/DependencyInjection/OcelotBuilder.cs @@ -40,7 +40,6 @@ namespace Ocelot.DependencyInjection using Microsoft.Extensions.DependencyInjection.Extensions; using System.Net.Http; using Ocelot.Infrastructure; - using Ocelot.Infrastructure.Consul; using Ocelot.Middleware.Multiplexer; using ServiceDiscovery.Providers; using Steeltoe.Common.Discovery; @@ -148,7 +147,6 @@ public OcelotBuilder(IServiceCollection services, IConfiguration configurationRo Services.TryAddSingleton(); Services.TryAddSingleton(); Services.TryAddSingleton(); - Services.TryAddSingleton(); Services.TryAddSingleton(); Services.TryAddSingleton(); Services.TryAddSingleton(); @@ -217,13 +215,6 @@ public IOcelotBuilder AddDelegatingHandler(bool global = false) return this; } - public IOcelotBuilder AddStoreOcelotConfigurationInConsul() - { - Services.AddHostedService(); - Services.AddSingleton(); - return this; - } - private void AddIdentityServer(Action configOptions) { Services diff --git a/src/Ocelot/Infrastructure/Consul/ConsulClientFactory.cs b/src/Ocelot/Infrastructure/Consul/ConsulClientFactory.cs deleted file mode 100644 index 267999340..000000000 --- a/src/Ocelot/Infrastructure/Consul/ConsulClientFactory.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using Consul; -using Ocelot.ServiceDiscovery.Configuration; - -namespace Ocelot.Infrastructure.Consul -{ - public class ConsulClientFactory : IConsulClientFactory - { - public IConsulClient Get(ConsulRegistryConfiguration config) - { - return new ConsulClient(c => - { - c.Address = new Uri($"http://{config.Host}:{config.Port}"); - - if (!string.IsNullOrEmpty(config?.Token)) - { - c.Token = config.Token; - } - }); - } - } -} diff --git a/src/Ocelot/Infrastructure/Consul/IConsulClientFactory.cs b/src/Ocelot/Infrastructure/Consul/IConsulClientFactory.cs deleted file mode 100644 index 434286860..000000000 --- a/src/Ocelot/Infrastructure/Consul/IConsulClientFactory.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Consul; -using Ocelot.ServiceDiscovery.Configuration; - -namespace Ocelot.Infrastructure.Consul -{ - public interface IConsulClientFactory - { - IConsulClient Get(ConsulRegistryConfiguration config); - } -} diff --git a/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs b/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs index 9f5b9a20e..6f76ebf32 100644 --- a/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs +++ b/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs @@ -242,7 +242,8 @@ private static void ThrowToStopOcelotStarting(Response config) private static bool UsingConsul(IFileConfigurationRepository fileConfigRepo) { - return fileConfigRepo.GetType() == typeof(ConsulFileConfigurationRepository); + //todo - remove coupling by string + return fileConfigRepo.GetType().Name == "ConsulFileConfigurationRepository"; } private static void CreateAdministrationArea(IApplicationBuilder builder, IInternalConfiguration configuration) diff --git a/src/Ocelot/Ocelot.csproj b/src/Ocelot/Ocelot.csproj index 28c7c3d8b..38de9a00f 100644 --- a/src/Ocelot/Ocelot.csproj +++ b/src/Ocelot/Ocelot.csproj @@ -46,7 +46,6 @@ all - diff --git a/src/Ocelot/ServiceDiscovery/Configuration/ConsulRegistryConfiguration.cs b/src/Ocelot/ServiceDiscovery/Configuration/ConsulRegistryConfiguration.cs deleted file mode 100644 index b99f43ccf..000000000 --- a/src/Ocelot/ServiceDiscovery/Configuration/ConsulRegistryConfiguration.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Ocelot.ServiceDiscovery.Configuration -{ - public class ConsulRegistryConfiguration - { - public ConsulRegistryConfiguration(string host, int port, string keyOfServiceInConsul, string token) - { - Host = string.IsNullOrEmpty(host) ? "localhost" : host; - Port = port > 0 ? port : 8500; - KeyOfServiceInConsul = keyOfServiceInConsul; - Token = token; - } - - public string KeyOfServiceInConsul { get; } - public string Host { get; } - public int Port { get; } - public string Token { get; } - } -} diff --git a/src/Ocelot/ServiceDiscovery/Providers/ConsulServiceDiscoveryProvider.cs b/src/Ocelot/ServiceDiscovery/Providers/ConsulServiceDiscoveryProvider.cs deleted file mode 100644 index e8abe460f..000000000 --- a/src/Ocelot/ServiceDiscovery/Providers/ConsulServiceDiscoveryProvider.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Consul; -using Ocelot.Infrastructure.Consul; -using Ocelot.Infrastructure.Extensions; -using Ocelot.Logging; -using Ocelot.ServiceDiscovery.Configuration; -using Ocelot.Values; - -namespace Ocelot.ServiceDiscovery.Providers -{ - public class ConsulServiceDiscoveryProvider : IServiceDiscoveryProvider - { - private readonly ConsulRegistryConfiguration _config; - private readonly IOcelotLogger _logger; - private readonly IConsulClient _consul; - private const string VersionPrefix = "version-"; - - public ConsulServiceDiscoveryProvider(ConsulRegistryConfiguration config, IOcelotLoggerFactory factory, IConsulClientFactory clientFactory) - {; - _logger = factory.CreateLogger(); - - _config = config; - _consul = clientFactory.Get(_config); - } - - public async Task> Get() - { - var queryResult = await _consul.Health.Service(_config.KeyOfServiceInConsul, string.Empty, true); - - var services = new List(); - - foreach (var serviceEntry in queryResult.Response) - { - if (IsValid(serviceEntry)) - { - services.Add(BuildService(serviceEntry)); - } - else - { - _logger.LogWarning($"Unable to use service Address: {serviceEntry.Service.Address} and Port: {serviceEntry.Service.Port} as it is invalid. Address must contain host only e.g. localhost and port must be greater than 0"); - } - } - - return services.ToList(); - } - - private Service BuildService(ServiceEntry serviceEntry) - { - return new Service( - serviceEntry.Service.Service, - new ServiceHostAndPort(serviceEntry.Service.Address, serviceEntry.Service.Port), - serviceEntry.Service.ID, - GetVersionFromStrings(serviceEntry.Service.Tags), - serviceEntry.Service.Tags ?? Enumerable.Empty()); - } - - private 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; - } - - private string GetVersionFromStrings(IEnumerable strings) - { - return strings - ?.FirstOrDefault(x => x.StartsWith(VersionPrefix, StringComparison.Ordinal)) - .TrimStart(VersionPrefix); - } - } -} diff --git a/src/Ocelot/ServiceDiscovery/Providers/PolingConsulServiceDiscoveryProvider.cs b/src/Ocelot/ServiceDiscovery/Providers/PolingConsulServiceDiscoveryProvider.cs deleted file mode 100644 index 4206f7c14..000000000 --- a/src/Ocelot/ServiceDiscovery/Providers/PolingConsulServiceDiscoveryProvider.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Consul; -using Ocelot.Infrastructure.Consul; -using Ocelot.Infrastructure.Extensions; -using Ocelot.Logging; -using Ocelot.ServiceDiscovery.Configuration; -using Ocelot.Values; - -namespace Ocelot.ServiceDiscovery.Providers -{ - public class PollingConsulServiceDiscoveryProvider : IServiceDiscoveryProvider - { - private readonly IOcelotLogger _logger; - private readonly IServiceDiscoveryProvider _consulServiceDiscoveryProvider; - private readonly Timer _timer; - private bool _polling; - private List _services; - private string _keyOfServiceInConsul; - - public PollingConsulServiceDiscoveryProvider(int pollingInterval, string keyOfServiceInConsul, IOcelotLoggerFactory factory, IServiceDiscoveryProvider consulServiceDiscoveryProvider) - {; - _logger = factory.CreateLogger(); - _keyOfServiceInConsul = keyOfServiceInConsul; - _consulServiceDiscoveryProvider = consulServiceDiscoveryProvider; - _services = new List(); - - _timer = new Timer(async x => - { - if(_polling) - { - return; - } - - _polling = true; - await Poll(); - _polling = false; - - }, null, pollingInterval, pollingInterval); - } - - public Task> Get() - { - return Task.FromResult(_services); - } - - private async Task Poll() - { - _services = await _consulServiceDiscoveryProvider.Get(); - } - } -} diff --git a/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs b/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs index 88b4ce793..9d3aef256 100644 --- a/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs +++ b/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs @@ -1,26 +1,31 @@ -using System.Collections.Generic; -using Ocelot.Configuration; -using Ocelot.Infrastructure.Consul; -using Ocelot.Logging; -using Ocelot.ServiceDiscovery.Configuration; -using Ocelot.ServiceDiscovery.Providers; -using Ocelot.Values; - namespace Ocelot.ServiceDiscovery -{ +{ + using System.Collections.Generic; + using Ocelot.Configuration; + using Ocelot.Logging; + using Ocelot.ServiceDiscovery.Configuration; + using Ocelot.ServiceDiscovery.Providers; + using Ocelot.Values; + using System; + using System.Linq; + using Microsoft.Extensions.DependencyInjection; using Steeltoe.Common.Discovery; public class ServiceDiscoveryProviderFactory : IServiceDiscoveryProviderFactory { private readonly IOcelotLoggerFactory _factory; - private readonly IConsulClientFactory _consulFactory; private readonly IDiscoveryClient _eurekaClient; + private readonly List _delegates; + private readonly IServiceProvider _provider; - public ServiceDiscoveryProviderFactory(IOcelotLoggerFactory factory, IConsulClientFactory consulFactory, IDiscoveryClient eurekaClient) + public ServiceDiscoveryProviderFactory(IOcelotLoggerFactory factory, IDiscoveryClient eurekaClient, IServiceProvider provider) { _factory = factory; - _consulFactory = consulFactory; _eurekaClient = eurekaClient; + _provider = provider; + _delegates = provider + .GetServices() + .ToList(); } public IServiceDiscoveryProvider Get(ServiceProviderConfiguration serviceConfig, DownstreamReRoute reRoute) @@ -42,29 +47,27 @@ public IServiceDiscoveryProvider Get(ServiceProviderConfiguration serviceConfig, return new ConfigurationServiceProvider(services); } - private IServiceDiscoveryProvider GetServiceDiscoveryProvider(ServiceProviderConfiguration serviceConfig, string serviceName) + private IServiceDiscoveryProvider GetServiceDiscoveryProvider(ServiceProviderConfiguration config, string key) { - if (serviceConfig.Type?.ToLower() == "servicefabric") + if (config.Type?.ToLower() == "servicefabric") { - var config = new ServiceFabricConfiguration(serviceConfig.Host, serviceConfig.Port, serviceName); - return new ServiceFabricServiceDiscoveryProvider(config); + var sfConfig = new ServiceFabricConfiguration(config.Host, config.Port, key); + return new ServiceFabricServiceDiscoveryProvider(sfConfig); } - if (serviceConfig.Type?.ToLower() == "eureka") + if (config.Type?.ToLower() == "eureka") { - return new EurekaServiceDiscoveryProvider(serviceName, _eurekaClient); + return new EurekaServiceDiscoveryProvider(key, _eurekaClient); } - - var consulRegistryConfiguration = new ConsulRegistryConfiguration(serviceConfig.Host, serviceConfig.Port, serviceName, serviceConfig.Token); - var consulServiceDiscoveryProvider = new ConsulServiceDiscoveryProvider(consulRegistryConfiguration, _factory, _consulFactory); + // Todo - dont just hardcode this...only expect Consul at the momement so works. + var finderDelegate = _delegates.FirstOrDefault(); - if (serviceConfig.Type?.ToLower() == "pollconsul") - { - return new PollingConsulServiceDiscoveryProvider(serviceConfig.PollingInterval, consulRegistryConfiguration.KeyOfServiceInConsul, _factory, consulServiceDiscoveryProvider); - } + var provider = finderDelegate?.Invoke(_provider, config, key); - return consulServiceDiscoveryProvider; + return provider; } } + + public delegate IServiceDiscoveryProvider ServiceDiscoveryFinderDelegate(IServiceProvider provider, ServiceProviderConfiguration config, string key); } diff --git a/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs b/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs deleted file mode 100644 index e44f7496d..000000000 --- a/test/Ocelot.AcceptanceTests/ConfigurationInConsulTests.cs +++ /dev/null @@ -1,469 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Net; -using System.Text; -using Consul; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Newtonsoft.Json; -using Ocelot.Configuration.File; -using Shouldly; -using TestStack.BDDfy; -using Xunit; -using static Ocelot.Infrastructure.Wait; - -namespace Ocelot.AcceptanceTests -{ - using Cache; - - public class ConfigurationInConsulTests : IDisposable - { - private IWebHost _builder; - private readonly Steps _steps; - private IWebHost _fakeConsulBuilder; - private FileConfiguration _config; - private List _consulServices; - - public ConfigurationInConsulTests() - { - _consulServices = new List(); - _steps = new Steps(); - } - - [Fact] - public void should_return_response_200_with_simple_url() - { - var configuration = new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - DownstreamPathTemplate = "/", - DownstreamScheme = "http", - DownstreamHostAndPorts = new List - { - new FileHostAndPort - { - Host = "localhost", - Port = 51779, - } - }, - UpstreamPathTemplate = "/", - UpstreamHttpMethod = new List { "Get" }, - } - }, - GlobalConfiguration = new FileGlobalConfiguration() - { - ServiceDiscoveryProvider = new FileServiceDiscoveryProvider() - { - Host = "localhost", - Port = 9500 - } - } - }; - - var fakeConsulServiceDiscoveryUrl = "http://localhost:9500"; - - this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, "")) - .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51779", "", 200, "Hello from Laura")) - .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfig()) - .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) - .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) - .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) - .BDDfy(); - } - - [Fact] - public void should_load_configuration_out_of_consul() - { - var consulPort = 8500; - - var configuration = new FileConfiguration - { - GlobalConfiguration = new FileGlobalConfiguration() - { - ServiceDiscoveryProvider = new FileServiceDiscoveryProvider() - { - Host = "localhost", - Port = consulPort - } - } - }; - - var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}"; - - var consulConfig = new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - DownstreamPathTemplate = "/status", - DownstreamScheme = "http", - DownstreamHostAndPorts = new List - { - new FileHostAndPort - { - Host = "localhost", - Port = 51779, - } - }, - UpstreamPathTemplate = "/cs/status", - UpstreamHttpMethod = new List {"Get"} - } - }, - GlobalConfiguration = new FileGlobalConfiguration() - { - ServiceDiscoveryProvider = new FileServiceDiscoveryProvider() - { - Host = "localhost", - Port = consulPort - } - } - }; - - this.Given(x => GivenTheConsulConfigurationIs(consulConfig)) - .And(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, "")) - .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51779", "/status", 200, "Hello from Laura")) - .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfig()) - .When(x => _steps.WhenIGetUrlOnTheApiGateway("/cs/status")) - .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) - .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) - .BDDfy(); - } - - [Fact] - public void should_load_configuration_out_of_consul_if_it_is_changed() - { - var consulPort = 8506; - var configuration = new FileConfiguration - { - GlobalConfiguration = new FileGlobalConfiguration() - { - ServiceDiscoveryProvider = new FileServiceDiscoveryProvider() - { - Host = "localhost", - Port = consulPort - } - } - }; - - var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}"; - - var consulConfig = new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - DownstreamPathTemplate = "/status", - DownstreamScheme = "http", - DownstreamHostAndPorts = new List - { - new FileHostAndPort - { - Host = "localhost", - Port = 51780, - } - }, - UpstreamPathTemplate = "/cs/status", - UpstreamHttpMethod = new List {"Get"} - } - }, - GlobalConfiguration = new FileGlobalConfiguration() - { - ServiceDiscoveryProvider = new FileServiceDiscoveryProvider() - { - Host = "localhost", - Port = consulPort - } - } - }; - - var secondConsulConfig = new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - DownstreamPathTemplate = "/status", - DownstreamScheme = "http", - DownstreamHostAndPorts = new List - { - new FileHostAndPort - { - Host = "localhost", - Port = 51780, - } - }, - UpstreamPathTemplate = "/cs/status/awesome", - UpstreamHttpMethod = new List {"Get"} - } - }, - GlobalConfiguration = new FileGlobalConfiguration() - { - ServiceDiscoveryProvider = new FileServiceDiscoveryProvider() - { - Host = "localhost", - Port = consulPort - } - } - }; - - this.Given(x => GivenTheConsulConfigurationIs(consulConfig)) - .And(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, "")) - .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51780", "/status", 200, "Hello from Laura")) - .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfig()) - .And(x => _steps.WhenIGetUrlOnTheApiGateway("/cs/status")) - .And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) - .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) - .When(x => GivenTheConsulConfigurationIs(secondConsulConfig)) - .Then(x => ThenTheConfigIsUpdatedInOcelot()) - .BDDfy(); - } - - [Fact] - public void should_handle_request_to_consul_for_downstream_service_and_make_request_no_re_routes_and_rate_limit() - { - const int consulPort = 8523; - const string serviceName = "web"; - const int downstreamServicePort = 8187; - var downstreamServiceOneUrl = $"http://localhost:{downstreamServicePort}"; - var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}"; - var serviceEntryOne = new ServiceEntry() - { - Service = new AgentService() - { - Service = serviceName, - Address = "localhost", - Port = downstreamServicePort, - ID = "web_90_0_2_224_8080", - Tags = new[] {"version-v1"} - }, - }; - - var consulConfig = new FileConfiguration - { - DynamicReRoutes = new List - { - new FileDynamicReRoute - { - ServiceName = serviceName, - RateLimitRule = new FileRateLimitRule() - { - EnableRateLimiting = true, - ClientWhitelist = new List(), - Limit = 3, - Period = "1s", - PeriodTimespan = 1000 - } - } - }, - GlobalConfiguration = new FileGlobalConfiguration - { - ServiceDiscoveryProvider = new FileServiceDiscoveryProvider - { - Host = "localhost", - Port = consulPort - }, - RateLimitOptions = new FileRateLimitOptions() - { - ClientIdHeader = "ClientId", - DisableRateLimitHeaders = false, - QuotaExceededMessage = "", - RateLimitCounterPrefix = "", - HttpStatusCode = 428 - }, - DownstreamScheme = "http", - } - }; - - var configuration = new FileConfiguration - { - GlobalConfiguration = new FileGlobalConfiguration - { - ServiceDiscoveryProvider = new FileServiceDiscoveryProvider - { - Host = "localhost", - Port = consulPort - } - } - }; - - this.Given(x => x.GivenThereIsAServiceRunningOn(downstreamServiceOneUrl, "/something", 200, "Hello from Laura")) - .And(x => GivenTheConsulConfigurationIs(consulConfig)) - .And(x => x.GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, serviceName)) - .And(x => x.GivenTheServicesAreRegisteredWithConsul(serviceEntryOne)) - .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfig()) - .When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/web/something",1)) - .Then(x => _steps.ThenTheStatusCodeShouldBe(200)) - .When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/web/something", 2)) - .Then(x => _steps.ThenTheStatusCodeShouldBe(200)) - .When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/web/something",1)) - .Then(x => _steps.ThenTheStatusCodeShouldBe(428)) - .BDDfy(); - } - - private void ThenTheConfigIsUpdatedInOcelot() - { - var result = WaitFor(20000).Until(() => { - try - { - _steps.WhenIGetUrlOnTheApiGateway("/cs/status/awesome"); - _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK); - _steps.ThenTheResponseBodyShouldBe("Hello from Laura"); - return true; - } - catch (Exception) - { - return false; - } - }); - result.ShouldBeTrue(); - } - - private void GivenTheConsulConfigurationIs(FileConfiguration config) - { - _config = config; - } - - private void GivenTheServicesAreRegisteredWithConsul(params ServiceEntry[] serviceEntries) - { - foreach(var serviceEntry in serviceEntries) - { - _consulServices.Add(serviceEntry); - } - } - - private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url, string serviceName) - { - _fakeConsulBuilder = new WebHostBuilder() - .UseUrls(url) - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseUrls(url) - .Configure(app => - { - app.Run(async context => - { - if (context.Request.Method.ToLower() == "get" && context.Request.Path.Value == "/v1/kv/InternalConfiguration") - { - var json = JsonConvert.SerializeObject(_config); - - var bytes = Encoding.UTF8.GetBytes(json); - - var base64 = Convert.ToBase64String(bytes); - - var kvp = new FakeConsulGetResponse(base64); - - await context.Response.WriteJsonAsync(new FakeConsulGetResponse[] { kvp }); - } - else if (context.Request.Method.ToLower() == "put" && context.Request.Path.Value == "/v1/kv/InternalConfiguration") - { - try - { - var reader = new StreamReader(context.Request.Body); - - var json = reader.ReadToEnd(); - - _config = JsonConvert.DeserializeObject(json); - - var response = JsonConvert.SerializeObject(true); - - await context.Response.WriteAsync(response); - } - catch (Exception e) - { - Console.WriteLine(e); - throw; - } - } - else if (context.Request.Path.Value == $"/v1/health/service/{serviceName}") - { - await context.Response.WriteJsonAsync(_consulServices); - } - }); - }) - .Build(); - - _fakeConsulBuilder.Start(); - } - - public class FakeConsulGetResponse - { - public FakeConsulGetResponse(string value) - { - Value = value; - } - - public int CreateIndex => 100; - public int ModifyIndex => 200; - public int LockIndex => 200; - public string Key => "InternalConfiguration"; - public int Flags => 0; - public string Value { get; private set; } - public string Session => "adf4238a-882b-9ddc-4a9d-5b6758e4159e"; - } - - private void GivenThereIsAServiceRunningOn(string url, string basePath, int statusCode, string responseBody) - { - _builder = new WebHostBuilder() - .UseUrls(url) - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseUrls(url) - .Configure(app => - { - app.UsePathBase(basePath); - - app.Run(async context => - { - context.Response.StatusCode = statusCode; - await context.Response.WriteAsync(responseBody); - }); - }) - .Build(); - - _builder.Start(); - } - - public void Dispose() - { - _builder?.Dispose(); - _steps.Dispose(); - } - - class FakeCache : IOcelotCache - { - public void Add(string key, FileConfiguration value, TimeSpan ttl, string region) - { - throw new NotImplementedException(); - } - - public void AddAndDelete(string key, FileConfiguration value, TimeSpan ttl, string region) - { - throw new NotImplementedException(); - } - - public FileConfiguration Get(string key, string region) - { - throw new NotImplementedException(); - } - - public void ClearRegion(string region) - { - throw new NotImplementedException(); - } - } - } -} diff --git a/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj b/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj index 02082c9f7..778fe2ef9 100644 --- a/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj +++ b/test/Ocelot.AcceptanceTests/Ocelot.AcceptanceTests.csproj @@ -50,7 +50,6 @@ - diff --git a/test/Ocelot.AcceptanceTests/ServiceDiscoveryTests.cs b/test/Ocelot.AcceptanceTests/ServiceDiscoveryTests.cs index ac5882587..8d6324d39 100644 --- a/test/Ocelot.AcceptanceTests/ServiceDiscoveryTests.cs +++ b/test/Ocelot.AcceptanceTests/ServiceDiscoveryTests.cs @@ -2,12 +2,9 @@ namespace Ocelot.AcceptanceTests { using System; using System.Collections.Generic; - using System.Linq; using System.Net; - using Consul; using Microsoft.AspNetCore.Http; using Ocelot.Configuration.File; - using Shouldly; using TestStack.BDDfy; using Xunit; using Newtonsoft.Json; @@ -16,20 +13,13 @@ namespace Ocelot.AcceptanceTests public class ServiceDiscoveryTests : IDisposable { private readonly Steps _steps; - private readonly List _consulServices; private readonly List _eurekaInstances; - private int _counterOne; - private int _counterTwo; - private static readonly object SyncLock = new object(); - private string _downstreamPath; - private string _receivedToken; private readonly ServiceHandler _serviceHandler; public ServiceDiscoveryTests() { _serviceHandler = new ServiceHandler(); _steps = new Steps(); - _consulServices = new List(); _eurekaInstances = new List(); } @@ -80,479 +70,6 @@ public void should_use_eureka_service_discovery_and_make_request() .BDDfy(); } - [Fact] - public void should_use_consul_service_discovery_and_load_balance_request() - { - var consulPort = 8502; - var serviceName = "product"; - var downstreamServiceOneUrl = "http://localhost:50881"; - var downstreamServiceTwoUrl = "http://localhost:50882"; - var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}"; - var serviceEntryOne = new ServiceEntry() - { - Service = new AgentService() - { - Service = serviceName, - Address = "localhost", - Port = 50881, - ID = Guid.NewGuid().ToString(), - Tags = new string[0] - }, - }; - var serviceEntryTwo = new ServiceEntry() - { - Service = new AgentService() - { - Service = serviceName, - Address = "localhost", - Port = 50882, - ID = Guid.NewGuid().ToString(), - Tags = new string[0] - }, - }; - - var configuration = new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - DownstreamPathTemplate = "/", - DownstreamScheme = "http", - UpstreamPathTemplate = "/", - UpstreamHttpMethod = new List { "Get" }, - ServiceName = serviceName, - LoadBalancerOptions = new FileLoadBalancerOptions { Type = "LeastConnection" }, - UseServiceDiscovery = true, - } - }, - GlobalConfiguration = new FileGlobalConfiguration() - { - ServiceDiscoveryProvider = new FileServiceDiscoveryProvider() - { - Host = "localhost", - Port = consulPort - } - } - }; - - this.Given(x => x.GivenProductServiceOneIsRunning(downstreamServiceOneUrl, 200)) - .And(x => x.GivenProductServiceTwoIsRunning(downstreamServiceTwoUrl, 200)) - .And(x => x.GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, serviceName)) - .And(x => x.GivenTheServicesAreRegisteredWithConsul(serviceEntryOne, serviceEntryTwo)) - .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) - .When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimes("/", 50)) - .Then(x => x.ThenTheTwoServicesShouldHaveBeenCalledTimes(50)) - .And(x => x.ThenBothServicesCalledRealisticAmountOfTimes(24, 26)) - .BDDfy(); - } - - [Fact] - public void should_handle_request_to_consul_for_downstream_service_and_make_request() - { - const int consulPort = 8505; - const string serviceName = "web"; - const string downstreamServiceOneUrl = "http://localhost:8080"; - var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}"; - var serviceEntryOne = new ServiceEntry() - { - Service = new AgentService() - { - Service = serviceName, - Address = "localhost", - Port = 8080, - ID = "web_90_0_2_224_8080", - Tags = new[] {"version-v1"} - }, - }; - - var configuration = new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - DownstreamPathTemplate = "/api/home", - DownstreamScheme = "http", - UpstreamPathTemplate = "/home", - UpstreamHttpMethod = new List { "Get", "Options" }, - ServiceName = serviceName, - LoadBalancerOptions = new FileLoadBalancerOptions { Type = "LeastConnection" }, - UseServiceDiscovery = true, - } - }, - GlobalConfiguration = new FileGlobalConfiguration() - { - ServiceDiscoveryProvider = new FileServiceDiscoveryProvider() - { - Host = "localhost", - Port = consulPort - } - } - }; - - this.Given(x => x.GivenThereIsAServiceRunningOn(downstreamServiceOneUrl, "/api/home", 200, "Hello from Laura")) - .And(x => x.GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, serviceName)) - .And(x => x.GivenTheServicesAreRegisteredWithConsul(serviceEntryOne)) - .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) - .When(x => _steps.WhenIGetUrlOnTheApiGateway("/home")) - .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) - .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) - .BDDfy(); - } - - [Fact] - public void should_handle_request_to_consul_for_downstream_service_and_make_request_no_re_routes() - { - const int consulPort = 8513; - const string serviceName = "web"; - const int downstreamServicePort = 8087; - var downstreamServiceOneUrl = $"http://localhost:{downstreamServicePort}"; - var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}"; - var serviceEntryOne = new ServiceEntry() - { - Service = new AgentService() - { - Service = serviceName, - Address = "localhost", - Port = downstreamServicePort, - ID = "web_90_0_2_224_8080", - Tags = new[] {"version-v1"} - }, - }; - - var configuration = new FileConfiguration - { - GlobalConfiguration = new FileGlobalConfiguration - { - ServiceDiscoveryProvider = new FileServiceDiscoveryProvider - { - Host = "localhost", - Port = consulPort - }, - DownstreamScheme = "http", - HttpHandlerOptions = new FileHttpHandlerOptions - { - AllowAutoRedirect = true, - UseCookieContainer = true, - UseTracing = false - }, - QoSOptions = new FileQoSOptions - { - TimeoutValue = 100, - DurationOfBreak = 1000, - ExceptionsAllowedBeforeBreaking = 1 - } - } - }; - - this.Given(x => x.GivenThereIsAServiceRunningOn(downstreamServiceOneUrl, "/something", 200, "Hello from Laura")) - .And(x => x.GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, serviceName)) - .And(x => x.GivenTheServicesAreRegisteredWithConsul(serviceEntryOne)) - .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) - .When(x => _steps.WhenIGetUrlOnTheApiGateway("/web/something")) - .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) - .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) - .BDDfy(); - } - - [Fact] - public void should_use_consul_service_discovery_and_load_balance_request_no_re_routes() - { - var consulPort = 8510; - var serviceName = "product"; - var serviceOnePort = 50888; - var serviceTwoPort = 50889; - var downstreamServiceOneUrl = $"http://localhost:{serviceOnePort}"; - var downstreamServiceTwoUrl = $"http://localhost:{serviceTwoPort}"; - var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}"; - var serviceEntryOne = new ServiceEntry() - { - Service = new AgentService() - { - Service = serviceName, - Address = "localhost", - Port = serviceOnePort, - ID = Guid.NewGuid().ToString(), - Tags = new string[0] - }, - }; - var serviceEntryTwo = new ServiceEntry() - { - Service = new AgentService() - { - Service = serviceName, - Address = "localhost", - Port = serviceTwoPort, - ID = Guid.NewGuid().ToString(), - Tags = new string[0] - }, - }; - - var configuration = new FileConfiguration - { - GlobalConfiguration = new FileGlobalConfiguration() - { - ServiceDiscoveryProvider = new FileServiceDiscoveryProvider() - { - Host = "localhost", - Port = consulPort - }, - LoadBalancerOptions = new FileLoadBalancerOptions { Type = "LeastConnection" }, - DownstreamScheme = "http" - } - }; - - this.Given(x => x.GivenProductServiceOneIsRunning(downstreamServiceOneUrl, 200)) - .And(x => x.GivenProductServiceTwoIsRunning(downstreamServiceTwoUrl, 200)) - .And(x => x.GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, serviceName)) - .And(x => x.GivenTheServicesAreRegisteredWithConsul(serviceEntryOne, serviceEntryTwo)) - .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) - .When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimes($"/{serviceName}/", 50)) - .Then(x => x.ThenTheTwoServicesShouldHaveBeenCalledTimes(50)) - .And(x => x.ThenBothServicesCalledRealisticAmountOfTimes(24, 26)) - .BDDfy(); - } - - [Fact] - public void should_use_token_to_make_request_to_consul() - { - var token = "abctoken"; - var consulPort = 8515; - var serviceName = "web"; - var downstreamServiceOneUrl = "http://localhost:8081"; - var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}"; - var serviceEntryOne = new ServiceEntry() - { - Service = new AgentService() - { - Service = serviceName, - Address = "localhost", - Port = 8081, - ID = "web_90_0_2_224_8080", - Tags = new[] { "version-v1" } - }, - }; - - var configuration = new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - DownstreamPathTemplate = "/api/home", - DownstreamScheme = "http", - UpstreamPathTemplate = "/home", - UpstreamHttpMethod = new List { "Get", "Options" }, - ServiceName = serviceName, - LoadBalancerOptions = new FileLoadBalancerOptions { Type = "LeastConnection" }, - UseServiceDiscovery = true, - } - }, - GlobalConfiguration = new FileGlobalConfiguration() - { - ServiceDiscoveryProvider = new FileServiceDiscoveryProvider() - { - Host = "localhost", - Port = consulPort, - Token = token - } - } - }; - - this.Given(_ => GivenThereIsAServiceRunningOn(downstreamServiceOneUrl, "/api/home", 200, "Hello from Laura")) - .And(_ => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, serviceName)) - .And(_ => GivenTheServicesAreRegisteredWithConsul(serviceEntryOne)) - .And(_ => _steps.GivenThereIsAConfiguration(configuration)) - .And(_ => _steps.GivenOcelotIsRunning()) - .When(_ => _steps.WhenIGetUrlOnTheApiGateway("/home")) - .Then(_ => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) - .And(_ => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) - .And(_ => _receivedToken.ShouldBe(token)) - .BDDfy(); - } - - [Fact] - public void should_send_request_to_service_after_it_becomes_available_in_consul() - { - var consulPort = 8501; - var serviceName = "product"; - var downstreamServiceOneUrl = "http://localhost:50879"; - var downstreamServiceTwoUrl = "http://localhost:50880"; - var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}"; - var serviceEntryOne = new ServiceEntry() - { - Service = new AgentService() - { - Service = serviceName, - Address = "localhost", - Port = 50879, - ID = Guid.NewGuid().ToString(), - Tags = new string[0] - }, - }; - var serviceEntryTwo = new ServiceEntry() - { - Service = new AgentService() - { - Service = serviceName, - Address = "localhost", - Port = 50880, - ID = Guid.NewGuid().ToString(), - Tags = new string[0] - }, - }; - - var configuration = new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - DownstreamPathTemplate = "/", - DownstreamScheme = "http", - UpstreamPathTemplate = "/", - UpstreamHttpMethod = new List { "Get" }, - ServiceName = serviceName, - LoadBalancerOptions = new FileLoadBalancerOptions { Type = "LeastConnection" }, - UseServiceDiscovery = true, - } - }, - GlobalConfiguration = new FileGlobalConfiguration() - { - ServiceDiscoveryProvider = new FileServiceDiscoveryProvider() - { - Host = "localhost", - Port = consulPort - } - } - }; - - this.Given(x => x.GivenProductServiceOneIsRunning(downstreamServiceOneUrl, 200)) - .And(x => x.GivenProductServiceTwoIsRunning(downstreamServiceTwoUrl, 200)) - .And(x => x.GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, serviceName)) - .And(x => x.GivenTheServicesAreRegisteredWithConsul(serviceEntryOne, serviceEntryTwo)) - .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) - .And(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimes("/", 10)) - .And(x => x.ThenTheTwoServicesShouldHaveBeenCalledTimes(10)) - .And(x => x.ThenBothServicesCalledRealisticAmountOfTimes(4, 6)) - .And(x => WhenIRemoveAService(serviceEntryTwo)) - .And(x => GivenIResetCounters()) - .And(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimes("/", 10)) - .And(x => ThenOnlyOneServiceHasBeenCalled()) - .And(x => WhenIAddAServiceBackIn(serviceEntryTwo)) - .And(x => GivenIResetCounters()) - .When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimes("/", 10)) - .Then(x => x.ThenTheTwoServicesShouldHaveBeenCalledTimes(10)) - .And(x => x.ThenBothServicesCalledRealisticAmountOfTimes(4, 6)) - .BDDfy(); - } - - [Fact] - public void should_handle_request_to_poll_consul_for_downstream_service_and_make_request() - { - const int consulPort = 8518; - const string serviceName = "web"; - const int downstreamServicePort = 8082; - var downstreamServiceOneUrl = $"http://localhost:{downstreamServicePort}"; - var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}"; - var serviceEntryOne = new ServiceEntry() - { - Service = new AgentService() - { - Service = serviceName, - Address = "localhost", - Port = downstreamServicePort, - ID = $"web_90_0_2_224_{downstreamServicePort}", - Tags = new[] {"version-v1"} - }, - }; - - var configuration = new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - DownstreamPathTemplate = "/api/home", - DownstreamScheme = "http", - UpstreamPathTemplate = "/home", - UpstreamHttpMethod = new List { "Get", "Options" }, - ServiceName = serviceName, - LoadBalancerOptions = new FileLoadBalancerOptions { Type = "LeastConnection" }, - UseServiceDiscovery = true, - } - }, - GlobalConfiguration = new FileGlobalConfiguration() - { - ServiceDiscoveryProvider = new FileServiceDiscoveryProvider() - { - Host = "localhost", - Port = consulPort, - Type = "PollConsul", - PollingInterval = 0 - } - } - }; - - this.Given(x => x.GivenThereIsAServiceRunningOn(downstreamServiceOneUrl, "/api/home", 200, "Hello from Laura")) - .And(x => x.GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, serviceName)) - .And(x => x.GivenTheServicesAreRegisteredWithConsul(serviceEntryOne)) - .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) - .When(x => _steps.WhenIGetUrlOnTheApiGatewayWaitingForTheResponseToBeOk("/home")) - .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) - .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) - .BDDfy(); - } - - private void WhenIAddAServiceBackIn(ServiceEntry serviceEntryTwo) - { - _consulServices.Add(serviceEntryTwo); - } - - private void ThenOnlyOneServiceHasBeenCalled() - { - _counterOne.ShouldBe(10); - _counterTwo.ShouldBe(0); - } - - private void WhenIRemoveAService(ServiceEntry serviceEntryTwo) - { - _consulServices.Remove(serviceEntryTwo); - } - - private void GivenIResetCounters() - { - _counterOne = 0; - _counterTwo = 0; - } - - private void ThenBothServicesCalledRealisticAmountOfTimes(int bottom, int top) - { - _counterOne.ShouldBeInRange(bottom, top); - _counterOne.ShouldBeInRange(bottom, top); - } - - private void ThenTheTwoServicesShouldHaveBeenCalledTimes(int expected) - { - var total = _counterOne + _counterTwo; - total.ShouldBe(expected); - } - - private void GivenTheServicesAreRegisteredWithConsul(params ServiceEntry[] serviceEntries) - { - foreach(var serviceEntry in serviceEntries) - { - _consulServices.Add(serviceEntry); - } - } - private void GivenTheServicesAreRegisteredWithEureka(params IServiceInstance[] serviceInstances) { foreach (var instance in serviceInstances) @@ -631,68 +148,6 @@ private void GivenThereIsAFakeEurekaServiceDiscoveryProvider(string url, string }); } - private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url, string serviceName) - { - _serviceHandler.GivenThereIsAServiceRunningOn(url, async context => - { - if (context.Request.Path.Value == $"/v1/health/service/{serviceName}") - { - if (context.Request.Headers.TryGetValue("X-Consul-Token", out var values)) - { - _receivedToken = values.First(); - } - - await context.Response.WriteJsonAsync(_consulServices); - } - }); - } - - private void GivenProductServiceOneIsRunning(string url, int statusCode) - { - _serviceHandler.GivenThereIsAServiceRunningOn(url, async context => - { - try - { - string response; - lock (SyncLock) - { - _counterOne++; - response = _counterOne.ToString(); - } - - context.Response.StatusCode = statusCode; - await context.Response.WriteAsync(response); - } - catch (Exception exception) - { - await context.Response.WriteAsync(exception.StackTrace); - } - }); - } - - private void GivenProductServiceTwoIsRunning(string url, int statusCode) - { - _serviceHandler.GivenThereIsAServiceRunningOn(url, async context => - { - try - { - string response; - lock (SyncLock) - { - _counterTwo++; - response = _counterTwo.ToString(); - } - - context.Response.StatusCode = statusCode; - await context.Response.WriteAsync(response); - } - catch (Exception exception) - { - await context.Response.WriteAsync(exception.StackTrace); - } - }); - } - private void GivenEurekaProductServiceOneIsRunning(string url) { _serviceHandler.GivenThereIsAServiceRunningOn(url, async context => @@ -709,25 +164,6 @@ private void GivenEurekaProductServiceOneIsRunning(string url) }); } - private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody) - { - _serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context => - { - _downstreamPath = !string.IsNullOrEmpty(context.Request.PathBase.Value) ? context.Request.PathBase.Value : context.Request.Path.Value; - - if (_downstreamPath != basePath) - { - context.Response.StatusCode = statusCode; - await context.Response.WriteAsync("downstream path didnt match base path"); - } - else - { - context.Response.StatusCode = statusCode; - await context.Response.WriteAsync(responseBody); - } - }); - } - public void Dispose() { _serviceHandler?.Dispose(); diff --git a/test/Ocelot.AcceptanceTests/Steps.cs b/test/Ocelot.AcceptanceTests/Steps.cs index c67c953ba..7841083bd 100644 --- a/test/Ocelot.AcceptanceTests/Steps.cs +++ b/test/Ocelot.AcceptanceTests/Steps.cs @@ -422,34 +422,6 @@ public void ThenTheResponseHeaderIs(string key, string value) header.First().ShouldBe(value); } - public void GivenOcelotIsRunningUsingConsulToStoreConfig() - { - _webHostBuilder = new WebHostBuilder(); - - _webHostBuilder - .ConfigureAppConfiguration((hostingContext, config) => - { - config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath); - var env = hostingContext.HostingEnvironment; - config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false) - .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: false); - config.AddJsonFile("ocelot.json", optional: true, reloadOnChange: false); - config.AddEnvironmentVariables(); - }) - .ConfigureServices(s => - { - s.AddOcelot().AddStoreOcelotConfigurationInConsul(); - }) - .Configure(app => - { - app.UseOcelot().Wait(); - }); - - _ocelotServer = new TestServer(_webHostBuilder); - - _ocelotClient = _ocelotServer.CreateClient(); - } - /// /// This is annoying cos it should be in the constructor but we need to set up the file before calling startup so its a step. /// @@ -576,24 +548,6 @@ public void WhenIGetUrlOnTheApiGateway(string url) _response = _ocelotClient.GetAsync(url).Result; } - public void WhenIGetUrlOnTheApiGatewayWaitingForTheResponseToBeOk(string url) - { - var result = WaitFor(2000).Until(() => { - try - { - _response = _ocelotClient.GetAsync(url).Result; - _response.EnsureSuccessStatusCode(); - return true; - } - catch(Exception) - { - return false; - } - }); - - result.ShouldBeTrue(); - } - public void WhenIGetUrlOnTheApiGateway(string url, string cookie, string value) { var request = _ocelotServer.CreateRequest(url); diff --git a/test/Ocelot.AcceptanceTests/TwoDownstreamServicesTests.cs b/test/Ocelot.AcceptanceTests/TwoDownstreamServicesTests.cs deleted file mode 100644 index f75298085..000000000 --- a/test/Ocelot.AcceptanceTests/TwoDownstreamServicesTests.cs +++ /dev/null @@ -1,151 +0,0 @@ -namespace Ocelot.AcceptanceTests -{ - using System; - using System.Collections.Generic; - using System.Net; - using Consul; - using Microsoft.AspNetCore.Http; - using Ocelot.Configuration.File; - using TestStack.BDDfy; - using Xunit; - - public class TwoDownstreamServicesTests : IDisposable - { - private readonly Steps _steps; - private readonly List _serviceEntries; - private string _downstreamPathOne; - private string _downstreamPathTwo; - private readonly ServiceHandler _serviceHandler; - - public TwoDownstreamServicesTests() - { - _serviceHandler = new ServiceHandler(); - _steps = new Steps(); - _serviceEntries = new List(); - } - - [Fact] - public void should_fix_issue_194() - { - var consulPort = 8503; - var downstreamServiceOneUrl = "http://localhost:8362"; - var downstreamServiceTwoUrl = "http://localhost:8330"; - var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}"; - - var configuration = new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - DownstreamPathTemplate = "/api/user/{user}", - DownstreamScheme = "http", - DownstreamHostAndPorts = new List - { - new FileHostAndPort - { - Host = "localhost", - Port = 8362, - } - }, - UpstreamPathTemplate = "/api/user/{user}", - UpstreamHttpMethod = new List { "Get" }, - }, - new FileReRoute - { - DownstreamPathTemplate = "/api/product/{product}", - DownstreamScheme = "http", - DownstreamHostAndPorts = new List - { - new FileHostAndPort - { - Host = "localhost", - Port = 8330, - } - }, - UpstreamPathTemplate = "/api/product/{product}", - UpstreamHttpMethod = new List { "Get" }, - } - }, - GlobalConfiguration = new FileGlobalConfiguration() - { - ServiceDiscoveryProvider = new FileServiceDiscoveryProvider() - { - Host = "localhost", - Port = consulPort - } - } - }; - - this.Given(x => x.GivenProductServiceOneIsRunning(downstreamServiceOneUrl, "/api/user/info", 200, "user")) - .And(x => x.GivenProductServiceTwoIsRunning(downstreamServiceTwoUrl, "/api/product/info", 200, "product")) - .And(x => x.GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl)) - .And(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) - .When(x => _steps.WhenIGetUrlOnTheApiGateway("/api/user/info?id=1")) - .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) - .And(x => _steps.ThenTheResponseBodyShouldBe("user")) - .When(x => _steps.WhenIGetUrlOnTheApiGateway("/api/product/info?id=1")) - .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) - .And(x => _steps.ThenTheResponseBodyShouldBe("product")) - .BDDfy(); - } - - private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url) - { - _serviceHandler.GivenThereIsAServiceRunningOn(url, async context => - { - if (context.Request.Path.Value == "/v1/health/service/product") - { - await context.Response.WriteJsonAsync(_serviceEntries); - } - }); - } - - private void GivenProductServiceOneIsRunning(string baseUrl, string basePath, int statusCode, string responseBody) - { - _serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context => - { - _downstreamPathOne = !string.IsNullOrEmpty(context.Request.PathBase.Value) - ? context.Request.PathBase.Value - : context.Request.Path.Value; - - if (_downstreamPathOne != basePath) - { - context.Response.StatusCode = statusCode; - await context.Response.WriteAsync("downstream path didnt match base path"); - } - else - { - context.Response.StatusCode = statusCode; - await context.Response.WriteAsync(responseBody); - } - }); - } - - private void GivenProductServiceTwoIsRunning(string baseUrl, string basePath, int statusCode, string responseBody) - { - _serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context => - { - _downstreamPathTwo = !string.IsNullOrEmpty(context.Request.PathBase.Value) ? context.Request.PathBase.Value : context.Request.Path.Value; - - if (_downstreamPathTwo != basePath) - { - context.Response.StatusCode = statusCode; - await context.Response.WriteAsync("downstream path didnt match base path"); - } - else - { - context.Response.StatusCode = statusCode; - await context.Response.WriteAsync(responseBody); - } - }); - } - - public void Dispose() - { - _serviceHandler?.Dispose(); - _steps.Dispose(); - } - } -} diff --git a/test/Ocelot.AcceptanceTests/WebSocketTests.cs b/test/Ocelot.AcceptanceTests/WebSocketTests.cs index 3036d07ae..77661613c 100644 --- a/test/Ocelot.AcceptanceTests/WebSocketTests.cs +++ b/test/Ocelot.AcceptanceTests/WebSocketTests.cs @@ -6,8 +6,6 @@ namespace Ocelot.AcceptanceTests using System.Text; using System.Threading; using System.Threading.Tasks; - using Consul; - using Microsoft.AspNetCore.Http; using Ocelot.Configuration.File; using Shouldly; using TestStack.BDDfy; @@ -17,7 +15,6 @@ public class WebSocketTests : IDisposable { private readonly List _secondRecieved; private readonly List _firstRecieved; - private readonly List _serviceEntries; private readonly Steps _steps; private readonly ServiceHandler _serviceHandler; @@ -27,7 +24,6 @@ public WebSocketTests() _steps = new Steps(); _firstRecieved = new List(); _secondRecieved = new List(); - _serviceEntries = new List(); } [Fact] @@ -109,77 +105,6 @@ public void should_proxy_websocket_input_to_downstream_service_and_use_load_bala .BDDfy(); } - [Fact] - public void should_proxy_websocket_input_to_downstream_service_and_use_service_discovery_and_load_balancer() - { - var downstreamPort = 5007; - var downstreamHost = "localhost"; - - var secondDownstreamPort = 5008; - var secondDownstreamHost = "localhost"; - - var serviceName = "websockets"; - var consulPort = 8509; - var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}"; - var serviceEntryOne = new ServiceEntry() - { - Service = new AgentService() - { - Service = serviceName, - Address = downstreamHost, - Port = downstreamPort, - ID = Guid.NewGuid().ToString(), - Tags = new string[0] - }, - }; - var serviceEntryTwo = new ServiceEntry() - { - Service = new AgentService() - { - Service = serviceName, - Address = secondDownstreamHost, - Port = secondDownstreamPort, - ID = Guid.NewGuid().ToString(), - Tags = new string[0] - }, - }; - - var config = new FileConfiguration - { - ReRoutes = new List - { - new FileReRoute - { - UpstreamPathTemplate = "/", - DownstreamPathTemplate = "/ws", - DownstreamScheme = "ws", - LoadBalancerOptions = new FileLoadBalancerOptions { Type = "RoundRobin" }, - ServiceName = serviceName, - UseServiceDiscovery = true - } - }, - GlobalConfiguration = new FileGlobalConfiguration - { - ServiceDiscoveryProvider = new FileServiceDiscoveryProvider - { - Host = "localhost", - Port = consulPort, - Type = "consul" - } - } - }; - - this.Given(_ => _steps.GivenThereIsAConfiguration(config)) - .And(_ => _steps.StartFakeOcelotWithWebSockets()) - .And(_ => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, serviceName)) - .And(_ => GivenTheServicesAreRegisteredWithConsul(serviceEntryOne, serviceEntryTwo)) - .And(_ => StartFakeDownstreamService($"http://{downstreamHost}:{downstreamPort}", "/ws")) - .And(_ => StartSecondFakeDownstreamService($"http://{secondDownstreamHost}:{secondDownstreamPort}", "/ws")) - .When(_ => WhenIStartTheClients()) - .Then(_ => ThenBothDownstreamServicesAreCalled()) - .BDDfy(); - } - private void ThenBothDownstreamServicesAreCalled() { _firstRecieved.Count.ShouldBe(10); @@ -195,25 +120,6 @@ private void ThenBothDownstreamServicesAreCalled() }); } - private void GivenTheServicesAreRegisteredWithConsul(params ServiceEntry[] serviceEntries) - { - foreach (var serviceEntry in serviceEntries) - { - _serviceEntries.Add(serviceEntry); - } - } - - private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url, string serviceName) - { - _serviceHandler.GivenThereIsAServiceRunningOn(url, async context => - { - if (context.Request.Path.Value == $"/v1/health/service/{serviceName}") - { - await context.Response.WriteJsonAsync(_serviceEntries); - } - }); - } - private async Task WhenIStartTheClients() { var firstClient = StartClient("ws://localhost:5000/"); diff --git a/test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.csproj b/test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.csproj index 19bf854fb..62e7371cd 100644 --- a/test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.csproj +++ b/test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.csproj @@ -42,7 +42,6 @@ - diff --git a/test/Ocelot.ManualTest/Ocelot.ManualTest.csproj b/test/Ocelot.ManualTest/Ocelot.ManualTest.csproj index d9ddff9c4..5c3c5cfeb 100644 --- a/test/Ocelot.ManualTest/Ocelot.ManualTest.csproj +++ b/test/Ocelot.ManualTest/Ocelot.ManualTest.csproj @@ -36,7 +36,6 @@ - all diff --git a/test/Ocelot.UnitTests/Configuration/ConsulFileConfigurationRepositoryTests.cs b/test/Ocelot.UnitTests/Configuration/ConsulFileConfigurationRepositoryTests.cs deleted file mode 100644 index d26a69fce..000000000 --- a/test/Ocelot.UnitTests/Configuration/ConsulFileConfigurationRepositoryTests.cs +++ /dev/null @@ -1,263 +0,0 @@ -namespace Ocelot.UnitTests.Configuration -{ - using Xunit; - using TestStack.BDDfy; - using Shouldly; - using Ocelot.Configuration.Repository; - using Moq; - using Ocelot.Infrastructure.Consul; - using Ocelot.Logging; - using Ocelot.Configuration.File; - using Ocelot.Cache; - using System; - using System.Collections.Generic; - using Ocelot.Responses; - using System.Threading.Tasks; - using Ocelot.Configuration; - using Ocelot.Configuration.Builder; - using Ocelot.ServiceDiscovery.Configuration; - using Consul; - using Newtonsoft.Json; - using System.Text; - using System.Threading; - using System.Linq; - - public class ConsulFileConfigurationRepositoryTests - { - private ConsulFileConfigurationRepository _repo; - private Mock> _cache; - private Mock _internalRepo; - private Mock _factory; - private Mock _loggerFactory; - private Mock _client; - private Mock _kvEndpoint; - private FileConfiguration _fileConfiguration; - private Response _setResult; - private Response _getResult; - - public ConsulFileConfigurationRepositoryTests() - { - _cache = new Mock>(); - _internalRepo = new Mock(); - _loggerFactory = new Mock(); - - _factory = new Mock(); - _client = new Mock(); - _kvEndpoint = new Mock(); - - _client - .Setup(x => x.KV) - .Returns(_kvEndpoint.Object); - - _factory - .Setup(x => x.Get(It.IsAny())) - .Returns(_client.Object); - - _internalRepo - .Setup(x => x.Get()) - .Returns(new OkResponse(new InternalConfiguration(new List(), "", new ServiceProviderConfigurationBuilder().Build(), "", It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()))); - - _repo = new ConsulFileConfigurationRepository(_cache.Object, _internalRepo.Object, _factory.Object, _loggerFactory.Object); - } - - [Fact] - public void should_set_config() - { - var config = FakeFileConfiguration(); - - this.Given(_ => GivenIHaveAConfiguration(config)) - .And(_ => GivenWritingToConsulSucceeds()) - .When(_ => WhenISetTheConfiguration()) - .Then(_ => ThenTheConfigurationIsStoredAs(config)) - .BDDfy(); - } - - [Fact] - public void should_get_config() - { - var config = FakeFileConfiguration(); - - this.Given(_ => GivenIHaveAConfiguration(config)) - .And(_ => GivenFetchFromConsulSucceeds()) - .When(_ => WhenIGetTheConfiguration()) - .Then(_ => ThenTheConfigurationIs(config)) - .BDDfy(); - } - - [Fact] - public void should_get_null_config() - { - this.Given(_ => GivenFetchFromConsulReturnsNull()) - .When(_ => WhenIGetTheConfiguration()) - .Then(_ => ThenTheConfigurationIsNull()) - .BDDfy(); - } - - [Fact] - public void should_get_config_from_cache() - { - var config = FakeFileConfiguration(); - - this.Given(_ => GivenIHaveAConfiguration(config)) - .And(_ => GivenFetchFromCacheSucceeds()) - .When(_ => WhenIGetTheConfiguration()) - .Then(_ => ThenTheConfigurationIs(config)) - .BDDfy(); - } - - [Fact] - public void should_set_config_key() - { - var config = FakeFileConfiguration(); - - this.Given(_ => GivenIHaveAConfiguration(config)) - .And(_ => GivenTheConfigKeyComesFromFileConfig("Tom")) - .And(_ => GivenFetchFromConsulSucceeds()) - .When(_ => WhenIGetTheConfiguration()) - .And(_ => ThenTheConfigKeyIs("Tom")) - .BDDfy(); - } - - [Fact] - public void should_set_default_config_key() - { - var config = FakeFileConfiguration(); - - this.Given(_ => GivenIHaveAConfiguration(config)) - .And(_ => GivenFetchFromConsulSucceeds()) - .When(_ => WhenIGetTheConfiguration()) - .And(_ => ThenTheConfigKeyIs("InternalConfiguration")) - .BDDfy(); - } - - private void ThenTheConfigKeyIs(string expected) - { - _kvEndpoint - .Verify(x => x.Get(expected, It.IsAny()), Times.Once); - } - - private void GivenTheConfigKeyComesFromFileConfig(string key) - { - _internalRepo - .Setup(x => x.Get()) - .Returns(new OkResponse(new InternalConfiguration(new List(), "", - new ServiceProviderConfigurationBuilder().WithConfigurationKey(key).Build(), "", - new LoadBalancerOptionsBuilder().Build(), "", new QoSOptionsBuilder().Build(), - new HttpHandlerOptionsBuilder().Build()))); - - _repo = new ConsulFileConfigurationRepository(_cache.Object, _internalRepo.Object, _factory.Object, _loggerFactory.Object); - } - - private void ThenTheConfigurationIsNull() - { - _getResult.Data.ShouldBeNull(); - } - - private void ThenTheConfigurationIs(FileConfiguration config) - { - var expected = JsonConvert.SerializeObject(config, Formatting.Indented); - var result = JsonConvert.SerializeObject(_getResult.Data, Formatting.Indented); - result.ShouldBe(expected); - } - - private async Task WhenIGetTheConfiguration() - { - _getResult = await _repo.Get(); - } - - private void GivenWritingToConsulSucceeds() - { - var response = new WriteResult(); - response.Response = true; - - _kvEndpoint - .Setup(x => x.Put(It.IsAny(), It.IsAny())).ReturnsAsync(response); - } - - private void GivenFetchFromCacheSucceeds() - { - _cache.Setup(x => x.Get(It.IsAny(), It.IsAny())).Returns(_fileConfiguration); - } - - private void GivenFetchFromConsulReturnsNull() - { - QueryResult result = new QueryResult(); - - _kvEndpoint - .Setup(x => x.Get(It.IsAny(), It.IsAny())) - .ReturnsAsync(result); - } - - private void GivenFetchFromConsulSucceeds() - { - var json = JsonConvert.SerializeObject(_fileConfiguration, Formatting.Indented); - - var bytes = Encoding.UTF8.GetBytes(json); - - var kvp = new KVPair("OcelotConfiguration"); - kvp.Value = bytes; - - var query = new QueryResult(); - query.Response = kvp; - - _kvEndpoint - .Setup(x => x.Get(It.IsAny(), It.IsAny())) - .ReturnsAsync(query); - } - - private void ThenTheConfigurationIsStoredAs(FileConfiguration config) - { - var json = JsonConvert.SerializeObject(config, Formatting.Indented); - - var bytes = Encoding.UTF8.GetBytes(json); - - _kvEndpoint - .Verify(x => x.Put(It.Is(k => k.Value.SequenceEqual(bytes)), It.IsAny()), Times.Once); - } - - private async Task WhenISetTheConfiguration() - { - _setResult = await _repo.Set(_fileConfiguration); - } - - private void GivenIHaveAConfiguration(FileConfiguration config) - { - _fileConfiguration = config; - } - - private FileConfiguration FakeFileConfiguration() - { - var reRoutes = new List - { - new FileReRoute - { - DownstreamHostAndPorts = new List - { - new FileHostAndPort - { - Host = "123.12.12.12", - Port = 80, - } - }, - DownstreamScheme = "https", - DownstreamPathTemplate = "/asdfs/test/{test}" - } - }; - - var globalConfiguration = new FileGlobalConfiguration - { - ServiceDiscoveryProvider = new FileServiceDiscoveryProvider - { - Port = 198, - Host = "blah" - } - }; - - return new FileConfiguration - { - GlobalConfiguration = globalConfiguration, - ReRoutes = reRoutes - }; - } - } -} diff --git a/test/Ocelot.UnitTests/DependencyInjection/OcelotBuilderTests.cs b/test/Ocelot.UnitTests/DependencyInjection/OcelotBuilderTests.cs index 9b80757cd..419fd2e01 100644 --- a/test/Ocelot.UnitTests/DependencyInjection/OcelotBuilderTests.cs +++ b/test/Ocelot.UnitTests/DependencyInjection/OcelotBuilderTests.cs @@ -1,28 +1,23 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Http; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Hosting.Internal; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Ocelot.Cache; -using Ocelot.Configuration; -using Ocelot.Configuration.File; -using Ocelot.Configuration.Setter; -using Ocelot.DependencyInjection; -using Ocelot.Requester; -using Ocelot.UnitTests.Requester; -using Shouldly; -using IdentityServer4.AccessTokenValidation; -using TestStack.BDDfy; -using Xunit; -using static Ocelot.UnitTests.Middleware.UserDefinedResponseAggregatorTests; -using Ocelot.Middleware.Multiplexer; - namespace Ocelot.UnitTests.DependencyInjection { - using Butterfly; + using System; + using System.Collections.Generic; + using System.Linq; + using System.Net.Http; + using Microsoft.AspNetCore.Hosting; + using Microsoft.AspNetCore.Hosting.Internal; + using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; + using Ocelot.Configuration.Setter; + using Ocelot.DependencyInjection; + using Ocelot.Requester; + using Ocelot.UnitTests.Requester; + using Shouldly; + using IdentityServer4.AccessTokenValidation; + using TestStack.BDDfy; + using Xunit; + using static Ocelot.UnitTests.Middleware.UserDefinedResponseAggregatorTests; + using Ocelot.Middleware.Multiplexer; public class OcelotBuilderTests { @@ -80,15 +75,6 @@ public void should_return_ocelot_builder() .BDDfy(); } - [Fact] - public void should_set_up_consul() - { - this.Given(x => WhenISetUpOcelotServices()) - .When(x => WhenISetUpConsul()) - .Then(x => ThenAnExceptionIsntThrown()) - .BDDfy(); - } - [Fact] public void should_set_up_rafty() { @@ -271,18 +257,6 @@ private void ThenTheAggregatorsAreSingleton() first.ShouldBe(second); } - private void WhenISetUpConsul() - { - try - { - _ocelotBuilder.AddStoreOcelotConfigurationInConsul(); - } - catch (Exception e) - { - _ex = e; - } - } - private void WhenISetUpRafty() { try diff --git a/test/Ocelot.UnitTests/Infrastructure/InMemoryBusTests.cs b/test/Ocelot.UnitTests/Infrastructure/InMemoryBusTests.cs index 35849dbf7..ed8f3e00e 100644 --- a/test/Ocelot.UnitTests/Infrastructure/InMemoryBusTests.cs +++ b/test/Ocelot.UnitTests/Infrastructure/InMemoryBusTests.cs @@ -22,7 +22,7 @@ public async Task should_publish_with_delay() called = true; }); _bus.Publish(new object(), 1); - await Task.Delay(10); + await Task.Delay(100); called.ShouldBeTrue(); } diff --git a/test/Ocelot.UnitTests/ServiceDiscovery/ConsulServiceDiscoveryProviderTests.cs b/test/Ocelot.UnitTests/ServiceDiscovery/ConsulServiceDiscoveryProviderTests.cs deleted file mode 100644 index 4bc05efb9..000000000 --- a/test/Ocelot.UnitTests/ServiceDiscovery/ConsulServiceDiscoveryProviderTests.cs +++ /dev/null @@ -1,297 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Consul; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Moq; -using Ocelot.Infrastructure.Consul; -using Ocelot.Logging; -using Ocelot.ServiceDiscovery.Configuration; -using Ocelot.ServiceDiscovery.Providers; -using Ocelot.Values; -using Xunit; -using TestStack.BDDfy; -using Shouldly; - -namespace Ocelot.UnitTests.ServiceDiscovery -{ - public class ConsulServiceDiscoveryProviderTests : IDisposable - { - private IWebHost _fakeConsulBuilder; - private readonly List _serviceEntries; - private ConsulServiceDiscoveryProvider _provider; - private readonly string _serviceName; - private readonly int _port; - private readonly string _consulHost; - private readonly string _fakeConsulServiceDiscoveryUrl; - private List _services; - private readonly Mock _factory; - private readonly Mock _logger; - private string _receivedToken; - private readonly IConsulClientFactory _clientFactory; - - public ConsulServiceDiscoveryProviderTests() - { - _serviceName = "test"; - _port = 8500; - _consulHost = "localhost"; - _fakeConsulServiceDiscoveryUrl = $"http://{_consulHost}:{_port}"; - _serviceEntries = new List(); - - _factory = new Mock(); - _clientFactory = new ConsulClientFactory(); - _logger = new Mock(); - _factory.Setup(x => x.CreateLogger()).Returns(_logger.Object); - - var config = new ConsulRegistryConfiguration(_consulHost, _port, _serviceName, null); - _provider = new ConsulServiceDiscoveryProvider(config, _factory.Object, _clientFactory); - } - - [Fact] - public void should_return_service_from_consul() - { - var serviceEntryOne = new ServiceEntry() - { - Service = new AgentService() - { - Service = _serviceName, - Address = "localhost", - Port = 50881, - ID = Guid.NewGuid().ToString(), - Tags = new string[0] - }, - }; - - this.Given(x =>GivenThereIsAFakeConsulServiceDiscoveryProvider(_fakeConsulServiceDiscoveryUrl, _serviceName)) - .And(x => GivenTheServicesAreRegisteredWithConsul(serviceEntryOne)) - .When(x => WhenIGetTheServices()) - .Then(x => ThenTheCountIs(1)) - .BDDfy(); - } - - [Fact] - public void should_use_token() - { - var token = "test token"; - var config = new ConsulRegistryConfiguration(_consulHost, _port, _serviceName, token); - _provider = new ConsulServiceDiscoveryProvider(config, _factory.Object, _clientFactory); - - var serviceEntryOne = new ServiceEntry() - { - Service = new AgentService() - { - Service = _serviceName, - Address = "localhost", - Port = 50881, - ID = Guid.NewGuid().ToString(), - Tags = new string[0] - }, - }; - - this.Given(_ => GivenThereIsAFakeConsulServiceDiscoveryProvider(_fakeConsulServiceDiscoveryUrl, _serviceName)) - .And(_ => GivenTheServicesAreRegisteredWithConsul(serviceEntryOne)) - .When(_ => WhenIGetTheServices()) - .Then(_ => ThenTheCountIs(1)) - .And(_ => _receivedToken.ShouldBe(token)) - .BDDfy(); - } - - [Fact] - public void should_not_return_services_with_invalid_address() - { - var serviceEntryOne = new ServiceEntry() - { - Service = new AgentService() - { - Service = _serviceName, - Address = "http://localhost", - Port = 50881, - ID = Guid.NewGuid().ToString(), - Tags = new string[0] - }, - }; - - var serviceEntryTwo = new ServiceEntry() - { - Service = new AgentService() - { - Service = _serviceName, - Address = "http://localhost", - Port = 50888, - ID = Guid.NewGuid().ToString(), - Tags = new string[0] - }, - }; - - this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(_fakeConsulServiceDiscoveryUrl, _serviceName)) - .And(x => GivenTheServicesAreRegisteredWithConsul(serviceEntryOne, serviceEntryTwo)) - .When(x => WhenIGetTheServices()) - .Then(x => ThenTheCountIs(0)) - .And(x => ThenTheLoggerHasBeenCalledCorrectlyForInvalidAddress()) - .BDDfy(); - } - - [Fact] - public void should_not_return_services_with_empty_address() - { - var serviceEntryOne = new ServiceEntry() - { - Service = new AgentService() - { - Service = _serviceName, - Address = "", - Port = 50881, - ID = Guid.NewGuid().ToString(), - Tags = new string[0] - }, - }; - - var serviceEntryTwo = new ServiceEntry() - { - Service = new AgentService() - { - Service = _serviceName, - Address = null, - Port = 50888, - ID = Guid.NewGuid().ToString(), - Tags = new string[0] - }, - }; - - this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(_fakeConsulServiceDiscoveryUrl, _serviceName)) - .And(x => GivenTheServicesAreRegisteredWithConsul(serviceEntryOne, serviceEntryTwo)) - .When(x => WhenIGetTheServices()) - .Then(x => ThenTheCountIs(0)) - .And(x => ThenTheLoggerHasBeenCalledCorrectlyForEmptyAddress()) - .BDDfy(); - } - - [Fact] - public void should_not_return_services_with_invalid_port() - { - var serviceEntryOne = new ServiceEntry() - { - Service = new AgentService() - { - Service = _serviceName, - Address = "localhost", - Port = -1, - ID = Guid.NewGuid().ToString(), - Tags = new string[0] - }, - }; - - var serviceEntryTwo = new ServiceEntry() - { - Service = new AgentService() - { - Service = _serviceName, - Address = "localhost", - Port = 0, - ID = Guid.NewGuid().ToString(), - Tags = new string[0] - }, - }; - - this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(_fakeConsulServiceDiscoveryUrl, _serviceName)) - .And(x => GivenTheServicesAreRegisteredWithConsul(serviceEntryOne, serviceEntryTwo)) - .When(x => WhenIGetTheServices()) - .Then(x => ThenTheCountIs(0)) - .And(x => ThenTheLoggerHasBeenCalledCorrectlyForInvalidPorts()) - .BDDfy(); - } - - private void ThenTheLoggerHasBeenCalledCorrectlyForInvalidAddress() - { - _logger.Verify( - x => x.LogWarning( - "Unable to use service Address: http://localhost and Port: 50881 as it is invalid. Address must contain host only e.g. localhost and port must be greater than 0"), - Times.Once); - - _logger.Verify( - x => x.LogWarning( - "Unable to use service Address: http://localhost and Port: 50888 as it is invalid. Address must contain host only e.g. localhost and port must be greater than 0"), - Times.Once); - } - - private void ThenTheLoggerHasBeenCalledCorrectlyForEmptyAddress() - { - _logger.Verify( - x => x.LogWarning( - "Unable to use service Address: and Port: 50881 as it is invalid. Address must contain host only e.g. localhost and port must be greater than 0"), - Times.Once); - - _logger.Verify( - x => x.LogWarning( - "Unable to use service Address: and Port: 50888 as it is invalid. Address must contain host only e.g. localhost and port must be greater than 0"), - Times.Once); - } - - private void ThenTheLoggerHasBeenCalledCorrectlyForInvalidPorts() - { - _logger.Verify( - x => x.LogWarning( - "Unable to use service Address: localhost and Port: -1 as it is invalid. Address must contain host only e.g. localhost and port must be greater than 0"), - Times.Once); - - _logger.Verify( - x => x.LogWarning( - "Unable to use service Address: localhost and Port: 0 as it is invalid. Address must contain host only e.g. localhost and port must be greater than 0"), - Times.Once); - } - - private void ThenTheCountIs(int count) - { - _services.Count.ShouldBe(count); - } - - private void WhenIGetTheServices() - { - _services = _provider.Get().GetAwaiter().GetResult(); - } - - private void GivenTheServicesAreRegisteredWithConsul(params ServiceEntry[] serviceEntries) - { - foreach (var serviceEntry in serviceEntries) - { - _serviceEntries.Add(serviceEntry); - } - } - - private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url, string serviceName) - { - _fakeConsulBuilder = new WebHostBuilder() - .UseUrls(url) - .UseKestrel() - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseUrls(url) - .Configure(app => - { - app.Run(async context => - { - if (context.Request.Path.Value == $"/v1/health/service/{serviceName}") - { - if (context.Request.Headers.TryGetValue("X-Consul-Token", out var values)) - { - _receivedToken = values.First(); - } - - await context.Response.WriteJsonAsync(_serviceEntries); - } - }); - }) - .Build(); - - _fakeConsulBuilder.Start(); - } - - public void Dispose() - { - _fakeConsulBuilder?.Dispose(); - } - } -} diff --git a/test/Ocelot.UnitTests/ServiceDiscovery/PollingConsulServiceDiscoveryProviderTests.cs b/test/Ocelot.UnitTests/ServiceDiscovery/PollingConsulServiceDiscoveryProviderTests.cs deleted file mode 100644 index 86d523e2d..000000000 --- a/test/Ocelot.UnitTests/ServiceDiscovery/PollingConsulServiceDiscoveryProviderTests.cs +++ /dev/null @@ -1,80 +0,0 @@ -namespace Ocelot.UnitTests.ServiceDiscovery -{ - using System; - using System.Collections.Generic; - using Moq; - using Ocelot.Logging; - using Ocelot.ServiceDiscovery.Providers; - using Ocelot.Values; - using Xunit; - using TestStack.BDDfy; - using Shouldly; - using static Ocelot.Infrastructure.Wait; - - public class PollingConsulServiceDiscoveryProviderTests - { - private readonly int _delay; - private PollingConsulServiceDiscoveryProvider _provider; - private readonly List _services; - private readonly Mock _factory; - private readonly Mock _logger; - private readonly Mock _consulServiceDiscoveryProvider; - private List _result; - - public PollingConsulServiceDiscoveryProviderTests() - { - _services = new List(); - _delay = 1; - _factory = new Mock(); - _logger = new Mock(); - _factory.Setup(x => x.CreateLogger()).Returns(_logger.Object); - _consulServiceDiscoveryProvider = new Mock(); - } - - [Fact] - public void should_return_service_from_consul() - { - var service = new Service("", new ServiceHostAndPort("", 0), "", "", new List()); - - this.Given(x => GivenConsulReturns(service)) - .When(x => WhenIGetTheServices(1)) - .Then(x => ThenTheCountIs(1)) - .BDDfy(); - } - - private void GivenConsulReturns(Service service) - { - _services.Add(service); - _consulServiceDiscoveryProvider.Setup(x => x.Get()).ReturnsAsync(_services); - } - - private void ThenTheCountIs(int count) - { - _result.Count.ShouldBe(count); - } - - private void WhenIGetTheServices(int expected) - { - _provider = new PollingConsulServiceDiscoveryProvider(_delay, "", _factory.Object, _consulServiceDiscoveryProvider.Object); - - var result = WaitFor(3000).Until(() => { - try - { - _result = _provider.Get().GetAwaiter().GetResult(); - if(_result.Count == expected) - { - return true; - } - - return false; - } - catch(Exception) - { - return false; - } - }); - - result.ShouldBeTrue(); - } - } -} diff --git a/test/Ocelot.UnitTests/ServiceDiscovery/ServiceFabricServiceDiscoveryProviderTests.cs b/test/Ocelot.UnitTests/ServiceDiscovery/ServiceFabricServiceDiscoveryProviderTests.cs index eabe72d7b..a9020e3e3 100644 --- a/test/Ocelot.UnitTests/ServiceDiscovery/ServiceFabricServiceDiscoveryProviderTests.cs +++ b/test/Ocelot.UnitTests/ServiceDiscovery/ServiceFabricServiceDiscoveryProviderTests.cs @@ -1,23 +1,12 @@ -using Ocelot.ServiceDiscovery.Configuration; -using Ocelot.ServiceDiscovery.Providers; - -namespace Ocelot.UnitTests.ServiceDiscovery +namespace Ocelot.UnitTests.ServiceDiscovery { - using System; using System.Collections.Generic; - using System.IO; - using System.Text; - using Consul; - using Microsoft.AspNetCore.Builder; - using Microsoft.AspNetCore.Hosting; - using Microsoft.AspNetCore.Http; - using Moq; - using Ocelot.Logging; - using Ocelot.ServiceDiscovery; using Ocelot.Values; using Xunit; using TestStack.BDDfy; using Shouldly; + using Ocelot.ServiceDiscovery.Configuration; + using Ocelot.ServiceDiscovery.Providers; public class ServiceFabricServiceDiscoveryProviderTests { diff --git a/test/Ocelot.UnitTests/ServiceDiscovery/ServiceProviderFactoryTests.cs b/test/Ocelot.UnitTests/ServiceDiscovery/ServiceProviderFactoryTests.cs index 9ef05f3c6..edf18cdd2 100644 --- a/test/Ocelot.UnitTests/ServiceDiscovery/ServiceProviderFactoryTests.cs +++ b/test/Ocelot.UnitTests/ServiceDiscovery/ServiceProviderFactoryTests.cs @@ -1,39 +1,41 @@ -using System; -using System.Collections.Generic; -using Moq; -using Ocelot.Configuration; -using Ocelot.Configuration.Builder; -using Ocelot.Infrastructure.Consul; -using Ocelot.Logging; -using Ocelot.ServiceDiscovery; -using Ocelot.ServiceDiscovery.Providers; -using Shouldly; -using TestStack.BDDfy; -using Xunit; - namespace Ocelot.UnitTests.ServiceDiscovery { - using Pivotal.Discovery.Client; + using System; + using System.Threading.Tasks; + using Microsoft.Extensions.DependencyInjection; using Steeltoe.Common.Discovery; + using Values; + using System.Collections.Generic; + using Moq; + using Ocelot.Configuration; + using Ocelot.Configuration.Builder; + using Ocelot.Logging; + using Ocelot.ServiceDiscovery; + using Ocelot.ServiceDiscovery.Providers; + using Shouldly; + using TestStack.BDDfy; + using Xunit; public class ServiceProviderFactoryTests { private ServiceProviderConfiguration _serviceConfig; private IServiceDiscoveryProvider _result; - private readonly ServiceDiscoveryProviderFactory _factory; + private ServiceDiscoveryProviderFactory _factory; private DownstreamReRoute _reRoute; private Mock _loggerFactory; private Mock _discoveryClient; private Mock _logger; + private IServiceProvider _provider; + private IServiceCollection _collection; public ServiceProviderFactoryTests() { _loggerFactory = new Mock(); _logger = new Mock(); - _loggerFactory.Setup(x => x.CreateLogger()).Returns(_logger.Object); _discoveryClient = new Mock(); - var consulClient = new Mock(); - _factory = new ServiceDiscoveryProviderFactory(_loggerFactory.Object, consulClient.Object, _discoveryClient.Object); + _collection = new ServiceCollection(); + _provider = _collection.BuildServiceProvider(); + _factory = new ServiceDiscoveryProviderFactory(_loggerFactory.Object, _discoveryClient.Object, _provider); } [Fact] @@ -72,7 +74,7 @@ public void should_return_list_of_configuration_services() } [Fact] - public void should_return_consul_service_provider() + public void should_call_delegate() { var reRoute = new DownstreamReRouteBuilder() .WithServiceName("product") @@ -83,27 +85,9 @@ public void should_return_consul_service_provider() .Build(); this.Given(x => x.GivenTheReRoute(serviceConfig, reRoute)) + .And(x => GivenAFakeDelegate()) .When(x => x.WhenIGetTheServiceProvider()) - .Then(x => x.ThenTheServiceProviderIs()) - .BDDfy(); - } - - [Fact] - public void should_return_polling_consul_service_provider() - { - var reRoute = new DownstreamReRouteBuilder() - .WithServiceName("product") - .WithUseServiceDiscovery(true) - .Build(); - - var serviceConfig = new ServiceProviderConfigurationBuilder() - .WithType("PollConsul") - .WithPollingInterval(100000) - .Build(); - - this.Given(x => x.GivenTheReRoute(serviceConfig, reRoute)) - .When(x => x.WhenIGetTheServiceProvider()) - .Then(x => x.ThenTheServiceProviderIs()) + .Then(x => x.ThenTheDelegateIsCalled()) .BDDfy(); } @@ -143,6 +127,27 @@ public void should_return_eureka_provider() .BDDfy(); } + private void GivenAFakeDelegate() + { + ServiceDiscoveryFinderDelegate fake = (provider, config, name) => new Fake(); + _collection.AddSingleton(fake); + _provider = _collection.BuildServiceProvider(); + _factory = new ServiceDiscoveryProviderFactory(_loggerFactory.Object, _discoveryClient.Object, _provider); + } + + class Fake : IServiceDiscoveryProvider + { + public Task> Get() + { + return null; + } + } + + private void ThenTheDelegateIsCalled() + { + _result.GetType().Name.ShouldBe("Fake"); + } + private void ThenTheFollowingServicesAreReturned(List downstreamAddresses) { var result = (ConfigurationServiceProvider)_result;