all tests passing, now to do authentication config provider

This commit is contained in:
Tom Gardham-Pallister 2017-02-22 07:48:49 +00:00
parent bf90b12f2c
commit aa0d8fe59a
18 changed files with 399 additions and 82 deletions

1
configuration.json Executable file
View File

@ -0,0 +1 @@
{"ReRoutes":[{"DownstreamPathTemplate":"/","UpstreamPathTemplate":"/","UpstreamHttpMethod":"get","AuthenticationOptions":{"Provider":null,"ProviderRootUrl":null,"ScopeName":null,"RequireHttps":false,"AdditionalScopes":[],"ScopeSecret":null},"AddHeadersToRequest":{},"AddClaimsToRequest":{},"RouteClaimsRequirement":{},"AddQueriesToRequest":{},"RequestIdKey":null,"FileCacheOptions":{"TtlSeconds":0},"ReRouteIsCaseSensitive":false,"ServiceName":null,"DownstreamScheme":"https","DownstreamHost":"localhost","DownstreamPort":80,"QoSOptions":{"ExceptionsAllowedBeforeBreaking":0,"DurationOfBreak":0,"TimeoutValue":0},"LoadBalancer":null},{"DownstreamPathTemplate":"/","UpstreamPathTemplate":"/test","UpstreamHttpMethod":"get","AuthenticationOptions":{"Provider":null,"ProviderRootUrl":null,"ScopeName":null,"RequireHttps":false,"AdditionalScopes":[],"ScopeSecret":null},"AddHeadersToRequest":{},"AddClaimsToRequest":{},"RouteClaimsRequirement":{},"AddQueriesToRequest":{},"RequestIdKey":null,"FileCacheOptions":{"TtlSeconds":0},"ReRouteIsCaseSensitive":false,"ServiceName":null,"DownstreamScheme":"https","DownstreamHost":"localhost","DownstreamPort":80,"QoSOptions":{"ExceptionsAllowedBeforeBreaking":0,"DurationOfBreak":0,"TimeoutValue":0},"LoadBalancer":null}],"GlobalConfiguration":{"RequestIdKey":"RequestId","ServiceDiscoveryProvider":{"Provider":null,"Host":null,"Port":0},"AdministrationPath":"/administration"}}

View File

@ -1,4 +1,5 @@
namespace Ocelot.Configuration.File

