Made the file config poller use IHostedService, bit more generic, not… (#507)

* Made the file config poller use IHostedService, bit more generic, not just need to provide the correct implementations of the repo services and it will poll anything..this means we can open up redis for #458

* removed comments
This commit is contained in:
Tom Pallister 2018-07-29 18:23:49 +01:00 committed by GitHub
parent 1817564ea5
commit 0f2cf2d188
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 798 additions and 763 deletions

View File

@ -1,84 +1,112 @@
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Ocelot.Configuration.File;
using Ocelot.Configuration.Setter;
using Ocelot.Logging;
namespace Ocelot.Configuration.Repository
{
public class ConsulFileConfigurationPoller : IDisposable
{
private readonly IOcelotLogger _logger;
private readonly IFileConfigurationRepository _repo;
private readonly IFileConfigurationSetter _setter;
private string _previousAsJson;
private readonly Timer _timer;
private bool _polling;
private readonly IConsulPollerConfiguration _config;
public ConsulFileConfigurationPoller(
IOcelotLoggerFactory factory,
IFileConfigurationRepository repo,
IFileConfigurationSetter setter,
IConsulPollerConfiguration config)
{
_setter = setter;
_config = config;
_logger = factory.CreateLogger<ConsulFileConfigurationPoller>();
_repo = repo;
_previousAsJson = "";
_timer = new Timer(async x =>
{
if(_polling)
{
return;
}
_polling = true;
await Poll();
_polling = false;
}, null, _config.Delay, _config.Delay);
}
private async Task Poll()
{
_logger.LogInformation("Started polling consul");
var fileConfig = await _repo.Get();
if(fileConfig.IsError)
{
_logger.LogWarning($"error geting file config, errors are {string.Join(",", fileConfig.Errors.Select(x => x.Message))}");
return;
}
var asJson = ToJson(fileConfig.Data);
if(!fileConfig.IsError && asJson != _previousAsJson)
{
await _setter.Set(fileConfig.Data);
_previousAsJson = asJson;
}
_logger.LogInformation("Finished polling consul");
}
/// <summary>
/// We could do object comparison here but performance isnt really a problem. This might be an issue one day!
/// </summary>
/// <returns>hash of the config</returns>
private string ToJson(FileConfiguration config)
{
var currentHash = JsonConvert.SerializeObject(config);
return currentHash;
}
public void Dispose()
{
_timer.Dispose();
}
}
}
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Ocelot.Configuration.Setter;
using Ocelot.Logging;
namespace Ocelot.Configuration.Repository
{
public class FileConfigurationPoller : IHostedService, IDisposable
{
private readonly IOcelotLogger _logger;
private readonly IFileConfigurationRepository _repo;
private string _previousAsJson;
private Timer _timer;
private bool _polling;
private readonly IFileConfigurationPollerOptions _options;
private readonly IInternalConfigurationRepository _internalConfigRepo;
private readonly IInternalConfigurationCreator _internalConfigCreator;
public FileConfigurationPoller(
IOcelotLoggerFactory factory,
IFileConfigurationRepository repo,
IFileConfigurationPollerOptions options,
IInternalConfigurationRepository internalConfigRepo,
IInternalConfigurationCreator internalConfigCreator)
{
_internalConfigRepo = internalConfigRepo;
_internalConfigCreator = internalConfigCreator;
_options = options;
_logger = factory.CreateLogger<FileConfigurationPoller>();
_repo = repo;
_previousAsJson = "";
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation($"{nameof(FileConfigurationPoller)} is starting.");
_timer = new Timer(async x =>
{
if(_polling)
{
return;
}
_polling = true;
await Poll();
_polling = false;
}, null, _options.Delay, _options.Delay);
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation($"{nameof(FileConfigurationPoller)} is stopping.");
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
private async Task Poll()
{
_logger.LogInformation("Started polling consul");
var fileConfig = await _repo.Get();
if(fileConfig.IsError)
{
_logger.LogWarning($"error geting file config, errors are {string.Join(",", fileConfig.Errors.Select(x => x.Message))}");
return;
}
var asJson = ToJson(fileConfig.Data);
if(!fileConfig.IsError && asJson != _previousAsJson)
{
var config = await _internalConfigCreator.Create(fileConfig.Data);
if(!config.IsError)
{
_internalConfigRepo.AddOrReplace(config.Data);
}
_previousAsJson = asJson;
}
_logger.LogInformation("Finished polling consul");
}
/// <summary>
/// We could do object comparison here but performance isnt really a problem. This might be an issue one day!
/// </summary>
/// <returns>hash of the config</returns>
private string ToJson(FileConfiguration config)
{
var currentHash = JsonConvert.SerializeObject(config);
return currentHash;
}
public void Dispose()
{
_timer.Dispose();
}
}
}

View File

@ -1,6 +1,6 @@
namespace Ocelot.Configuration.Repository
{
public interface IConsulPollerConfiguration
public interface IFileConfigurationPollerOptions
{
int Delay { get; }
}

View File

@ -1,6 +1,6 @@
namespace Ocelot.Configuration.Repository
{
public class InMemoryConsulPollerConfiguration : IConsulPollerConfiguration
public class InMemoryFileConfigurationPollerOptions : IFileConfigurationPollerOptions
{
public int Delay => 1000;
}

View File

@ -8,7 +8,7 @@ namespace Ocelot.Configuration.Setter
{
public class FileAndInternalConfigurationSetter : IFileConfigurationSetter
{
private readonly IInternalConfigurationRepository _configRepo;
private readonly IInternalConfigurationRepository internalConfigRepo;
private readonly IInternalConfigurationCreator _configCreator;
private readonly IFileConfigurationRepository _repo;
@ -17,7 +17,7 @@ namespace Ocelot.Configuration.Setter
IInternalConfigurationCreator configCreator,
IFileConfigurationRepository repo)
{
_configRepo = configRepo;
internalConfigRepo = configRepo;
_configCreator = configCreator;
_repo = repo;
}
@ -35,7 +35,7 @@ namespace Ocelot.Configuration.Setter
if(!config.IsError)
{
_configRepo.AddOrReplace(config.Data);
internalConfigRepo.AddOrReplace(config.Data);
}
return new ErrorResponse(config.Errors);

View File

@ -160,7 +160,7 @@ namespace Ocelot.DependencyInjection
// We add this here so that we can always inject something into the factory for IoC..
_services.AddSingleton<IServiceTracer, FakeServiceTracer>();
_services.TryAddSingleton<IConsulPollerConfiguration, InMemoryConsulPollerConfiguration>();
_services.TryAddSingleton<IFileConfigurationPollerOptions, InMemoryFileConfigurationPollerOptions>();
_services.TryAddSingleton<IAddHeadersToResponse, AddHeadersToResponse>();
_services.TryAddSingleton<IPlaceholders, Placeholders>();
_services.TryAddSingleton<IConsulClientFactory, ConsulClientFactory>();
@ -245,7 +245,7 @@ namespace Ocelot.DependencyInjection
public IOcelotBuilder AddStoreOcelotConfigurationInConsul()
{
_services.AddSingleton<ConsulFileConfigurationPoller>();
_services.AddHostedService<FileConfigurationPoller>();
_services.AddSingleton<IFileConfigurationRepository, ConsulFileConfigurationRepository>();
return this;
}

View File

@ -1,266 +1,263 @@
namespace Ocelot.Middleware
{
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Options;
using System.Diagnostics;
using DependencyInjection;
using Microsoft.AspNetCore.Builder;
using Ocelot.Configuration;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Ocelot.Configuration.Repository;
using Ocelot.Configuration.Setter;
using Ocelot.Responses;
using Ocelot.Logging;
using Rafty.Concensus;
using Rafty.Infrastructure;
using Ocelot.Middleware.Pipeline;
using Pivotal.Discovery.Client;
using Rafty.Concensus.Node;
public static class OcelotMiddlewareExtensions
{
public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder)
{
await builder.UseOcelot(new OcelotPipelineConfiguration());
return builder;
}
public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder, Action<OcelotPipelineConfiguration> pipelineConfiguration)
{
var config = new OcelotPipelineConfiguration();
pipelineConfiguration?.Invoke(config);
return await builder.UseOcelot(config);
}
public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder, OcelotPipelineConfiguration pipelineConfiguration)
{
var configuration = await CreateConfiguration(builder);
CreateAdministrationArea(builder, configuration);
if (UsingRafty(builder))
{
SetUpRafty(builder);
}
if (UsingEurekaServiceDiscoveryProvider(configuration))
{
builder.UseDiscoveryClient();
}
ConfigureDiagnosticListener(builder);
var pipelineBuilder = new OcelotPipelineBuilder(builder.ApplicationServices);
pipelineBuilder.BuildOcelotPipeline(pipelineConfiguration);
var firstDelegate = pipelineBuilder.Build();
/*
inject first delegate into first piece of asp.net middleware..maybe not like this
then because we are updating the http context in ocelot it comes out correct for
rest of asp.net..
*/
builder.Properties["analysis.NextMiddlewareName"] = "TransitionToOcelotMiddleware";
builder.Use(async (context, task) =>
{
var downstreamContext = new DownstreamContext(context);
await firstDelegate.Invoke(downstreamContext);
});
return builder;
}
private static bool UsingEurekaServiceDiscoveryProvider(IInternalConfiguration configuration)
{
return configuration?.ServiceProviderConfiguration != null && configuration.ServiceProviderConfiguration.Type?.ToLower() == "eureka";
}
private static bool UsingRafty(IApplicationBuilder builder)
{
var possible = builder.ApplicationServices.GetService(typeof(INode)) as INode;
if (possible != null)
{
return true;
}
return false;
}
private static void SetUpRafty(IApplicationBuilder builder)
{
var applicationLifetime = (IApplicationLifetime)builder.ApplicationServices.GetService(typeof(IApplicationLifetime));
applicationLifetime.ApplicationStopping.Register(() => OnShutdown(builder));
var node = (INode)builder.ApplicationServices.GetService(typeof(INode));
var nodeId = (NodeId)builder.ApplicationServices.GetService(typeof(NodeId));
node.Start(nodeId);
}
private static async Task<IInternalConfiguration> CreateConfiguration(IApplicationBuilder builder)
{
// make configuration from file system?
// earlier user needed to add ocelot files in startup configuration stuff, asp.net will map it to this
var fileConfig = (IOptions<FileConfiguration>)builder.ApplicationServices.GetService(typeof(IOptions<FileConfiguration>));
// now create the config
var internalConfigCreator = (IInternalConfigurationCreator)builder.ApplicationServices.GetService(typeof(IInternalConfigurationCreator));
var internalConfig = await internalConfigCreator.Create(fileConfig.Value);
// now save it in memory
var internalConfigRepo = (IInternalConfigurationRepository)builder.ApplicationServices.GetService(typeof(IInternalConfigurationRepository));
internalConfigRepo.AddOrReplace(internalConfig.Data);
var fileConfigRepo = (IFileConfigurationRepository)builder.ApplicationServices.GetService(typeof(IFileConfigurationRepository));
var adminPath = (IAdministrationPath)builder.ApplicationServices.GetService(typeof(IAdministrationPath));
if (UsingConsul(fileConfigRepo))
namespace Ocelot.Middleware
{
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Options;
using System.Diagnostics;
using DependencyInjection;
using Microsoft.AspNetCore.Builder;
using Ocelot.Configuration;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Ocelot.Configuration.Repository;
using Ocelot.Configuration.Setter;
using Ocelot.Responses;
using Ocelot.Logging;
using Rafty.Concensus;
using Rafty.Infrastructure;
using Ocelot.Middleware.Pipeline;
using Pivotal.Discovery.Client;
using Rafty.Concensus.Node;
public static class OcelotMiddlewareExtensions
{
public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder)
{
await builder.UseOcelot(new OcelotPipelineConfiguration());
return builder;
}
public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder, Action<OcelotPipelineConfiguration> pipelineConfiguration)
{
var config = new OcelotPipelineConfiguration();
pipelineConfiguration?.Invoke(config);
return await builder.UseOcelot(config);
}
public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder, OcelotPipelineConfiguration pipelineConfiguration)
{
var configuration = await CreateConfiguration(builder);
CreateAdministrationArea(builder, configuration);
if (UsingRafty(builder))
{
//Lots of jazz happens in here..check it out if you are using consul to store your config.
await SetFileConfigInConsul(builder, fileConfigRepo, fileConfig, internalConfigCreator, internalConfigRepo);
}
else if(AdministrationApiInUse(adminPath))
SetUpRafty(builder);
}
if (UsingEurekaServiceDiscoveryProvider(configuration))
{
builder.UseDiscoveryClient();
}
ConfigureDiagnosticListener(builder);
var pipelineBuilder = new OcelotPipelineBuilder(builder.ApplicationServices);
pipelineBuilder.BuildOcelotPipeline(pipelineConfiguration);
var firstDelegate = pipelineBuilder.Build();
/*
inject first delegate into first piece of asp.net middleware..maybe not like this
then because we are updating the http context in ocelot it comes out correct for
rest of asp.net..
*/
builder.Properties["analysis.NextMiddlewareName"] = "TransitionToOcelotMiddleware";
builder.Use(async (context, task) =>
{
var downstreamContext = new DownstreamContext(context);
await firstDelegate.Invoke(downstreamContext);
});
return builder;
}
private static bool UsingEurekaServiceDiscoveryProvider(IInternalConfiguration configuration)
{
return configuration?.ServiceProviderConfiguration != null && configuration.ServiceProviderConfiguration.Type?.ToLower() == "eureka";
}
private static bool UsingRafty(IApplicationBuilder builder)
{
var possible = builder.ApplicationServices.GetService(typeof(INode)) as INode;
if (possible != null)
{
return true;
}
return false;
}
private static void SetUpRafty(IApplicationBuilder builder)
{
var applicationLifetime = (IApplicationLifetime)builder.ApplicationServices.GetService(typeof(IApplicationLifetime));
applicationLifetime.ApplicationStopping.Register(() => OnShutdown(builder));
var node = (INode)builder.ApplicationServices.GetService(typeof(INode));
var nodeId = (NodeId)builder.ApplicationServices.GetService(typeof(NodeId));
node.Start(nodeId);
}
private static async Task<IInternalConfiguration> CreateConfiguration(IApplicationBuilder builder)
{
// make configuration from file system?
// earlier user needed to add ocelot files in startup configuration stuff, asp.net will map it to this
var fileConfig = (IOptions<FileConfiguration>)builder.ApplicationServices.GetService(typeof(IOptions<FileConfiguration>));
// now create the config
var internalConfigCreator = (IInternalConfigurationCreator)builder.ApplicationServices.GetService(typeof(IInternalConfigurationCreator));
var internalConfig = await internalConfigCreator.Create(fileConfig.Value);
// now save it in memory
var internalConfigRepo = (IInternalConfigurationRepository)builder.ApplicationServices.GetService(typeof(IInternalConfigurationRepository));
internalConfigRepo.AddOrReplace(internalConfig.Data);
var fileConfigRepo = (IFileConfigurationRepository)builder.ApplicationServices.GetService(typeof(IFileConfigurationRepository));
var adminPath = (IAdministrationPath)builder.ApplicationServices.GetService(typeof(IAdministrationPath));
if (UsingConsul(fileConfigRepo))
{
//Lots of jazz happens in here..check it out if you are using consul to store your config.
await SetFileConfigInConsul(builder, fileConfigRepo, fileConfig, internalConfigCreator, internalConfigRepo);
}
else if(AdministrationApiInUse(adminPath))
{
//We have to make sure the file config is set for the ocelot.env.json and ocelot.json so that if we pull it from the
//admin api it works...boy this is getting a spit spags boll.
var fileConfigSetter = (IFileConfigurationSetter)builder.ApplicationServices.GetService(typeof(IFileConfigurationSetter));
await SetFileConfig(fileConfigSetter, fileConfig);
}
return GetOcelotConfigAndReturn(internalConfigRepo);
}
private static bool AdministrationApiInUse(IAdministrationPath adminPath)
{
return adminPath.GetType() != typeof(NullAdministrationPath);
}
private static async Task SetFileConfigInConsul(IApplicationBuilder builder,
IFileConfigurationRepository fileConfigRepo, IOptions<FileConfiguration> fileConfig,
IInternalConfigurationCreator internalConfigCreator, IInternalConfigurationRepository internalConfigRepo)
{
// get the config from consul.
var fileConfigFromConsul = await fileConfigRepo.Get();
if (IsError(fileConfigFromConsul))
{
ThrowToStopOcelotStarting(fileConfigFromConsul);
}
else if (ConfigNotStoredInConsul(fileConfigFromConsul))
{
//there was no config in consul set the file in config in consul
await fileConfigRepo.Set(fileConfig.Value);
}
else
{
// create the internal config from consul data
var internalConfig = await internalConfigCreator.Create(fileConfigFromConsul.Data);
if (IsError(internalConfig))
{
ThrowToStopOcelotStarting(internalConfig);
}
else
{
// add the internal config to the internal repo
var response = internalConfigRepo.AddOrReplace(internalConfig.Data);
if (IsError(response))
{
ThrowToStopOcelotStarting(response);
}
}
if (IsError(internalConfig))
{
ThrowToStopOcelotStarting(internalConfig);
}
}
//todo - this starts the poller if it has been registered...please this is so bad.
var hack = builder.ApplicationServices.GetService(typeof(ConsulFileConfigurationPoller));
}
private static async Task SetFileConfig(IFileConfigurationSetter fileConfigSetter, IOptions<FileConfiguration> fileConfig)
{
var response = await fileConfigSetter.Set(fileConfig.Value);
if (IsError(response))
{
ThrowToStopOcelotStarting(response);
}
}
private static bool ConfigNotStoredInConsul(Responses.Response<FileConfiguration> fileConfigFromConsul)
{
return fileConfigFromConsul.Data == null;
}
private static bool IsError(Response response)
{
return response == null || response.IsError;
}
private static IInternalConfiguration GetOcelotConfigAndReturn(IInternalConfigurationRepository provider)
{
var ocelotConfiguration = provider.Get();
if (ocelotConfiguration?.Data == null || ocelotConfiguration.IsError)
{
ThrowToStopOcelotStarting(ocelotConfiguration);
}
return ocelotConfiguration.Data;
}
private static void ThrowToStopOcelotStarting(Response config)
{
throw new Exception($"Unable to start Ocelot, errors are: {string.Join(",", config.Errors.Select(x => x.ToString()))}");
}
private static bool UsingConsul(IFileConfigurationRepository fileConfigRepo)
{
return fileConfigRepo.GetType() == typeof(ConsulFileConfigurationRepository);
}
private static void CreateAdministrationArea(IApplicationBuilder builder, IInternalConfiguration configuration)
{
if (!string.IsNullOrEmpty(configuration.AdministrationPath))
{
builder.Map(configuration.AdministrationPath, app =>
{
//todo - hack so we know that we are using internal identity server
var identityServerConfiguration = (IIdentityServerConfiguration)builder.ApplicationServices.GetService(typeof(IIdentityServerConfiguration));
if (identityServerConfiguration != null)
{
app.UseIdentityServer();
}
app.UseAuthentication();
app.UseMvc();
});
}
}
private static void ConfigureDiagnosticListener(IApplicationBuilder builder)
{
var env = (IHostingEnvironment)builder.ApplicationServices.GetService(typeof(IHostingEnvironment));
var listener = (OcelotDiagnosticListener)builder.ApplicationServices.GetService(typeof(OcelotDiagnosticListener));
var diagnosticListener = (DiagnosticListener)builder.ApplicationServices.GetService(typeof(DiagnosticListener));
diagnosticListener.SubscribeWithAdapter(listener);
}
private static void OnShutdown(IApplicationBuilder app)
{
var node = (INode)app.ApplicationServices.GetService(typeof(INode));
node.Stop();
}
}
}
//admin api it works...boy this is getting a spit spags boll.
var fileConfigSetter = (IFileConfigurationSetter)builder.ApplicationServices.GetService(typeof(IFileConfigurationSetter));
await SetFileConfig(fileConfigSetter, fileConfig);
}
return GetOcelotConfigAndReturn(internalConfigRepo);
}
private static bool AdministrationApiInUse(IAdministrationPath adminPath)
{
return adminPath.GetType() != typeof(NullAdministrationPath);
}
private static async Task SetFileConfigInConsul(IApplicationBuilder builder,
IFileConfigurationRepository fileConfigRepo, IOptions<FileConfiguration> fileConfig,
IInternalConfigurationCreator internalConfigCreator, IInternalConfigurationRepository internalConfigRepo)
{
// get the config from consul.
var fileConfigFromConsul = await fileConfigRepo.Get();
if (IsError(fileConfigFromConsul))
{
ThrowToStopOcelotStarting(fileConfigFromConsul);
}
else if (ConfigNotStoredInConsul(fileConfigFromConsul))
{
//there was no config in consul set the file in config in consul
await fileConfigRepo.Set(fileConfig.Value);
}
else
{
// create the internal config from consul data
var internalConfig = await internalConfigCreator.Create(fileConfigFromConsul.Data);
if (IsError(internalConfig))
{
ThrowToStopOcelotStarting(internalConfig);
}
else
{
// add the internal config to the internal repo
var response = internalConfigRepo.AddOrReplace(internalConfig.Data);
if (IsError(response))
{
ThrowToStopOcelotStarting(response);
}
}
if (IsError(internalConfig))
{
ThrowToStopOcelotStarting(internalConfig);
}
}
}
private static async Task SetFileConfig(IFileConfigurationSetter fileConfigSetter, IOptions<FileConfiguration> fileConfig)
{
var response = await fileConfigSetter.Set(fileConfig.Value);
if (IsError(response))
{
ThrowToStopOcelotStarting(response);
}
}
private static bool ConfigNotStoredInConsul(Responses.Response<FileConfiguration> fileConfigFromConsul)
{
return fileConfigFromConsul.Data == null;
}
private static bool IsError(Response response)
{
return response == null || response.IsError;
}
private static IInternalConfiguration GetOcelotConfigAndReturn(IInternalConfigurationRepository provider)
{
var ocelotConfiguration = provider.Get();
if (ocelotConfiguration?.Data == null || ocelotConfiguration.IsError)
{
ThrowToStopOcelotStarting(ocelotConfiguration);
}
return ocelotConfiguration.Data;
}
private static void ThrowToStopOcelotStarting(Response config)
{
throw new Exception($"Unable to start Ocelot, errors are: {string.Join(",", config.Errors.Select(x => x.ToString()))}");
}
private static bool UsingConsul(IFileConfigurationRepository fileConfigRepo)
{
return fileConfigRepo.GetType() == typeof(ConsulFileConfigurationRepository);
}
private static void CreateAdministrationArea(IApplicationBuilder builder, IInternalConfiguration configuration)
{
if (!string.IsNullOrEmpty(configuration.AdministrationPath))
{
builder.Map(configuration.AdministrationPath, app =>
{
//todo - hack so we know that we are using internal identity server
var identityServerConfiguration = (IIdentityServerConfiguration)builder.ApplicationServices.GetService(typeof(IIdentityServerConfiguration));
if (identityServerConfiguration != null)
{
app.UseIdentityServer();
}
app.UseAuthentication();
app.UseMvc();
});
}
}
private static void ConfigureDiagnosticListener(IApplicationBuilder builder)
{
var env = (IHostingEnvironment)builder.ApplicationServices.GetService(typeof(IHostingEnvironment));
var listener = (OcelotDiagnosticListener)builder.ApplicationServices.GetService(typeof(OcelotDiagnosticListener));
var diagnosticListener = (DiagnosticListener)builder.ApplicationServices.GetService(typeof(DiagnosticListener));
diagnosticListener.SubscribeWithAdapter(listener);
}
private static void OnShutdown(IApplicationBuilder app)
{
var node = (INode)app.ApplicationServices.GetService(typeof(INode));
node.Stop();
}
}
}

