Feature/merge configuration files (#316)

* #296 renamed configuration.json to ocelot.json in preparation

* removed things we dont need for tests

* another file we dont need

* removed some async we dont need

* refactoring to consolidate configuration code

* removed another pointless abstraction

* #296 started writing merge code

* #296 coming up with ideas for this config merging

* #296 still hacking this idea around

* #296 will now do a crappy merge on the configuration

* #296 change so tests pass on windows
This commit is contained in:
Tom Pallister
2018-04-17 22:06:41 +01:00
committed by GitHub
parent 3607c0867e
commit aa55fe34cb
84 changed files with 883 additions and 1050 deletions

View File

@ -1,22 +1,18 @@
using System.Collections.Generic;
using Castle.Components.DictionaryAdapter;
using Microsoft.Extensions.Options;
using Moq;
using Ocelot.Cache;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Ocelot.Configuration.Validator;
using Ocelot.Logging;
using Ocelot.Responses;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration
namespace Ocelot.UnitTests.Configuration
{
using System;
using System.Collections.Generic;
using Moq;
using Ocelot.Cache;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Ocelot.Configuration.Validator;
using Ocelot.Logging;
using Ocelot.Responses;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
using Ocelot.DependencyInjection;
using Ocelot.Errors;
using Ocelot.UnitTests.TestData;
@ -24,23 +20,22 @@ namespace Ocelot.UnitTests.Configuration
public class FileConfigurationCreatorTests
{
private readonly Mock<IOptions<FileConfiguration>> _fileConfig;
private readonly Mock<IConfigurationValidator> _validator;
private Response<IOcelotConfiguration> _config;
private Response<IInternalConfiguration> _config;
private FileConfiguration _fileConfiguration;
private readonly Mock<IOcelotLoggerFactory> _logger;
private readonly FileOcelotConfigurationCreator _ocelotConfigurationCreator;
private Mock<IClaimsToThingCreator> _claimsToThingCreator;
private Mock<IAuthenticationOptionsCreator> _authOptionsCreator;
private Mock<IUpstreamTemplatePatternCreator> _upstreamTemplatePatternCreator;
private Mock<IRequestIdKeyCreator> _requestIdKeyCreator;
private Mock<IServiceProviderConfigurationCreator> _serviceProviderConfigCreator;
private Mock<IQoSOptionsCreator> _qosOptionsCreator;
private Mock<IReRouteOptionsCreator> _fileReRouteOptionsCreator;
private Mock<IRateLimitOptionsCreator> _rateLimitOptions;
private Mock<IRegionCreator> _regionCreator;
private Mock<IHttpHandlerOptionsCreator> _httpHandlerOptionsCreator;
private Mock<IAdministrationPath> _adminPath;
private readonly FileInternalConfigurationCreator _internalConfigurationCreator;
private readonly Mock<IClaimsToThingCreator> _claimsToThingCreator;
private readonly Mock<IAuthenticationOptionsCreator> _authOptionsCreator;
private readonly Mock<IUpstreamTemplatePatternCreator> _upstreamTemplatePatternCreator;
private readonly Mock<IRequestIdKeyCreator> _requestIdKeyCreator;
private readonly Mock<IServiceProviderConfigurationCreator> _serviceProviderConfigCreator;
private readonly Mock<IQoSOptionsCreator> _qosOptionsCreator;
private readonly Mock<IReRouteOptionsCreator> _fileReRouteOptionsCreator;
private readonly Mock<IRateLimitOptionsCreator> _rateLimitOptions;
private readonly Mock<IRegionCreator> _regionCreator;
private readonly Mock<IHttpHandlerOptionsCreator> _httpHandlerOptionsCreator;
private readonly Mock<IAdministrationPath> _adminPath;
private readonly Mock<IHeaderFindAndReplaceCreator> _headerFindAndReplaceCreator;
private readonly Mock<IDownstreamAddressesCreator> _downstreamAddressesCreator;
@ -48,7 +43,6 @@ namespace Ocelot.UnitTests.Configuration
{
_logger = new Mock<IOcelotLoggerFactory>();
_validator = new Mock<IConfigurationValidator>();
_fileConfig = new Mock<IOptions<FileConfiguration>>();
_claimsToThingCreator = new Mock<IClaimsToThingCreator>();
_authOptionsCreator = new Mock<IAuthenticationOptionsCreator>();
_upstreamTemplatePatternCreator = new Mock<IUpstreamTemplatePatternCreator>();
@ -63,8 +57,7 @@ namespace Ocelot.UnitTests.Configuration
_headerFindAndReplaceCreator = new Mock<IHeaderFindAndReplaceCreator>();
_downstreamAddressesCreator = new Mock<IDownstreamAddressesCreator>();
_ocelotConfigurationCreator = new FileOcelotConfigurationCreator(
_fileConfig.Object,
_internalConfigurationCreator = new FileInternalConfigurationCreator(
_validator.Object,
_logger.Object,
_claimsToThingCreator.Object,
@ -262,7 +255,7 @@ namespace Ocelot.UnitTests.Configuration
.And(x => x.GivenTheConfigIsValid())
.And(x => x.GivenTheFollowingRegionIsReturned("region"))
.When(x => x.WhenICreateTheConfig())
.Then(x => x.ThenTheRegionCreatorIsCalledCorrectly("region"))
.Then(x => x.ThenTheRegionCreatorIsCalledCorrectly())
.And(x => x.ThenTheHeaderFindAndReplaceCreatorIsCalledCorrectly())
.BDDfy();
}
@ -800,14 +793,11 @@ namespace Ocelot.UnitTests.Configuration
private void GivenTheConfigIs(FileConfiguration fileConfiguration)
{
_fileConfiguration = fileConfiguration;
_fileConfig
.Setup(x => x.Value)
.Returns(_fileConfiguration);
}
private void WhenICreateTheConfig()
{
_config = _ocelotConfigurationCreator.Create(_fileConfiguration).Result;
_config = _internalConfigurationCreator.Create(_fileConfiguration).Result;
}
private void ThenTheReRoutesAre(List<ReRoute> expectedReRoutes)
@ -928,7 +918,7 @@ namespace Ocelot.UnitTests.Configuration
.Returns(region);
}
private void ThenTheRegionCreatorIsCalledCorrectly(string expected)
private void ThenTheRegionCreatorIsCalledCorrectly()
{
_regionCreator
.Verify(x => x.Create(_fileConfiguration.ReRoutes[0]), Times.Once);

View File

@ -1,60 +0,0 @@
using System;
using System.Collections.Generic;
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.File;
using Ocelot.Responses;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
using Newtonsoft.Json;
using System.IO;
using Ocelot.Configuration.Provider;
using Ocelot.Configuration.Repository;
namespace Ocelot.UnitTests.Configuration
{
public class FileConfigurationProviderTests
{
private readonly IFileConfigurationProvider _provider;
private Mock<IFileConfigurationRepository> _repo;
private FileConfiguration _result;
private FileConfiguration _fileConfiguration;
public FileConfigurationProviderTests()
{
_repo = new Mock<IFileConfigurationRepository>();
_provider = new FileConfigurationProvider(_repo.Object);
}
[Fact]
public void should_return_file_configuration()
{
var config = new FileConfiguration();
this.Given(x => x.GivenTheConfigurationIs(config))
.When(x => x.WhenIGetTheReRoutes())
.Then(x => x.ThenTheRepoIsCalledCorrectly())
.BDDfy();
}
private void GivenTheConfigurationIs(FileConfiguration fileConfiguration)
{
_fileConfiguration = fileConfiguration;
_repo
.Setup(x => x.Get())
.ReturnsAsync(new OkResponse<FileConfiguration>(fileConfiguration));
}
private void WhenIGetTheReRoutes()
{
_result = _provider.Get().Result.Data;
}
private void ThenTheRepoIsCalledCorrectly()
{
_repo
.Verify(x => x.Get(), Times.Once);
}
}
}

View File

@ -18,12 +18,16 @@ namespace Ocelot.UnitTests.Configuration
private IFileConfigurationRepository _repo;
private FileConfiguration _result;
private FileConfiguration _fileConfiguration;
private string _environmentName = "DEV";
// This is a bit dirty and it is dev.dev so that the ConfigurationBuilderExtensionsTests
// cant pick it up if they run in parralel..sigh these are not really unit
// tests but whatever...
private string _environmentName = "DEV.DEV";
public FileConfigurationRepositoryTests()
{
_hostingEnvironment.Setup(he => he.EnvironmentName).Returns(_environmentName);
_repo = new FileConfigurationRepository(_hostingEnvironment.Object);
_repo = new DiskFileConfigurationRepository(_hostingEnvironment.Object);
}
[Fact]
@ -75,7 +79,7 @@ namespace Ocelot.UnitTests.Configuration
{
_environmentName = null;
_hostingEnvironment.Setup(he => he.EnvironmentName).Returns(_environmentName);
_repo = new FileConfigurationRepository(_hostingEnvironment.Object);
_repo = new DiskFileConfigurationRepository(_hostingEnvironment.Object);
}
private void GivenIHaveAConfiguration(FileConfiguration fileConfiguration)
@ -113,7 +117,7 @@ namespace Ocelot.UnitTests.Configuration
private void GivenTheConfigurationIs(FileConfiguration fileConfiguration)
{
var configurationPath = $"{AppContext.BaseDirectory}/configuration{(string.IsNullOrEmpty(_environmentName) ? string.Empty : ".")}{_environmentName}.json";
var configurationPath = $"{AppContext.BaseDirectory}/ocelot{(string.IsNullOrEmpty(_environmentName) ? string.Empty : ".")}{_environmentName}.json";
var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration);

View File

@ -18,19 +18,19 @@ namespace Ocelot.UnitTests.Configuration
public class FileConfigurationSetterTests
{
private FileConfiguration _fileConfiguration;
private FileConfigurationSetter _configSetter;
private Mock<IOcelotConfigurationRepository> _configRepo;
private Mock<IOcelotConfigurationCreator> _configCreator;
private Response<IOcelotConfiguration> _configuration;
private FileAndInternalConfigurationSetter _configSetter;
private Mock<IInternalConfigurationRepository> _configRepo;
private Mock<IInternalConfigurationCreator> _configCreator;
private Response<IInternalConfiguration> _configuration;
private object _result;
private Mock<IFileConfigurationRepository> _repo;
public FileConfigurationSetterTests()
{
_repo = new Mock<IFileConfigurationRepository>();
_configRepo = new Mock<IOcelotConfigurationRepository>();
_configCreator = new Mock<IOcelotConfigurationCreator>();
_configSetter = new FileConfigurationSetter(_configRepo.Object, _configCreator.Object, _repo.Object);
_configRepo = new Mock<IInternalConfigurationRepository>();
_configCreator = new Mock<IInternalConfigurationCreator>();
_configSetter = new FileAndInternalConfigurationSetter(_configRepo.Object, _configCreator.Object, _repo.Object);
}
[Fact]
@ -38,11 +38,11 @@ namespace Ocelot.UnitTests.Configuration
{
var fileConfig = new FileConfiguration();
var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
var config = new OcelotConfiguration(new List<ReRoute>(), string.Empty, serviceProviderConfig, "asdf");
var config = new InternalConfiguration(new List<ReRoute>(), string.Empty, serviceProviderConfig, "asdf");
this.Given(x => GivenTheFollowingConfiguration(fileConfig))
.And(x => GivenTheRepoReturns(new OkResponse()))
.And(x => GivenTheCreatorReturns(new OkResponse<IOcelotConfiguration>(config)))
.And(x => GivenTheCreatorReturns(new OkResponse<IInternalConfiguration>(config)))
.When(x => WhenISetTheConfiguration())
.Then(x => ThenTheConfigurationRepositoryIsCalledCorrectly())
.BDDfy();
@ -67,7 +67,7 @@ namespace Ocelot.UnitTests.Configuration
this.Given(x => GivenTheFollowingConfiguration(fileConfig))
.And(x => GivenTheRepoReturns(new OkResponse()))
.And(x => GivenTheCreatorReturns(new ErrorResponse<IOcelotConfiguration>(It.IsAny<Error>())))
.And(x => GivenTheCreatorReturns(new ErrorResponse<IInternalConfiguration>(It.IsAny<Error>())))
.When(x => WhenISetTheConfiguration())
.And(x => ThenAnErrorResponseIsReturned())
.BDDfy();
@ -85,7 +85,7 @@ namespace Ocelot.UnitTests.Configuration
_result.ShouldBeOfType<ErrorResponse>();
}
private void GivenTheCreatorReturns(Response<IOcelotConfiguration> configuration)
private void GivenTheCreatorReturns(Response<IInternalConfiguration> configuration)
{
_configuration = configuration;
_configCreator

View File

@ -1,76 +0,0 @@
using Ocelot.Configuration.Authentication;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration
{
public class HashMatcherTests
{
private string _password;
private string _hash;
private string _salt;
private bool _result;
private HashMatcher _hashMatcher;
public HashMatcherTests()
{
_hashMatcher = new HashMatcher();
}
[Fact]
public void should_match_hash()
{
var hash = "kE/mxd1hO9h9Sl2VhGhwJUd9xZEv4NP6qXoN39nIqM4=";
var salt = "zzWITpnDximUNKYLiUam/w==";
var password = "secret";
this.Given(x => GivenThePassword(password))
.And(x => GivenTheHash(hash))
.And(x => GivenTheSalt(salt))
.When(x => WhenIMatch())
.Then(x => ThenTheResultIs(true))
.BDDfy();
}
[Fact]
public void should_not_match_hash()
{
var hash = "kE/mxd1hO9h9Sl2VhGhwJUd9xZEv4NP6qXoN39nIqM4=";
var salt = "zzWITpnDximUNKYLiUam/w==";
var password = "secret1";
this.Given(x => GivenThePassword(password))
.And(x => GivenTheHash(hash))
.And(x => GivenTheSalt(salt))
.When(x => WhenIMatch())
.Then(x => ThenTheResultIs(false))
.BDDfy();
}
private void GivenThePassword(string password)
{
_password = password;
}
private void GivenTheHash(string hash)
{
_hash = hash;
}
private void GivenTheSalt(string salt)
{
_salt = salt;
}
private void WhenIMatch()
{
_result = _hashMatcher.Match(_password, _salt, _hash);
}
private void ThenTheResultIs(bool expected)
{
_result.ShouldBe(expected);
}
}
}

View File

@ -149,6 +149,7 @@ namespace Ocelot.UnitTests.Configuration
.Then(x => ThenTheFollowingDownstreamIsReturned(downstream))
.BDDfy();
}
[Fact]
public void should_add_trace_id_header()
{

View File

@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Repository;
@ -14,14 +12,14 @@ namespace Ocelot.UnitTests.Configuration
{
public class InMemoryConfigurationRepositoryTests
{
private readonly InMemoryOcelotConfigurationRepository _repo;
private IOcelotConfiguration _config;
private readonly InMemoryInternalConfigurationRepository _repo;
private IInternalConfiguration _config;
private Response _result;
private Response<IOcelotConfiguration> _getResult;
private Response<IInternalConfiguration> _getResult;
public InMemoryConfigurationRepositoryTests()
{
_repo = new InMemoryOcelotConfigurationRepository();
_repo = new InMemoryInternalConfigurationRepository();
}
[Fact]
@ -49,7 +47,7 @@ namespace Ocelot.UnitTests.Configuration
private void WhenIGetTheConfiguration()
{
_getResult = _repo.Get().Result;
_getResult = _repo.Get();
}
private void GivenThereIsASavedConfiguration()
@ -58,14 +56,14 @@ namespace Ocelot.UnitTests.Configuration
WhenIAddOrReplaceTheConfig();
}
private void GivenTheConfigurationIs(IOcelotConfiguration config)
private void GivenTheConfigurationIs(IInternalConfiguration config)
{
_config = config;
}
private void WhenIAddOrReplaceTheConfig()
{
_result = _repo.AddOrReplace(_config).Result;
_result = _repo.AddOrReplace(_config);
}
private void ThenNoErrorsAreReturned()
@ -73,7 +71,7 @@ namespace Ocelot.UnitTests.Configuration
_result.IsError.ShouldBeFalse();
}
class FakeConfig : IOcelotConfiguration
class FakeConfig : IInternalConfiguration
{
private readonly string _downstreamTemplatePath;

View File

@ -1,80 +0,0 @@
using System.Collections.Generic;
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.Provider;
using Ocelot.Configuration.Repository;
using Ocelot.Errors;
using Ocelot.Responses;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration
{
public class OcelotConfigurationProviderTests
{
private readonly IOcelotConfigurationProvider _ocelotConfigurationProvider;
private readonly Mock<IOcelotConfigurationRepository> _configurationRepository;
private Response<IOcelotConfiguration> _result;
public OcelotConfigurationProviderTests()
{
_configurationRepository = new Mock<IOcelotConfigurationRepository>();
_ocelotConfigurationProvider = new OcelotConfigurationProvider(_configurationRepository.Object);
}
[Fact]
public void should_get_config()
{
var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
this.Given(x => x.GivenTheRepoReturns(new OkResponse<IOcelotConfiguration>(new OcelotConfiguration(new List<ReRoute>(), string.Empty, serviceProviderConfig, ""))))
.When(x => x.WhenIGetTheConfig())
.Then(x => x.TheFollowingIsReturned(new OkResponse<IOcelotConfiguration>(new OcelotConfiguration(new List<ReRoute>(), string.Empty, serviceProviderConfig, ""))))
.BDDfy();
}
[Fact]
public void should_return_error()
{
this.Given(x => x.GivenTheRepoReturns(new ErrorResponse<IOcelotConfiguration>(new List<Error>
{
new AnyError()
})))
.When(x => x.WhenIGetTheConfig())
.Then(x => x.TheFollowingIsReturned(
new ErrorResponse<IOcelotConfiguration>(new List<Error>
{
new AnyError()
})))
.BDDfy();
}
private void GivenTheRepoReturns(Response<IOcelotConfiguration> config)
{
_configurationRepository
.Setup(x => x.Get())
.ReturnsAsync(config);
}
private void WhenIGetTheConfig()
{
_result = _ocelotConfigurationProvider.Get().Result;
}
private void TheFollowingIsReturned(Response<IOcelotConfiguration> expected)
{
_result.IsError.ShouldBe(expected.IsError);
}
class AnyError : Error
{
public AnyError()
: base("blamo", OcelotErrorCode.UnknownError)
{
}
}
}
}