namespace Ocelot.Configuration.File
{
public class FileGlobalConfiguration
{
@ -6,6 +7,7 @@
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider();
}
public string RequestIdKey { get; set; }
public FileServiceDiscoveryProvider ServiceDiscoveryProvider {get;set;}
public string AdministrationPath {get;set;}

View File

@ -2,6 +2,7 @@ namespace Ocelot.Configuration.File
{
public class FileServiceDiscoveryProvider
{
public string Provider {get;set;}
public string Host {get;set;}
public int Port { get; set; }

View File

@ -0,0 +1,25 @@
using System;
using System.IO;
using Newtonsoft.Json;
using Ocelot.Configuration.File;
using Ocelot.Configuration.Repository;
using Ocelot.Responses;
namespace Ocelot.Configuration.Provider
{
public class FileConfigurationProvider : IFileConfigurationProvider
{
private IFileConfigurationRepository _repo;
public FileConfigurationProvider(IFileConfigurationRepository repo)
{
_repo = repo;
}
public Response<FileConfiguration> Get()
{
var fileConfig = _repo.Get();
return new OkResponse<FileConfiguration>(fileConfig.Data);
}
}
}

View File

@ -1,7 +1,7 @@
using Ocelot.Configuration.File;
using Ocelot.Responses;
namespace Ocelot.Services
namespace Ocelot.Configuration.Provider
{
public interface IFileConfigurationProvider
{

View File

@ -0,0 +1,42 @@
using System;
using Newtonsoft.Json;
using Ocelot.Configuration.File;
using Ocelot.Responses;
namespace Ocelot.Configuration.Repository
{
public class FileConfigurationRepository : IFileConfigurationRepository
{
private static readonly object _lock = new object();
public Response<FileConfiguration> Get()
{
var configFilePath = $"{AppContext.BaseDirectory}/configuration.json";
string json = string.Empty;
lock(_lock)
{
json = System.IO.File.ReadAllText(configFilePath);
}
var fileConfiguration = JsonConvert.DeserializeObject<FileConfiguration>(json);
return new OkResponse<FileConfiguration>(fileConfiguration);
}
public Response Set(FileConfiguration fileConfiguration)
{
var configurationPath = $"{AppContext.BaseDirectory}/configuration.json";
var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration);
lock(_lock)
{
if (System.IO.File.Exists(configurationPath))
{
System.IO.File.Delete(configurationPath);
}
System.IO.File.WriteAllText(configurationPath, jsonConfiguration);
}
return new OkResponse();
}
}
}

View File

@ -0,0 +1,11 @@
using Ocelot.Configuration.File;
using Ocelot.Responses;
namespace Ocelot.Configuration.Repository
{
public interface IFileConfigurationRepository
{
Response<FileConfiguration> Get();
Response Set(FileConfiguration fileConfiguration);
}
}

View File

@ -10,15 +10,25 @@ namespace Ocelot.Configuration.Setter
{
private readonly IOcelotConfigurationRepository _configRepo;
private readonly IOcelotConfigurationCreator _configCreator;
private readonly IFileConfigurationRepository _repo;
public FileConfigurationSetter(IOcelotConfigurationRepository configRepo, IOcelotConfigurationCreator configCreator)
public FileConfigurationSetter(IOcelotConfigurationRepository configRepo,
IOcelotConfigurationCreator configCreator, IFileConfigurationRepository repo)
{
_configRepo = configRepo;
_configCreator = configCreator;
_repo = repo;
}
public async Task<Response> Set(FileConfiguration fileConfig)
{
var response = _repo.Set(fileConfig);
if(response.IsError)
{
return new ErrorResponse(response.Errors);
}
var config = await _configCreator.Create(fileConfig);
if(!config.IsError)

View File

@ -2,8 +2,8 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Ocelot.Configuration.File;
using Ocelot.Configuration.Provider;
using Ocelot.Configuration.Setter;
using Ocelot.Services;
namespace Ocelot.Controllers
{
@ -34,7 +34,7 @@ namespace Ocelot.Controllers
}
[HttpPost]
public async Task<IActionResult> Post(FileConfiguration fileConfiguration)
public async Task<IActionResult> Post([FromBody]FileConfiguration fileConfiguration)
{
var response = await _configSetter.Set(fileConfiguration);

View File

@ -34,7 +34,6 @@ using Ocelot.Requester;
using Ocelot.Requester.QoS;
using Ocelot.Responder;
using Ocelot.ServiceDiscovery;
using Ocelot.Services;
namespace Ocelot.DependencyInjection
{
@ -112,8 +111,9 @@ namespace Ocelot.DependencyInjection
.AddAuthorization()
.AddJsonFormatters();
services.AddLogging();
services.AddSingleton<IFileConfigurationRepository, FileConfigurationRepository>();
services.AddSingleton<IFileConfigurationSetter, FileConfigurationSetter>();
services.AddSingleton<IFileConfigurationProvider, Services.FileConfigurationProvider>();
services.AddSingleton<Configuration.Provider.IFileConfigurationProvider, Configuration.Provider.FileConfigurationProvider>();
services.AddSingleton<IQosProviderHouse, QosProviderHouse>();
services.AddSingleton<IQoSProviderFactory, QoSProviderFactory>();
services.AddSingleton<IServiceDiscoveryProviderFactory, ServiceDiscoveryProviderFactory>();

View File

@ -1,19 +0,0 @@
using System;
using System.IO;
using Newtonsoft.Json;
using Ocelot.Configuration.File;
using Ocelot.Responses;
namespace Ocelot.Services
{
public class FileConfigurationProvider : IFileConfigurationProvider
{
public Response<FileConfiguration> Get()
{
var configFilePath = $"{AppContext.BaseDirectory}/configuration.json";
var json = File.ReadAllText(configFilePath);
var fileConfiguration = JsonConvert.DeserializeObject<FileConfiguration>(json);
return new OkResponse<FileConfiguration>(fileConfiguration);
}
}
}

View File

@ -74,7 +74,14 @@ namespace Ocelot.IntegrationTests
{
GlobalConfiguration = new FileGlobalConfiguration
{
AdministrationPath = "/administration"
AdministrationPath = "/administration",
RequestIdKey = "RequestId",
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{
Host = "127.0.0.1",
Provider = "test"
}
},
ReRoutes = new List<FileReRoute>()
{
@ -109,6 +116,88 @@ namespace Ocelot.IntegrationTests
.BDDfy();
}
[Fact]
public void should_get_file_configuration_edit_and_post_updated_version()
{
var initialConfiguration = new FileConfiguration
{
GlobalConfiguration = new FileGlobalConfiguration
{
AdministrationPath = "/administration"
},
ReRoutes = new List<FileReRoute>()
{
new FileReRoute()
{
DownstreamHost = "localhost",
DownstreamPort = 80,
DownstreamScheme = "https",
DownstreamPathTemplate = "/",
UpstreamHttpMethod = "get",
UpstreamPathTemplate = "/"
},
new FileReRoute()
{
DownstreamHost = "localhost",
DownstreamPort = 80,
DownstreamScheme = "https",
DownstreamPathTemplate = "/",
UpstreamHttpMethod = "get",
UpstreamPathTemplate = "/test"
}
}
};
var updatedConfiguration = new FileConfiguration
{
GlobalConfiguration = new FileGlobalConfiguration
{
AdministrationPath = "/administration"
},
ReRoutes = new List<FileReRoute>()
{
new FileReRoute()
{
DownstreamHost = "127.0.0.1",
DownstreamPort = 80,
DownstreamScheme = "http",
DownstreamPathTemplate = "/geoffrey",
UpstreamHttpMethod = "get",
UpstreamPathTemplate = "/"
},
new FileReRoute()
{
DownstreamHost = "123.123.123",
DownstreamPort = 443,
DownstreamScheme = "https",
DownstreamPathTemplate = "/blooper/{productId}",
UpstreamHttpMethod = "post",
UpstreamPathTemplate = "/test"
}
}
};
this.Given(x => GivenThereIsAConfiguration(initialConfiguration))
.And(x => GivenOcelotIsRunning())
.And(x => GivenIHaveAnOcelotToken("/administration"))
.And(x => GivenIHaveAddedATokenToMyRequest())
.When(x => WhenIGetUrlOnTheApiGateway("/administration/configuration"))
.When(x => WhenIPostOnTheApiGateway("/administration/configuration", updatedConfiguration))
.Then(x => ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => ThenTheResponseShouldBe(updatedConfiguration))
.When(x => WhenIGetUrlOnTheApiGateway("/administration/configuration"))
.And(x => ThenTheResponseShouldBe(updatedConfiguration))
.BDDfy();
}
private void WhenIPostOnTheApiGateway(string url, FileConfiguration updatedConfiguration)
{
var json = JsonConvert.SerializeObject(updatedConfiguration);
var content = new StringContent(json);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
_response = _httpClient.PostAsync(url, content).Result;
}
private void ThenTheResponseShouldBe(FileConfiguration expected)
{
var response = JsonConvert.DeserializeObject<FileConfiguration>(_response.Content.ReadAsStringAsync().Result);
@ -180,6 +269,8 @@ namespace Ocelot.IntegrationTests
File.WriteAllText(configurationPath, jsonConfiguration);
var text = File.ReadAllText(configurationPath);
configurationPath = $"{AppContext.BaseDirectory}/configuration.json";
if (File.Exists(configurationPath))
@ -188,6 +279,8 @@ namespace Ocelot.IntegrationTests
}
File.WriteAllText(configurationPath, jsonConfiguration);
text = File.ReadAllText(configurationPath);
}
private void WhenIGetUrlOnTheApiGateway(string url)

0
test/Ocelot.IntegrationTests/configuration.json Normal file → Executable file
View File

View File

@ -1,77 +1,62 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.Provider;
using Ocelot.Configuration.Repository;
using Ocelot.Errors;
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 IOcelotConfigurationProvider _ocelotConfigurationProvider;
private readonly Mock<IOcelotConfigurationRepository> _configurationRepository;
private Response<IOcelotConfiguration> _result;
private readonly IFileConfigurationProvider _provider;
private Mock<IFileConfigurationRepository> _repo;
private FileConfiguration _result;
private FileConfiguration _fileConfiguration;
public FileConfigurationProviderTests()
{
_configurationRepository = new Mock<IOcelotConfigurationRepository>();
_ocelotConfigurationProvider = new OcelotConfigurationProvider(_configurationRepository.Object);
_repo = new Mock<IFileConfigurationRepository>();
_provider = new FileConfigurationProvider(_repo.Object);
}
[Fact]
public void should_get_config()
public void should_return_file_configuration()
{
this.Given(x => x.GivenTheRepoReturns(new OkResponse<IOcelotConfiguration>(new OcelotConfiguration(new List<ReRoute>(), string.Empty))))
.When(x => x.WhenIGetTheConfig())
.Then(x => x.TheFollowingIsReturned(new OkResponse<IOcelotConfiguration>(new OcelotConfiguration(new List<ReRoute>(), string.Empty))))
var config = new FileConfiguration();
this.Given(x => x.GivenTheConfigurationIs(config))
.When(x => x.WhenIGetTheReRoutes())
.Then(x => x.ThenTheRepoIsCalledCorrectly())
.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)
private void GivenTheConfigurationIs(FileConfiguration fileConfiguration)
{
_configurationRepository
_fileConfiguration = fileConfiguration;
_repo
.Setup(x => x.Get())
.Returns(config);
.Returns(new OkResponse<FileConfiguration>(fileConfiguration));
}
private void WhenIGetTheConfig()
private void WhenIGetTheReRoutes()
{
_result = _ocelotConfigurationProvider.Get();
_result = _provider.Get().Data;
}
private void TheFollowingIsReturned(Response<IOcelotConfiguration> expected)
private void ThenTheRepoIsCalledCorrectly()
{
_result.IsError.ShouldBe(expected.IsError);
}
class AnyError : Error
{
public AnyError()
: base("blamo", OcelotErrorCode.UnknownError)
{
}
_repo
.Verify(x => x.Get(), Times.Once);
}
}
}

View File

@ -7,20 +7,21 @@ using Ocelot.Responses;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
using Ocelot.Services;
using Newtonsoft.Json;
using System.IO;
using Ocelot.Configuration.Repository;
namespace Ocelot.UnitTests.Services
namespace Ocelot.UnitTests.Configuration
{
public class GetFileConfigurationTests
public class FileConfigurationRepositoryTests
{
private readonly IFileConfigurationProvider _getReRoutes;
private readonly IFileConfigurationRepository _repo;
private FileConfiguration _result;
private FileConfiguration _fileConfiguration;
public GetFileConfigurationTests()
public FileConfigurationRepositoryTests()
{
_getReRoutes = new FileConfigurationProvider();
_repo = new FileConfigurationRepository();
}
[Fact]
@ -58,6 +59,69 @@ namespace Ocelot.UnitTests.Services
.BDDfy();
}
[Fact]
public void should_set_file_configuration()
{
var reRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamHost = "123.12.12.12",
DownstreamPort = 80,
DownstreamScheme = "https",
DownstreamPathTemplate = "/asdfs/test/{test}"
}
};
var globalConfiguration = new FileGlobalConfiguration
{
AdministrationPath = "asdas",
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{
Provider = "consul",
Port = 198,
Host = "blah"
}
};
var config = new FileConfiguration();
config.GlobalConfiguration = globalConfiguration;
config.ReRoutes.AddRange(reRoutes);
this.Given(x => GivenIHaveAConfiguration(config))
.When(x => WhenISetTheConfiguration())
.Then(x => ThenTheConfigurationIsStoredAs(config))
.BDDfy();
}
private void GivenIHaveAConfiguration(FileConfiguration fileConfiguration)
{
_fileConfiguration = fileConfiguration;
}
private void WhenISetTheConfiguration()
{
_repo.Set(_fileConfiguration);
_result = _repo.Get().Data;
}
private void ThenTheConfigurationIsStoredAs(FileConfiguration expected)
{
_result.GlobalConfiguration.AdministrationPath.ShouldBe(expected.GlobalConfiguration.AdministrationPath);
_result.GlobalConfiguration.RequestIdKey.ShouldBe(expected.GlobalConfiguration.RequestIdKey);
_result.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Host);
_result.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Port);
_result.GlobalConfiguration.ServiceDiscoveryProvider.Provider.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Provider);
for(var i = 0; i < _result.ReRoutes.Count; i++)
{
_result.ReRoutes[i].DownstreamHost.ShouldBe(expected.ReRoutes[i].DownstreamHost);
_result.ReRoutes[i].DownstreamPathTemplate.ShouldBe(expected.ReRoutes[i].DownstreamPathTemplate);
_result.ReRoutes[i].DownstreamPort.ShouldBe(expected.ReRoutes[i].DownstreamPort);
_result.ReRoutes[i].DownstreamScheme.ShouldBe(expected.ReRoutes[i].DownstreamScheme);
}
}
private void GivenTheConfigurationIs(FileConfiguration fileConfiguration)
{
var configurationPath = $"{AppContext.BaseDirectory}/configuration.json";
@ -74,7 +138,7 @@ namespace Ocelot.UnitTests.Services
private void WhenIGetTheReRoutes()
{
_result = _getReRoutes.Get().Data;
_result = _repo.Get().Data;
}
private void ThenTheFollowingIsReturned(FileConfiguration expected)

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using Moq;
using Ocelot.Configuration;
@ -21,12 +22,14 @@ namespace Ocelot.UnitTests.Configuration
private Mock<IOcelotConfigurationCreator> _configCreator;
private Response<IOcelotConfiguration> _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);
_configSetter = new FileConfigurationSetter(_configRepo.Object, _configCreator.Object, _repo.Object);
}
[Fact]
@ -36,24 +39,46 @@ namespace Ocelot.UnitTests.Configuration
var config = new OcelotConfiguration(new List<ReRoute>(), string.Empty);
this.Given(x => GivenTheFollowingConfiguration(fileConfig))
.And(x => GivenTheRepoReturns(new OkResponse()))
.And(x => GivenTheCreatorReturns(new OkResponse<IOcelotConfiguration>(config)))
.When(x => WhenISetTheConfiguration())
.Then(x => ThenTheConfigurationRepositoryIsCalledCorrectly())
.BDDfy();
}
[Fact]
public void should_return_error_if_unable_to_set_configuration()
public void should_return_error_if_unable_to_set_file_configuration()
{
var fileConfig = new FileConfiguration();
this.Given(x => GivenTheFollowingConfiguration(fileConfig))
.And(x => GivenTheRepoReturns(new ErrorResponse(It.IsAny<Error>())))
.When(x => WhenISetTheConfiguration())
.And(x => ThenAnErrorResponseIsReturned())
.BDDfy();
}
[Fact]
public void should_return_error_if_unable_to_set_ocelot_configuration()
{
var fileConfig = new FileConfiguration();
this.Given(x => GivenTheFollowingConfiguration(fileConfig))
.And(x => GivenTheRepoReturns(new OkResponse()))
.And(x => GivenTheCreatorReturns(new ErrorResponse<IOcelotConfiguration>(It.IsAny<Error>())))
.When(x => WhenISetTheConfiguration())
.And(x => ThenAnErrorResponseIsReturned())
.BDDfy();
}
private void GivenTheRepoReturns(Response response)
{
_repo
.Setup(x => x.Set(It.IsAny<FileConfiguration>()))
.Returns(response);
}
private void ThenAnErrorResponseIsReturned()
{
_result.ShouldBeOfType<ErrorResponse>();

View File

@ -0,0 +1,77 @@
using System.Collections.Generic;
using Moq;
using Ocelot.Configuration;
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()
{
this.Given(x => x.GivenTheRepoReturns(new OkResponse<IOcelotConfiguration>(new OcelotConfiguration(new List<ReRoute>(), string.Empty))))
.When(x => x.WhenIGetTheConfig())
.Then(x => x.TheFollowingIsReturned(new OkResponse<IOcelotConfiguration>(new OcelotConfiguration(new List<ReRoute>(), string.Empty))))
.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())
.Returns(config);
}
private void WhenIGetTheConfig()
{
_result = _ocelotConfigurationProvider.Get();
}
private void TheFollowingIsReturned(Response<IOcelotConfiguration> expected)
{
_result.IsError.ShouldBe(expected.IsError);
}
class AnyError : Error
{
public AnyError()
: base("blamo", OcelotErrorCode.UnknownError)
{
}
}
}
}

View File

@ -7,10 +7,10 @@ using Ocelot.Configuration.Setter;
using Ocelot.Controllers;
using Ocelot.Errors;
using Ocelot.Responses;
using Ocelot.Services;
using TestStack.BDDfy;
using Xunit;
using Shouldly;
using Ocelot.Configuration.Provider;
namespace Ocelot.UnitTests.Controllers
{