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
This commit is contained in:
Tom Pallister
2018-04-24 08:30:17 +01:00
committed by GitHub
parent 636d116491
commit 77211e9f16
14 changed files with 445 additions and 53 deletions

View File

@ -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))
{

View File

@ -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<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51879,
}
},
DownstreamScheme = "http",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "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();
}
}
}

View File

@ -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<IConfigurationProvider>());
var builder = new OcelotBuilder(serviceCollection, config);
var services = serviceCollection.BuildServiceProvider();
var loggerFactory = services.GetService<IOcelotLoggerFactory>();
var configRepo = services.GetService<IInternalConfigurationRepository>();
var repo = services.GetService<IRequestScopedDataRepository>();
_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);
}
}
}

View File

@ -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);

View File

@ -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 |
}
}

View File

@ -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<IOcelotCache<FileConfiguration>> _cache;
private Mock<IInternalConfigurationRepository> _internalRepo;
private Mock<IConsulClientFactory> _factory;
private Mock<IOcelotLoggerFactory> _loggerFactory;
private Mock<IConsulClient> _client;
private Mock<IKVEndpoint> _kvEndpoint;
private FileConfiguration _fileConfiguration;
private Response _result;
public ConsulFileConfigurationRepositoryTests()
{
_cache = new Mock<IOcelotCache<FileConfiguration>>();
_internalRepo = new Mock<IInternalConfigurationRepository>();
_loggerFactory = new Mock<IOcelotLoggerFactory>();
_factory = new Mock<IConsulClientFactory>();
_client = new Mock<IConsulClient>();
_kvEndpoint = new Mock<IKVEndpoint>();
_client
.Setup(x => x.KV)
.Returns(_kvEndpoint.Object);
_factory
.Setup(x => x.Get(It.IsAny<ConsulRegistryConfiguration>()))
.Returns(_client.Object);
_internalRepo
.Setup(x => x.Get())
.Returns(new OkResponse<IInternalConfiguration>(new InternalConfiguration(new List<ReRoute>(), "", 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<bool>();
response.Response = true;
_kvEndpoint
.Setup(x => x.Put(It.IsAny<KVPair>(), It.IsAny<CancellationToken>())).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<KVPair>(k => k.Value.SequenceEqual(bytes)), It.IsAny<CancellationToken>()), 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<FileReRoute>
{
new FileReRoute
{
DownstreamHostAndPorts = new List<FileHostAndPort>
{
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
};
}
}
}

View File

@ -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<IHostingEnvironment> _hostingEnvironment = new Mock<IHostingEnvironment>();
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()