From 77211e9f16e178a2bc8d2cba25ca4dde52894fa5 Mon Sep 17 00:00:00 2001 From: Tom Pallister Date: Tue, 24 Apr 2018 08:30:17 +0100 Subject: [PATCH] Feature/store configuraton json idented (#328) * messing around with benchmark.net.seems Ocelot adds about 2ms to a request..lets make this less? :) * #326 store json indented so it looks nice :P --- docs/features/configuration.rst | 2 +- docs/features/servicediscovery.rst | 8 +- .../ConsulFileConfigurationRepository.cs | 4 +- .../DiskFileConfigurationRepository.cs | 2 +- .../Consul/ConsulClientFactory.cs | 2 +- .../Consul/IConsulClientFactory.cs | 2 +- .../ConsulServiceDiscoveryProvider.cs | 2 +- test/Ocelot.AcceptanceTests/Steps.cs | 4 +- .../AllTheThingsBenchmarks.cs | 157 ++++++++++++++++++ .../ExceptionHandlerMiddlewareBenchmarks.cs | 69 ++++++++ test/Ocelot.Benchmarks/Program.cs | 4 +- ...lPathToUrlPathTemplateMatcherBenchmarks.cs | 26 ++- .../ConsulFileConfigurationRepositoryTests.cs | 137 +++++++++++++++ ...> DiskFileConfigurationRepositoryTests.cs} | 79 +++++---- 14 files changed, 445 insertions(+), 53 deletions(-) create mode 100644 test/Ocelot.Benchmarks/AllTheThingsBenchmarks.cs create mode 100644 test/Ocelot.Benchmarks/ExceptionHandlerMiddlewareBenchmarks.cs create mode 100644 test/Ocelot.UnitTests/Configuration/ConsulFileConfigurationRepositoryTests.cs rename test/Ocelot.UnitTests/Configuration/{FileConfigurationRepositoryTests.cs => DiskFileConfigurationRepositoryTests.cs} (73%) diff --git a/docs/features/configuration.rst b/docs/features/configuration.rst index 343d7cbe..4e11e7ed 100644 --- a/docs/features/configuration.rst +++ b/docs/features/configuration.rst @@ -163,7 +163,7 @@ requests. This would also mean that subsequent requests dont use the cookies fro UseCookieContainer to true unless you have a really really good reason. Just look at your response headers and forward the cookies back with your next request! SSL Errors ----------- +^^^^^^^^^^ Id you want to ignore SSL warnings / errors set the following in your ReRoute config. diff --git a/docs/features/servicediscovery.rst b/docs/features/servicediscovery.rst index 88b13057..6fe25c12 100644 --- a/docs/features/servicediscovery.rst +++ b/docs/features/servicediscovery.rst @@ -69,18 +69,20 @@ In order to get this working add the following to ocelot.json.. "Type": "Eureka" } -And following the guide `Here `_ you may also need to add some stuff to appsettings.json. For example the json below -tells the steeltoe / pivotal services where to look for the service discovery server and if the service should register with it. +And following the guide `Here `_ you may also need to add some stuff to appsettings.json. For example the json below tells the steeltoe / pivotal services where to look for the service discovery server and if the service should register with it. .. code-block:: json "eureka": { "client": { "serviceUrl": "http://localhost:8761/eureka/", - "shouldRegisterWithEureka": true + "shouldRegisterWithEureka": false, + "shouldFetchRegistry": true } } +I am told that if shouldRegisterWithEureka is false then shouldFetchRegistry will defaut to true so you don't need it explicitly but left it in there. + Ocelot will now register all the necessary services when it starts up and if you have the json above will register itself with Eureka. One of the services polls Eureka every 30 seconds (default) and gets the latest service state and persists this in memory. When Ocelot asks for a given service it is retrieved from memory so performance is not a big problem. Please note that this code diff --git a/src/Ocelot/Configuration/Repository/ConsulFileConfigurationRepository.cs b/src/Ocelot/Configuration/Repository/ConsulFileConfigurationRepository.cs index 21216168..165e035b 100644 --- a/src/Ocelot/Configuration/Repository/ConsulFileConfigurationRepository.cs +++ b/src/Ocelot/Configuration/Repository/ConsulFileConfigurationRepository.cs @@ -13,7 +13,7 @@ namespace Ocelot.Configuration.Repository public class ConsulFileConfigurationRepository : IFileConfigurationRepository { - private readonly ConsulClient _consul; + private readonly IConsulClient _consul; private const string OcelotConfiguration = "InternalConfiguration"; private readonly Cache.IOcelotCache _cache; private readonly IOcelotLogger _logger; @@ -72,7 +72,7 @@ namespace Ocelot.Configuration.Repository public async Task Set(FileConfiguration ocelotConfiguration) { - var json = JsonConvert.SerializeObject(ocelotConfiguration); + var json = JsonConvert.SerializeObject(ocelotConfiguration, Formatting.Indented); var bytes = Encoding.UTF8.GetBytes(json); diff --git a/src/Ocelot/Configuration/Repository/DiskFileConfigurationRepository.cs b/src/Ocelot/Configuration/Repository/DiskFileConfigurationRepository.cs index 5fb871f4..a870419c 100644 --- a/src/Ocelot/Configuration/Repository/DiskFileConfigurationRepository.cs +++ b/src/Ocelot/Configuration/Repository/DiskFileConfigurationRepository.cs @@ -36,7 +36,7 @@ namespace Ocelot.Configuration.Repository public Task Set(FileConfiguration fileConfiguration) { - string jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration); + string jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration, Formatting.Indented); lock(_lock) { diff --git a/src/Ocelot/Infrastructure/Consul/ConsulClientFactory.cs b/src/Ocelot/Infrastructure/Consul/ConsulClientFactory.cs index 0e7f2782..26799934 100644 --- a/src/Ocelot/Infrastructure/Consul/ConsulClientFactory.cs +++ b/src/Ocelot/Infrastructure/Consul/ConsulClientFactory.cs @@ -6,7 +6,7 @@ namespace Ocelot.Infrastructure.Consul { public class ConsulClientFactory : IConsulClientFactory { - public ConsulClient Get(ConsulRegistryConfiguration config) + public IConsulClient Get(ConsulRegistryConfiguration config) { return new ConsulClient(c => { diff --git a/src/Ocelot/Infrastructure/Consul/IConsulClientFactory.cs b/src/Ocelot/Infrastructure/Consul/IConsulClientFactory.cs index 27e413fc..43428686 100644 --- a/src/Ocelot/Infrastructure/Consul/IConsulClientFactory.cs +++ b/src/Ocelot/Infrastructure/Consul/IConsulClientFactory.cs @@ -5,6 +5,6 @@ namespace Ocelot.Infrastructure.Consul { public interface IConsulClientFactory { - ConsulClient Get(ConsulRegistryConfiguration config); + IConsulClient Get(ConsulRegistryConfiguration config); } } diff --git a/src/Ocelot/ServiceDiscovery/Providers/ConsulServiceDiscoveryProvider.cs b/src/Ocelot/ServiceDiscovery/Providers/ConsulServiceDiscoveryProvider.cs index 12c34cb2..4c1afcc7 100644 --- a/src/Ocelot/ServiceDiscovery/Providers/ConsulServiceDiscoveryProvider.cs +++ b/src/Ocelot/ServiceDiscovery/Providers/ConsulServiceDiscoveryProvider.cs @@ -15,7 +15,7 @@ namespace Ocelot.ServiceDiscovery.Providers { private readonly ConsulRegistryConfiguration _config; private readonly IOcelotLogger _logger; - private readonly ConsulClient _consul; + private readonly IConsulClient _consul; private const string VersionPrefix = "version-"; public ConsulServiceDiscoveryProvider(ConsulRegistryConfiguration config, IOcelotLoggerFactory factory, IConsulClientFactory clientFactory) diff --git a/test/Ocelot.AcceptanceTests/Steps.cs b/test/Ocelot.AcceptanceTests/Steps.cs index f5c186ca..aac5be0d 100644 --- a/test/Ocelot.AcceptanceTests/Steps.cs +++ b/test/Ocelot.AcceptanceTests/Steps.cs @@ -88,7 +88,7 @@ namespace Ocelot.AcceptanceTests { var configurationPath = TestConfiguration.ConfigurationPath; - var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration); + var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration, Formatting.Indented); if (File.Exists(configurationPath)) { @@ -100,7 +100,7 @@ namespace Ocelot.AcceptanceTests public void GivenThereIsAConfiguration(FileConfiguration fileConfiguration, string configurationPath) { - var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration); + var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration, Formatting.Indented); if (File.Exists(configurationPath)) { diff --git a/test/Ocelot.Benchmarks/AllTheThingsBenchmarks.cs b/test/Ocelot.Benchmarks/AllTheThingsBenchmarks.cs new file mode 100644 index 00000000..3e9e1a4a --- /dev/null +++ b/test/Ocelot.Benchmarks/AllTheThingsBenchmarks.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections.Generic; +using System.IO; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Columns; +using BenchmarkDotNet.Configs; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Ocelot.Configuration.File; +using Ocelot.DownstreamRouteFinder.UrlMatcher; +using Ocelot.Middleware; +using Ocelot.DependencyInjection; +using System.Net.Http; +using System.Threading.Tasks; +using BenchmarkDotNet.Attributes.Jobs; +using BenchmarkDotNet.Diagnosers; +using BenchmarkDotNet.Validators; + +namespace Ocelot.Benchmarks +{ + [Config(typeof(AllTheThingsBenchmarks))] + public class AllTheThingsBenchmarks : ManualConfig + { + private IWebHost _service; + private IWebHost _ocelot; + private HttpClient _httpClient; + + public AllTheThingsBenchmarks() + { + Add(StatisticColumn.AllStatistics); + Add(MemoryDiagnoser.Default); + Add(BaselineValidator.FailOnError); + } + + [GlobalSetup] + public void SetUp() + { + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = "/", + DownstreamHostAndPorts = new List + { + new FileHostAndPort + { + Host = "localhost", + Port = 51879, + } + }, + DownstreamScheme = "http", + UpstreamPathTemplate = "/", + UpstreamHttpMethod = new List { "Get" }, + } + } + }; + + GivenThereIsAServiceRunningOn("http://localhost:51879", "/", 201, string.Empty); + GivenThereIsAConfiguration(configuration); + GivenOcelotIsRunning("http://localhost:5000"); + + _httpClient = new HttpClient(); + } + + [Benchmark(Baseline = true)] + public async Task Baseline() + { + var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost:5000/"); + var response = await _httpClient.SendAsync(request); + response.EnsureSuccessStatusCode(); + } + + // * Summary * + // BenchmarkDotNet=v0.10.13, OS=macOS 10.12.6 (16G1212) [Darwin 16.7.0] + // Intel Core i5-4278U CPU 2.60GHz (Haswell), 1 CPU, 4 logical cores and 2 physical cores + // .NET Core SDK=2.1.4 + // [Host] : .NET Core 2.0.6 (CoreCLR 4.6.0.0, CoreFX 4.6.26212.01), 64bit RyuJIT + // DefaultJob : .NET Core 2.0.6 (CoreCLR 4.6.0.0, CoreFX 4.6.26212.01), 64bit RyuJIT + + // Method | Mean | Error | StdDev | StdErr | Min | Q1 | Median | Q3 | Max | Op/s | Scaled | Gen 0 | Gen 1 | Allocated | + // --------- |---------:|----------:|----------:|----------:|---------:|---------:|---------:|---------:|---------:|------:|-------:|--------:|-------:|----------:| + // Baseline | 2.102 ms | 0.0292 ms | 0.0273 ms | 0.0070 ms | 2.063 ms | 2.080 ms | 2.093 ms | 2.122 ms | 2.152 ms | 475.8 | 1.00 | 31.2500 | 3.9063 | 1.63 KB | + + private void GivenOcelotIsRunning(string url) + { + _ocelot = new WebHostBuilder() + .UseKestrel() + .UseUrls(url) + .UseContentRoot(Directory.GetCurrentDirectory()) + .ConfigureAppConfiguration((hostingContext, config) => + { + config + .SetBasePath(hostingContext.HostingEnvironment.ContentRootPath) + .AddJsonFile("appsettings.json", true, true) + .AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true) + .AddJsonFile("ocelot.json") + .AddEnvironmentVariables(); + }) + .ConfigureServices(s => { + s.AddOcelot(); + }) + .ConfigureLogging((hostingContext, logging) => + { + logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); + }) + .UseIISIntegration() + .Configure(app => + { + app.UseOcelot().Wait(); + }) + .Build(); + + _ocelot.Start(); + } + + public void GivenThereIsAConfiguration(FileConfiguration fileConfiguration) + { + var configurationPath = Path.Combine(AppContext.BaseDirectory, "ocelot.json");; + + var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration); + + if (File.Exists(configurationPath)) + { + File.Delete(configurationPath); + } + + File.WriteAllText(configurationPath, jsonConfiguration); + } + + private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody) + { + _service = new WebHostBuilder() + .UseUrls(baseUrl) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .Configure(app => + { + app.UsePathBase(basePath); + app.Run(async context => + { + context.Response.StatusCode = statusCode; + await context.Response.WriteAsync(responseBody); + }); + }) + .Build(); + + _service.Start(); + } + } +} diff --git a/test/Ocelot.Benchmarks/ExceptionHandlerMiddlewareBenchmarks.cs b/test/Ocelot.Benchmarks/ExceptionHandlerMiddlewareBenchmarks.cs new file mode 100644 index 00000000..9b1f3312 --- /dev/null +++ b/test/Ocelot.Benchmarks/ExceptionHandlerMiddlewareBenchmarks.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.IO; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Columns; +using BenchmarkDotNet.Configs; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Ocelot.Configuration.File; +using Ocelot.DownstreamRouteFinder.UrlMatcher; +using Ocelot.Middleware; +using Ocelot.DependencyInjection; +using System.Net.Http; +using System.Threading.Tasks; +using BenchmarkDotNet.Attributes.Jobs; +using Ocelot.Configuration.Repository; +using Ocelot.Infrastructure.RequestData; +using Ocelot.Logging; +using Ocelot.Errors.Middleware; +using Microsoft.Extensions.DependencyInjection; +using BenchmarkDotNet.Diagnosers; +using BenchmarkDotNet.Validators; + +namespace Ocelot.Benchmarks +{ + [SimpleJob(launchCount: 1, warmupCount: 2, targetCount: 5)] + [Config(typeof(ExceptionHandlerMiddlewareBenchmarks))] + public class ExceptionHandlerMiddlewareBenchmarks : ManualConfig + { + private ExceptionHandlerMiddleware _middleware; + private DownstreamContext _downstreamContext; + private OcelotRequestDelegate _next; + + public ExceptionHandlerMiddlewareBenchmarks() + { + Add(StatisticColumn.AllStatistics); + Add(MemoryDiagnoser.Default); + Add(BaselineValidator.FailOnError); + } + + [GlobalSetup] + public void SetUp() + { + var serviceCollection = new ServiceCollection(); + var config = new ConfigurationRoot(new List()); + var builder = new OcelotBuilder(serviceCollection, config); + var services = serviceCollection.BuildServiceProvider(); + var loggerFactory = services.GetService(); + var configRepo = services.GetService(); + var repo = services.GetService(); + _next = async context => { + await Task.CompletedTask; + throw new Exception("BOOM"); + }; + _middleware = new ExceptionHandlerMiddleware(_next, loggerFactory, configRepo, repo); + _downstreamContext = new DownstreamContext(new DefaultHttpContext()); + } + + [Benchmark(Baseline = true)] + public async Task Baseline() + { + await _middleware.Invoke(_downstreamContext); + } + } +} diff --git a/test/Ocelot.Benchmarks/Program.cs b/test/Ocelot.Benchmarks/Program.cs index 56b87404..8601eeaa 100644 --- a/test/Ocelot.Benchmarks/Program.cs +++ b/test/Ocelot.Benchmarks/Program.cs @@ -7,7 +7,9 @@ namespace Ocelot.Benchmarks public static void Main(string[] args) { var switcher = new BenchmarkSwitcher(new[] { - typeof(UrlPathToUrlPathTemplateMatcherBenchmarks), + typeof(UrlPathToUrlPathTemplateMatcherBenchmarks), + typeof(AllTheThingsBenchmarks), + typeof(ExceptionHandlerMiddlewareBenchmarks) }); switcher.Run(args); diff --git a/test/Ocelot.Benchmarks/UrlPathToUrlPathTemplateMatcherBenchmarks.cs b/test/Ocelot.Benchmarks/UrlPathToUrlPathTemplateMatcherBenchmarks.cs index d7f4434b..3f02f48b 100644 --- a/test/Ocelot.Benchmarks/UrlPathToUrlPathTemplateMatcherBenchmarks.cs +++ b/test/Ocelot.Benchmarks/UrlPathToUrlPathTemplateMatcherBenchmarks.cs @@ -1,6 +1,9 @@ +using System; using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Columns; using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Diagnosers; +using BenchmarkDotNet.Validators; using Ocelot.DownstreamRouteFinder.UrlMatcher; namespace Ocelot.Benchmarks @@ -15,6 +18,8 @@ namespace Ocelot.Benchmarks public UrlPathToUrlPathTemplateMatcherBenchmarks() { Add(StatisticColumn.AllStatistics); + Add(MemoryDiagnoser.Default); + Add(BaselineValidator.FailOnError); } [GlobalSetup] @@ -25,16 +30,23 @@ namespace Ocelot.Benchmarks _downstreamUrlPathTemplate = "api/product/products/{productId}/variants/"; } - [Benchmark] - public void Benchmark1() + [Benchmark(Baseline = true)] + public void Baseline() { _urlPathMatcher.Match(_downstreamUrlPath, _downstreamUrlPathTemplate); } - [Benchmark] - public void Benchmark2() - { - _urlPathMatcher.Match(_downstreamUrlPath, _downstreamUrlPathTemplate); - } + // * Summary * + + // BenchmarkDotNet=v0.10.13, OS=macOS 10.12.6 (16G1212) [Darwin 16.7.0] + // Intel Core i5-4278U CPU 2.60GHz (Haswell), 1 CPU, 4 logical cores and 2 physical cores + // .NET Core SDK=2.1.4 + // [Host] : .NET Core 2.0.6 (CoreCLR 4.6.0.0, CoreFX 4.6.26212.01), 64bit RyuJIT + // DefaultJob : .NET Core 2.0.6 (CoreCLR 4.6.0.0, CoreFX 4.6.26212.01), 64bit RyuJIT + + + // Method | Mean | Error | StdDev | StdErr | Min | Q1 | Median | Q3 | Max | Op/s | + // ----------- |---------:|----------:|----------:|----------:|---------:|---------:|---------:|---------:|---------:|----------:| + // Benchmark1 | 3.133 us | 0.0492 us | 0.0460 us | 0.0119 us | 3.082 us | 3.100 us | 3.122 us | 3.168 us | 3.233 us | 319,161.9 | } } diff --git a/test/Ocelot.UnitTests/Configuration/ConsulFileConfigurationRepositoryTests.cs b/test/Ocelot.UnitTests/Configuration/ConsulFileConfigurationRepositoryTests.cs new file mode 100644 index 00000000..b6b1cc6d --- /dev/null +++ b/test/Ocelot.UnitTests/Configuration/ConsulFileConfigurationRepositoryTests.cs @@ -0,0 +1,137 @@ +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 _result; + + 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(), ""))); + + _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(); + } + + private void GivenWritingToConsulSucceeds() + { + var response = new WriteResult(); + response.Response = true; + + _kvEndpoint + .Setup(x => x.Put(It.IsAny(), It.IsAny())).ReturnsAsync(response); + } + + 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() + { + _result = 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 + }; + } + } +} \ No newline at end of file diff --git a/test/Ocelot.UnitTests/Configuration/FileConfigurationRepositoryTests.cs b/test/Ocelot.UnitTests/Configuration/DiskFileConfigurationRepositoryTests.cs similarity index 73% rename from test/Ocelot.UnitTests/Configuration/FileConfigurationRepositoryTests.cs rename to test/Ocelot.UnitTests/Configuration/DiskFileConfigurationRepositoryTests.cs index 5b0e93db..c2e77b38 100644 --- a/test/Ocelot.UnitTests/Configuration/FileConfigurationRepositoryTests.cs +++ b/test/Ocelot.UnitTests/Configuration/DiskFileConfigurationRepositoryTests.cs @@ -1,21 +1,22 @@ -using System; -using System.Collections.Generic; -using Moq; -using Ocelot.Configuration.File; -using Shouldly; -using TestStack.BDDfy; -using Xunit; -using Newtonsoft.Json; -using System.IO; -using Microsoft.AspNetCore.Hosting; -using Ocelot.Configuration.Repository; - namespace Ocelot.UnitTests.Configuration { - public class FileConfigurationRepositoryTests + using System; + using System.Collections.Generic; + using Moq; + using Ocelot.Configuration.File; + using Shouldly; + using TestStack.BDDfy; + using Xunit; + using Newtonsoft.Json; + using System.IO; + using Microsoft.AspNetCore.Hosting; + using Ocelot.Configuration.Repository; + + public class DiskFileConfigurationRepositoryTests { private readonly Mock _hostingEnvironment = new Mock(); private IFileConfigurationRepository _repo; + private string _configurationPath; private FileConfiguration _result; private FileConfiguration _fileConfiguration; @@ -24,7 +25,7 @@ namespace Ocelot.UnitTests.Configuration // tests but whatever... private string _environmentName = "DEV.DEV"; - public FileConfigurationRepositoryTests() + public DiskFileConfigurationRepositoryTests() { _hostingEnvironment.Setup(he => he.EnvironmentName).Returns(_environmentName); _repo = new DiskFileConfigurationRepository(_hostingEnvironment.Object); @@ -35,9 +36,9 @@ namespace Ocelot.UnitTests.Configuration { var config = FakeFileConfigurationForGet(); - this.Given(x => x.GivenTheConfigurationIs(config)) - .When(x => x.WhenIGetTheReRoutes()) - .Then(x => x.ThenTheFollowingIsReturned(config)) + this.Given(_ => GivenTheConfigurationIs(config)) + .When(_ => WhenIGetTheReRoutes()) + .Then(_ => ThenTheFollowingIsReturned(config)) .BDDfy(); } @@ -46,10 +47,10 @@ namespace Ocelot.UnitTests.Configuration { var config = FakeFileConfigurationForGet(); - this.Given(x => x.GivenTheEnvironmentNameIsUnavailable()) - .And(x => x.GivenTheConfigurationIs(config)) - .When(x => x.WhenIGetTheReRoutes()) - .Then(x => x.ThenTheFollowingIsReturned(config)) + this.Given(_ => GivenTheEnvironmentNameIsUnavailable()) + .And(_ => GivenTheConfigurationIs(config)) + .When(_ => WhenIGetTheReRoutes()) + .Then(_ => ThenTheFollowingIsReturned(config)) .BDDfy(); } @@ -58,9 +59,10 @@ namespace Ocelot.UnitTests.Configuration { var config = FakeFileConfigurationForSet(); - this.Given(x => GivenIHaveAConfiguration(config)) - .When(x => WhenISetTheConfiguration()) - .Then(x => ThenTheConfigurationIsStoredAs(config)) + this.Given(_ => GivenIHaveAConfiguration(config)) + .When(_ => WhenISetTheConfiguration()) + .Then(_ => ThenTheConfigurationIsStoredAs(config)) + .And(_ => ThenTheConfigurationJsonIsIndented(config)) .BDDfy(); } @@ -68,10 +70,12 @@ namespace Ocelot.UnitTests.Configuration public void should_set_file_configuration_if_environment_name_is_unavailable() { var config = FakeFileConfigurationForSet(); - this.Given(x => GivenIHaveAConfiguration(config)) - .And(x => GivenTheEnvironmentNameIsUnavailable()) - .When(x => WhenISetTheConfiguration()) - .Then(x => ThenTheConfigurationIsStoredAs(config)) + + this.Given(_ => GivenIHaveAConfiguration(config)) + .And(_ => GivenTheEnvironmentNameIsUnavailable()) + .When(_ => WhenISetTheConfiguration()) + .Then(_ => ThenTheConfigurationIsStoredAs(config)) + .And(_ => ThenTheConfigurationJsonIsIndented(config)) .BDDfy(); } @@ -117,16 +121,25 @@ namespace Ocelot.UnitTests.Configuration private void GivenTheConfigurationIs(FileConfiguration fileConfiguration) { - var configurationPath = $"{AppContext.BaseDirectory}/ocelot{(string.IsNullOrEmpty(_environmentName) ? string.Empty : ".")}{_environmentName}.json"; + _configurationPath = $"{AppContext.BaseDirectory}/ocelot{(string.IsNullOrEmpty(_environmentName) ? string.Empty : ".")}{_environmentName}.json"; - var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration); + var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration, Formatting.Indented); - if (File.Exists(configurationPath)) + if (File.Exists(_configurationPath)) { - File.Delete(configurationPath); + File.Delete(_configurationPath); } - File.WriteAllText(configurationPath, jsonConfiguration); + File.WriteAllText(_configurationPath, jsonConfiguration); + } + + private void ThenTheConfigurationJsonIsIndented(FileConfiguration expecteds) + { + var path = !string.IsNullOrEmpty(_configurationPath) ? _configurationPath : _configurationPath = $"{AppContext.BaseDirectory}/ocelot{(string.IsNullOrEmpty(_environmentName) ? string.Empty : ".")}{_environmentName}.json"; + + var resultText = File.ReadAllText(_configurationPath); + var expectedText = JsonConvert.SerializeObject(expecteds, Formatting.Indented); + resultText.ShouldBe(expectedText); } private void WhenIGetTheReRoutes()