View File

@ -1,390 +1,391 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Text;
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
{
public class ConfigurationInConsulTests : IDisposable
{
private IWebHost _builder;
private readonly Steps _steps;
private IWebHost _fakeConsulBuilder;
private FileConfiguration _config;
public ConfigurationInConsulTests()
{
_steps = new Steps();
}
[Fact]
public void should_return_response_200_with_simple_url()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51779,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "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_return_response_200_with_simple_url_when_using_jsonserialized_cache()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51779,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
},
GlobalConfiguration = new FileGlobalConfiguration()
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Host = "localhost",
Port = 9502
}
}
};
var fakeConsulServiceDiscoveryUrl = "http://localhost:9502";
this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl))
.And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51779", "", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfigAndJsonSerializedCache())
.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<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/status",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51779,
}
},
UpstreamPathTemplate = "/cs/status",
UpstreamHttpMethod = new List<string> {"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<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/status",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51780,
}
},
UpstreamPathTemplate = "/cs/status",
UpstreamHttpMethod = new List<string> {"Get"}
}
},
GlobalConfiguration = new FileGlobalConfiguration()
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Host = "localhost",
Port = consulPort
}
}
};
var secondConsulConfig = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/status",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51780,
}
},
UpstreamPathTemplate = "/cs/status/awesome",
UpstreamHttpMethod = new List<string> {"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();
}
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 GivenThereIsAFakeConsulServiceDiscoveryProvider(string url)
{
_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<FileConfiguration>(json);
var response = JsonConvert.SerializeObject(true);
await context.Response.WriteAsync(response);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
});
})
.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();
}
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Text;
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
{
public class ConfigurationInConsulTests : IDisposable
{
private IWebHost _builder;
private readonly Steps _steps;
private IWebHost _fakeConsulBuilder;
private FileConfiguration _config;
public ConfigurationInConsulTests()
{
_steps = new Steps();
}
[Fact]
public void should_return_response_200_with_simple_url()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51779,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "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_return_response_200_with_simple_url_when_using_jsonserialized_cache()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51779,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
},
GlobalConfiguration = new FileGlobalConfiguration()
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Host = "localhost",
Port = 9502
}
}
};
var fakeConsulServiceDiscoveryUrl = "http://localhost:9502";
this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl))
.And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51779", "", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfigAndJsonSerializedCache())
.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<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/status",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51779,
}
},
UpstreamPathTemplate = "/cs/status",
UpstreamHttpMethod = new List<string> {"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<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/status",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51780,
}
},
UpstreamPathTemplate = "/cs/status",
UpstreamHttpMethod = new List<string> {"Get"}
}
},
GlobalConfiguration = new FileGlobalConfiguration()
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Host = "localhost",
Port = consulPort
}
}
};
var secondConsulConfig = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/status",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51780,
}
},
UpstreamPathTemplate = "/cs/status/awesome",
UpstreamHttpMethod = new List<string> {"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();
}
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 GivenThereIsAFakeConsulServiceDiscoveryProvider(string url)
{
_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<FileConfiguration>(json);
var response = JsonConvert.SerializeObject(true);
await context.Response.WriteAsync(response);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
});
})
.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();
}
}
}

View File

@ -12,37 +12,39 @@ using TestStack.BDDfy;
using Xunit;
using Shouldly;
using static Ocelot.Infrastructure.Wait;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration;
namespace Ocelot.UnitTests.Configuration
{
public class ConsulFileConfigurationPollerTests : IDisposable
public class FileConfigurationPollerTests : IDisposable
{
private readonly ConsulFileConfigurationPoller _poller;
private readonly FileConfigurationPoller _poller;
private Mock<IOcelotLoggerFactory> _factory;
private readonly Mock<IFileConfigurationRepository> _repo;
private readonly Mock<IFileConfigurationSetter> _setter;
private readonly FileConfiguration _fileConfig;
private Mock<IConsulPollerConfiguration> _config;
private Mock<IFileConfigurationPollerOptions> _config;
private readonly Mock<IInternalConfigurationRepository> _internalConfigRepo;
private readonly Mock<IInternalConfigurationCreator> _internalConfigCreator;
private IInternalConfiguration _internalConfig;
public ConsulFileConfigurationPollerTests()
public FileConfigurationPollerTests()
{
var logger = new Mock<IOcelotLogger>();
_factory = new Mock<IOcelotLoggerFactory>();
_factory.Setup(x => x.CreateLogger<ConsulFileConfigurationPoller>()).Returns(logger.Object);
_factory.Setup(x => x.CreateLogger<FileConfigurationPoller>()).Returns(logger.Object);
_repo = new Mock<IFileConfigurationRepository>();
_setter = new Mock<IFileConfigurationSetter>();
_fileConfig = new FileConfiguration();
_config = new Mock<IConsulPollerConfiguration>();
_config = new Mock<IFileConfigurationPollerOptions>();
_repo.Setup(x => x.Get()).ReturnsAsync(new OkResponse<FileConfiguration>(_fileConfig));
_config.Setup(x => x.Delay).Returns(100);
_poller = new ConsulFileConfigurationPoller(_factory.Object, _repo.Object, _setter.Object, _config.Object);
_internalConfigRepo = new Mock<IInternalConfigurationRepository>();
_internalConfigCreator = new Mock<IInternalConfigurationCreator>();
_internalConfigCreator.Setup(x => x.Create(It.IsAny<FileConfiguration>())).ReturnsAsync(new OkResponse<IInternalConfiguration>(_internalConfig));
_poller = new FileConfigurationPoller(_factory.Object, _repo.Object, _config.Object, _internalConfigRepo.Object, _internalConfigCreator.Object);
_poller.StartAsync(new CancellationToken());
}
public void Dispose()
{
_poller.Dispose();
}
[Fact]
public void should_start()
{
@ -141,10 +143,11 @@ namespace Ocelot.UnitTests.Configuration
private void ThenTheSetterIsCalled(FileConfiguration fileConfig, int times)
{
var result = WaitFor(2000).Until(() => {
var result = WaitFor(4000).Until(() => {
try
{
_setter.Verify(x => x.Set(fileConfig), Times.Exactly(times));
_internalConfigRepo.Verify(x => x.AddOrReplace(_internalConfig), Times.Exactly(times));
_internalConfigCreator.Verify(x => x.Create(fileConfig), Times.Exactly(times));
return true;
}
catch(Exception)
@ -157,10 +160,11 @@ namespace Ocelot.UnitTests.Configuration
private void ThenTheSetterIsCalledAtLeast(FileConfiguration fileConfig, int times)
{
var result = WaitFor(2000).Until(() => {
var result = WaitFor(4000).Until(() => {
try
{
_setter.Verify(x => x.Set(fileConfig), Times.AtLeast(times));
_internalConfigRepo.Verify(x => x.AddOrReplace(_internalConfig), Times.AtLeast(times));
_internalConfigCreator.Verify(x => x.Create(fileConfig), Times.AtLeast(times));
return true;
}
catch(Exception)
@ -170,5 +174,10 @@ namespace Ocelot.UnitTests.Configuration
});
result.ShouldBeTrue();
}
public void Dispose()
{
_poller.Dispose();
}
}
}