mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-06-19 13:48:15 +08:00
Merge branch 'develop' into feature/config_grow_when_merged
# Conflicts: # src/Ocelot/DependencyInjection/ConfigurationBuilderExtensions.cs # test/Ocelot.UnitTests/DependencyInjection/ConfigurationBuilderExtensionsTests.cs
This commit is contained in:
@ -1,91 +1,94 @@
|
||||
using Ocelot.Configuration;
|
||||
using Ocelot.Middleware;
|
||||
|
||||
namespace Ocelot.UnitTests.Authentication
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Moq;
|
||||
using Ocelot.Authentication.Middleware;
|
||||
using Ocelot.Configuration.Builder;
|
||||
using Ocelot.Logging;
|
||||
using Shouldly;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
|
||||
public class AuthenticationMiddlewareTests
|
||||
{
|
||||
private AuthenticationMiddleware _middleware;
|
||||
private Mock<IOcelotLoggerFactory> _factory;
|
||||
private Mock<IOcelotLogger> _logger;
|
||||
private OcelotRequestDelegate _next;
|
||||
private DownstreamContext _downstreamContext;
|
||||
|
||||
public AuthenticationMiddlewareTests()
|
||||
{
|
||||
_factory = new Mock<IOcelotLoggerFactory>();
|
||||
_logger = new Mock<IOcelotLogger>();
|
||||
_factory.Setup(x => x.CreateLogger<AuthenticationMiddleware>()).Returns(_logger.Object);
|
||||
_downstreamContext = new DownstreamContext(new DefaultHttpContext());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_call_next_middleware_if_route_is_not_authenticated()
|
||||
{
|
||||
this.Given(x => GivenTheDownStreamRouteIs(
|
||||
new DownstreamReRouteBuilder().WithUpstreamHttpMethod(new List<string> { "Get" }).Build()))
|
||||
.And(x => GivenTheTestServerPipelineIsConfigured())
|
||||
.When(x => WhenICallTheMiddleware())
|
||||
.Then(x => ThenTheUserIsAuthenticated())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void WhenICallTheMiddleware()
|
||||
{
|
||||
_next = (context) => {
|
||||
byte[] byteArray = Encoding.ASCII.GetBytes("The user is authenticated");
|
||||
var stream = new MemoryStream(byteArray);
|
||||
context.HttpContext.Response.Body = stream;
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
_middleware = new AuthenticationMiddleware(_next, _factory.Object);
|
||||
_middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
private void GivenTheTestServerPipelineIsConfigured()
|
||||
{
|
||||
_next = (context) => {
|
||||
byte[] byteArray = Encoding.ASCII.GetBytes("The user is authenticated");
|
||||
var stream = new MemoryStream(byteArray);
|
||||
context.HttpContext.Response.Body = stream;
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
}
|
||||
|
||||
private void ThenTheUserIsAuthenticated()
|
||||
{
|
||||
var content = _downstreamContext.HttpContext.Response.Body.AsString();
|
||||
content.ShouldBe("The user is authenticated");
|
||||
}
|
||||
|
||||
private void GivenTheDownStreamRouteIs(DownstreamReRoute downstreamRoute)
|
||||
{
|
||||
_downstreamContext.DownstreamReRoute = downstreamRoute;
|
||||
}
|
||||
}
|
||||
|
||||
public static class StreamExtensions
|
||||
{
|
||||
public static string AsString(this Stream stream)
|
||||
{
|
||||
using(var reader = new StreamReader(stream))
|
||||
{
|
||||
string text = reader.ReadToEnd();
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using Xunit;
|
||||
|
||||
[assembly: CollectionBehavior(DisableTestParallelization = true)]
|
||||
|
||||
namespace Ocelot.UnitTests.Authentication
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Moq;
|
||||
using Ocelot.Authentication.Middleware;
|
||||
using Ocelot.Configuration.Builder;
|
||||
using Ocelot.Logging;
|
||||
using Shouldly;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
using Ocelot.Configuration;
|
||||
using Ocelot.Middleware;
|
||||
|
||||
public class AuthenticationMiddlewareTests
|
||||
{
|
||||
private AuthenticationMiddleware _middleware;
|
||||
private readonly Mock<IOcelotLoggerFactory> _factory;
|
||||
private Mock<IOcelotLogger> _logger;
|
||||
private OcelotRequestDelegate _next;
|
||||
private readonly DownstreamContext _downstreamContext;
|
||||
|
||||
public AuthenticationMiddlewareTests()
|
||||
{
|
||||
_factory = new Mock<IOcelotLoggerFactory>();
|
||||
_logger = new Mock<IOcelotLogger>();
|
||||
_factory.Setup(x => x.CreateLogger<AuthenticationMiddleware>()).Returns(_logger.Object);
|
||||
_downstreamContext = new DownstreamContext(new DefaultHttpContext());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_call_next_middleware_if_route_is_not_authenticated()
|
||||
{
|
||||
this.Given(x => GivenTheDownStreamRouteIs(
|
||||
new DownstreamReRouteBuilder().WithUpstreamHttpMethod(new List<string> { "Get" }).Build()))
|
||||
.And(x => GivenTheTestServerPipelineIsConfigured())
|
||||
.When(x => WhenICallTheMiddleware())
|
||||
.Then(x => ThenTheUserIsAuthenticated())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void WhenICallTheMiddleware()
|
||||
{
|
||||
_next = (context) => {
|
||||
byte[] byteArray = Encoding.ASCII.GetBytes("The user is authenticated");
|
||||
var stream = new MemoryStream(byteArray);
|
||||
context.HttpContext.Response.Body = stream;
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
_middleware = new AuthenticationMiddleware(_next, _factory.Object);
|
||||
_middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
private void GivenTheTestServerPipelineIsConfigured()
|
||||
{
|
||||
_next = (context) => {
|
||||
byte[] byteArray = Encoding.ASCII.GetBytes("The user is authenticated");
|
||||
var stream = new MemoryStream(byteArray);
|
||||
context.HttpContext.Response.Body = stream;
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
}
|
||||
|
||||
private void ThenTheUserIsAuthenticated()
|
||||
{
|
||||
var content = _downstreamContext.HttpContext.Response.Body.AsString();
|
||||
content.ShouldBe("The user is authenticated");
|
||||
}
|
||||
|
||||
private void GivenTheDownStreamRouteIs(DownstreamReRoute downstreamRoute)
|
||||
{
|
||||
_downstreamContext.DownstreamReRoute = downstreamRoute;
|
||||
}
|
||||
}
|
||||
|
||||
public static class StreamExtensions
|
||||
{
|
||||
public static string AsString(this Stream stream)
|
||||
{
|
||||
using(var reader = new StreamReader(stream))
|
||||
{
|
||||
string text = reader.ReadToEnd();
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,103 +0,0 @@
|
||||
using System;
|
||||
using CacheManager.Core;
|
||||
using Moq;
|
||||
using Ocelot.Cache;
|
||||
using Shouldly;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
|
||||
namespace Ocelot.UnitTests.Cache
|
||||
{
|
||||
public class CacheManagerCacheTests
|
||||
{
|
||||
private OcelotCacheManagerCache<string> _ocelotOcelotCacheManager;
|
||||
private Mock<ICacheManager<string>> _mockCacheManager;
|
||||
private string _key;
|
||||
private string _value;
|
||||
private string _resultGet;
|
||||
private TimeSpan _ttlSeconds;
|
||||
private string _region;
|
||||
|
||||
public CacheManagerCacheTests()
|
||||
{
|
||||
_mockCacheManager = new Mock<ICacheManager<string>>();
|
||||
_ocelotOcelotCacheManager = new OcelotCacheManagerCache<string>(_mockCacheManager.Object);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_get_from_cache()
|
||||
{
|
||||
this.Given(x => x.GivenTheFollowingIsCached("someKey", "someRegion", "someValue"))
|
||||
.When(x => x.WhenIGetFromTheCache())
|
||||
.Then(x => x.ThenTheResultIs("someValue"))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_add_to_cache()
|
||||
{
|
||||
this.When(x => x.WhenIAddToTheCache("someKey", "someValue", TimeSpan.FromSeconds(1)))
|
||||
.Then(x => x.ThenTheCacheIsCalledCorrectly())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_delete_key_from_cache()
|
||||
{
|
||||
this.Given(_ => GivenTheFollowingRegion("fookey"))
|
||||
.When(_ => WhenIDeleteTheRegion("fookey"))
|
||||
.Then(_ => ThenTheRegionIsDeleted("fookey"))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void WhenIDeleteTheRegion(string region)
|
||||
{
|
||||
_ocelotOcelotCacheManager.ClearRegion(region);
|
||||
}
|
||||
|
||||
private void ThenTheRegionIsDeleted(string region)
|
||||
{
|
||||
_mockCacheManager
|
||||
.Verify(x => x.ClearRegion(region), Times.Once);
|
||||
}
|
||||
|
||||
private void GivenTheFollowingRegion(string key)
|
||||
{
|
||||
_ocelotOcelotCacheManager.Add(key, "doesnt matter", TimeSpan.FromSeconds(10), "region");
|
||||
}
|
||||
|
||||
private void WhenIAddToTheCache(string key, string value, TimeSpan ttlSeconds)
|
||||
{
|
||||
_key = key;
|
||||
_value = value;
|
||||
_ttlSeconds = ttlSeconds;
|
||||
_ocelotOcelotCacheManager.Add(_key, _value, _ttlSeconds, "region");
|
||||
}
|
||||
|
||||
private void ThenTheCacheIsCalledCorrectly()
|
||||
{
|
||||
_mockCacheManager
|
||||
.Verify(x => x.Add(It.IsAny<CacheItem<string>>()), Times.Once);
|
||||
}
|
||||
|
||||
private void ThenTheResultIs(string expected)
|
||||
{
|
||||
_resultGet.ShouldBe(expected);
|
||||
}
|
||||
|
||||
private void WhenIGetFromTheCache()
|
||||
{
|
||||
_resultGet = _ocelotOcelotCacheManager.Get(_key, _region);
|
||||
}
|
||||
|
||||
private void GivenTheFollowingIsCached(string key, string region, string value)
|
||||
{
|
||||
_key = key;
|
||||
_value = value;
|
||||
_region = region;
|
||||
_mockCacheManager
|
||||
.Setup(x => x.Get<string>(It.IsAny<string>(), It.IsAny<string>()))
|
||||
.Returns(value);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
namespace Ocelot.UnitTests.Cache
|
||||
{
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http.Headers;
|
||||
using CacheManager.Core;
|
||||
using Shouldly;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Moq;
|
||||
using Ocelot.Cache;
|
||||
using Ocelot.Cache.Middleware;
|
||||
using Ocelot.Configuration;
|
||||
using Ocelot.Configuration.Builder;
|
||||
using Ocelot.Logging;
|
||||
using Ocelot.Middleware;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Ocelot.Middleware.Multiplexer;
|
||||
|
||||
public class OutputCacheMiddlewareRealCacheTests
|
||||
{
|
||||
private readonly IOcelotCache<CachedResponse> _cacheManager;
|
||||
private readonly OutputCacheMiddleware _middleware;
|
||||
private readonly DownstreamContext _downstreamContext;
|
||||
private OcelotRequestDelegate _next;
|
||||
private Mock<IOcelotLoggerFactory> _loggerFactory;
|
||||
private IRegionCreator _regionCreator;
|
||||
private Mock<IOcelotLogger> _logger;
|
||||
|
||||
public OutputCacheMiddlewareRealCacheTests()
|
||||
{
|
||||
_loggerFactory = new Mock<IOcelotLoggerFactory>();
|
||||
_logger = new Mock<IOcelotLogger>();
|
||||
_loggerFactory.Setup(x => x.CreateLogger<OutputCacheMiddleware>()).Returns(_logger.Object);
|
||||
_regionCreator = new RegionCreator();
|
||||
var cacheManagerOutputCache = CacheFactory.Build<CachedResponse>("OcelotOutputCache", x =>
|
||||
{
|
||||
x.WithDictionaryHandle();
|
||||
});
|
||||
_cacheManager = new OcelotCacheManagerCache<CachedResponse>(cacheManagerOutputCache);
|
||||
_downstreamContext = new DownstreamContext(new DefaultHttpContext());
|
||||
_downstreamContext.DownstreamRequest = new Ocelot.Request.Middleware.DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "https://some.url/blah?abcd=123"));
|
||||
_next = context => Task.CompletedTask;
|
||||
_middleware = new OutputCacheMiddleware(_next, _loggerFactory.Object, _cacheManager, _regionCreator);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_cache_content_headers()
|
||||
{
|
||||
var content = new StringContent("{\"Test\": 1}")
|
||||
{
|
||||
Headers = { ContentType = new MediaTypeHeaderValue("application/json")}
|
||||
};
|
||||
|
||||
var response = new DownstreamResponse(content, HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>());
|
||||
|
||||
this.Given(x => x.GivenResponseIsNotCached(response))
|
||||
.And(x => x.GivenTheDownstreamRouteIs())
|
||||
.When(x => x.WhenICallTheMiddleware())
|
||||
.Then(x => x.ThenTheContentTypeHeaderIsCached())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void WhenICallTheMiddleware()
|
||||
{
|
||||
_middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
private void ThenTheContentTypeHeaderIsCached()
|
||||
{
|
||||
var result = _cacheManager.Get("GET-https://some.url/blah?abcd=123", "kanken");
|
||||
var header = result.ContentHeaders["Content-Type"];
|
||||
header.First().ShouldBe("application/json");
|
||||
}
|
||||
|
||||
private void GivenResponseIsNotCached(DownstreamResponse response)
|
||||
{
|
||||
_downstreamContext.DownstreamResponse = response;
|
||||
}
|
||||
|
||||
private void GivenTheDownstreamRouteIs()
|
||||
{
|
||||
var reRoute = new DownstreamReRouteBuilder()
|
||||
.WithIsCached(true)
|
||||
.WithCacheOptions(new CacheOptions(100, "kanken"))
|
||||
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
||||
.Build();
|
||||
|
||||
_downstreamContext.DownstreamReRoute = reRoute;
|
||||
}
|
||||
}
|
||||
}
|
@ -16,24 +16,22 @@
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
using System.Net;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Ocelot.Middleware;
|
||||
using Ocelot.Middleware.Multiplexer;
|
||||
|
||||
public class OutputCacheMiddlewareTests
|
||||
{
|
||||
private readonly Mock<IOcelotCache<CachedResponse>> _cacheManager;
|
||||
private readonly Mock<IOcelotCache<CachedResponse>> _cache;
|
||||
private readonly Mock<IOcelotLoggerFactory> _loggerFactory;
|
||||
private Mock<IOcelotLogger> _logger;
|
||||
private OutputCacheMiddleware _middleware;
|
||||
private readonly DownstreamContext _downstreamContext;
|
||||
private readonly OcelotRequestDelegate _next;
|
||||
private CachedResponse _response;
|
||||
private readonly IRegionCreator _regionCreator;
|
||||
|
||||
public OutputCacheMiddlewareTests()
|
||||
{
|
||||
_cacheManager = new Mock<IOcelotCache<CachedResponse>>();
|
||||
_regionCreator = new RegionCreator();
|
||||
_cache = new Mock<IOcelotCache<CachedResponse>>();
|
||||
_downstreamContext = new DownstreamContext(new DefaultHttpContext());
|
||||
_loggerFactory = new Mock<IOcelotLoggerFactory>();
|
||||
_logger = new Mock<IOcelotLogger>();
|
||||
@ -91,14 +89,14 @@
|
||||
|
||||
private void WhenICallTheMiddleware()
|
||||
{
|
||||
_middleware = new OutputCacheMiddleware(_next, _loggerFactory.Object, _cacheManager.Object, _regionCreator);
|
||||
_middleware = new OutputCacheMiddleware(_next, _loggerFactory.Object, _cache.Object);
|
||||
_middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
private void GivenThereIsACachedResponse(CachedResponse response)
|
||||
{
|
||||
_response = response;
|
||||
_cacheManager
|
||||
_cache
|
||||
.Setup(x => x.Get(It.IsAny<string>(), It.IsAny<string>()))
|
||||
.Returns(_response);
|
||||
}
|
||||
@ -127,13 +125,13 @@
|
||||
|
||||
private void ThenTheCacheGetIsCalledCorrectly()
|
||||
{
|
||||
_cacheManager
|
||||
_cache
|
||||
.Verify(x => x.Get(It.IsAny<string>(), It.IsAny<string>()), Times.Once);
|
||||
}
|
||||
|
||||
private void ThenTheCacheAddIsCalledCorrectly()
|
||||
{
|
||||
_cacheManager
|
||||
_cache
|
||||
.Verify(x => x.Add(It.IsAny<string>(), It.IsAny<CachedResponse>(), It.IsAny<TimeSpan>(), It.IsAny<string>()), Times.Once);
|
||||
}
|
||||
}
|
||||
|
@ -1,263 +0,0 @@
|
||||
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 _setResult;
|
||||
private Response<FileConfiguration> _getResult;
|
||||
|
||||
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(), "", It.IsAny<LoadBalancerOptions>(), It.IsAny<string>(), It.IsAny<QoSOptions>(), It.IsAny<HttpHandlerOptions>())));
|
||||
|
||||
_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();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_get_config()
|
||||
{
|
||||
var config = FakeFileConfiguration();
|
||||
|
||||
this.Given(_ => GivenIHaveAConfiguration(config))
|
||||
.And(_ => GivenFetchFromConsulSucceeds())
|
||||
.When(_ => WhenIGetTheConfiguration())
|
||||
.Then(_ => ThenTheConfigurationIs(config))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_get_null_config()
|
||||
{
|
||||
this.Given(_ => GivenFetchFromConsulReturnsNull())
|
||||
.When(_ => WhenIGetTheConfiguration())
|
||||
.Then(_ => ThenTheConfigurationIsNull())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_get_config_from_cache()
|
||||
{
|
||||
var config = FakeFileConfiguration();
|
||||
|
||||
this.Given(_ => GivenIHaveAConfiguration(config))
|
||||
.And(_ => GivenFetchFromCacheSucceeds())
|
||||
.When(_ => WhenIGetTheConfiguration())
|
||||
.Then(_ => ThenTheConfigurationIs(config))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_set_config_key()
|
||||
{
|
||||
var config = FakeFileConfiguration();
|
||||
|
||||
this.Given(_ => GivenIHaveAConfiguration(config))
|
||||
.And(_ => GivenTheConfigKeyComesFromFileConfig("Tom"))
|
||||
.And(_ => GivenFetchFromConsulSucceeds())
|
||||
.When(_ => WhenIGetTheConfiguration())
|
||||
.And(_ => ThenTheConfigKeyIs("Tom"))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_set_default_config_key()
|
||||
{
|
||||
var config = FakeFileConfiguration();
|
||||
|
||||
this.Given(_ => GivenIHaveAConfiguration(config))
|
||||
.And(_ => GivenFetchFromConsulSucceeds())
|
||||
.When(_ => WhenIGetTheConfiguration())
|
||||
.And(_ => ThenTheConfigKeyIs("InternalConfiguration"))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void ThenTheConfigKeyIs(string expected)
|
||||
{
|
||||
_kvEndpoint
|
||||
.Verify(x => x.Get(expected, It.IsAny<CancellationToken>()), Times.Once);
|
||||
}
|
||||
|
||||
private void GivenTheConfigKeyComesFromFileConfig(string key)
|
||||
{
|
||||
_internalRepo
|
||||
.Setup(x => x.Get())
|
||||
.Returns(new OkResponse<IInternalConfiguration>(new InternalConfiguration(new List<ReRoute>(), "",
|
||||
new ServiceProviderConfigurationBuilder().WithConfigurationKey(key).Build(), "",
|
||||
new LoadBalancerOptionsBuilder().Build(), "", new QoSOptionsBuilder().Build(),
|
||||
new HttpHandlerOptionsBuilder().Build())));
|
||||
|
||||
_repo = new ConsulFileConfigurationRepository(_cache.Object, _internalRepo.Object, _factory.Object, _loggerFactory.Object);
|
||||
}
|
||||
|
||||
private void ThenTheConfigurationIsNull()
|
||||
{
|
||||
_getResult.Data.ShouldBeNull();
|
||||
}
|
||||
|
||||
private void ThenTheConfigurationIs(FileConfiguration config)
|
||||
{
|
||||
var expected = JsonConvert.SerializeObject(config, Formatting.Indented);
|
||||
var result = JsonConvert.SerializeObject(_getResult.Data, Formatting.Indented);
|
||||
result.ShouldBe(expected);
|
||||
}
|
||||
|
||||
private async Task WhenIGetTheConfiguration()
|
||||
{
|
||||
_getResult = await _repo.Get();
|
||||
}
|
||||
|
||||
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 GivenFetchFromCacheSucceeds()
|
||||
{
|
||||
_cache.Setup(x => x.Get(It.IsAny<string>(), It.IsAny<string>())).Returns(_fileConfiguration);
|
||||
}
|
||||
|
||||
private void GivenFetchFromConsulReturnsNull()
|
||||
{
|
||||
QueryResult<KVPair> result = new QueryResult<KVPair>();
|
||||
|
||||
_kvEndpoint
|
||||
.Setup(x => x.Get(It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(result);
|
||||
}
|
||||
|
||||
private void GivenFetchFromConsulSucceeds()
|
||||
{
|
||||
var json = JsonConvert.SerializeObject(_fileConfiguration, Formatting.Indented);
|
||||
|
||||
var bytes = Encoding.UTF8.GetBytes(json);
|
||||
|
||||
var kvp = new KVPair("OcelotConfiguration");
|
||||
kvp.Value = bytes;
|
||||
|
||||
var query = new QueryResult<KVPair>();
|
||||
query.Response = kvp;
|
||||
|
||||
_kvEndpoint
|
||||
.Setup(x => x.Get(It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(query);
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
_setResult = 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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,242 +1,287 @@
|
||||
namespace Ocelot.UnitTests.Configuration
|
||||
{
|
||||
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;
|
||||
|
||||
// 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 DiskFileConfigurationRepositoryTests()
|
||||
{
|
||||
_hostingEnvironment.Setup(he => he.EnvironmentName).Returns(_environmentName);
|
||||
_repo = new DiskFileConfigurationRepository(_hostingEnvironment.Object);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_return_file_configuration()
|
||||
{
|
||||
var config = FakeFileConfigurationForGet();
|
||||
|
||||
this.Given(_ => GivenTheConfigurationIs(config))
|
||||
.When(_ => WhenIGetTheReRoutes())
|
||||
.Then(_ => ThenTheFollowingIsReturned(config))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_return_file_configuration_if_environment_name_is_unavailable()
|
||||
{
|
||||
var config = FakeFileConfigurationForGet();
|
||||
|
||||
this.Given(_ => GivenTheEnvironmentNameIsUnavailable())
|
||||
.And(_ => GivenTheConfigurationIs(config))
|
||||
.When(_ => WhenIGetTheReRoutes())
|
||||
.Then(_ => ThenTheFollowingIsReturned(config))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_set_file_configuration()
|
||||
{
|
||||
var config = FakeFileConfigurationForSet();
|
||||
|
||||
this.Given(_ => GivenIHaveAConfiguration(config))
|
||||
.When(_ => WhenISetTheConfiguration())
|
||||
.Then(_ => ThenTheConfigurationIsStoredAs(config))
|
||||
.And(_ => ThenTheConfigurationJsonIsIndented(config))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_set_file_configuration_if_environment_name_is_unavailable()
|
||||
{
|
||||
var config = FakeFileConfigurationForSet();
|
||||
|
||||
this.Given(_ => GivenIHaveAConfiguration(config))
|
||||
.And(_ => GivenTheEnvironmentNameIsUnavailable())
|
||||
.When(_ => WhenISetTheConfiguration())
|
||||
.Then(_ => ThenTheConfigurationIsStoredAs(config))
|
||||
.And(_ => ThenTheConfigurationJsonIsIndented(config))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void GivenTheEnvironmentNameIsUnavailable()
|
||||
{
|
||||
_environmentName = null;
|
||||
_hostingEnvironment.Setup(he => he.EnvironmentName).Returns(_environmentName);
|
||||
_repo = new DiskFileConfigurationRepository(_hostingEnvironment.Object);
|
||||
}
|
||||
|
||||
private void GivenIHaveAConfiguration(FileConfiguration fileConfiguration)
|
||||
{
|
||||
_fileConfiguration = fileConfiguration;
|
||||
}
|
||||
|
||||
private void WhenISetTheConfiguration()
|
||||
{
|
||||
_repo.Set(_fileConfiguration);
|
||||
_result = _repo.Get().Result.Data;
|
||||
}
|
||||
|
||||
private void ThenTheConfigurationIsStoredAs(FileConfiguration expecteds)
|
||||
{
|
||||
_result.GlobalConfiguration.RequestIdKey.ShouldBe(expecteds.GlobalConfiguration.RequestIdKey);
|
||||
_result.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Host);
|
||||
_result.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Port);
|
||||
|
||||
for(var i = 0; i < _result.ReRoutes.Count; i++)
|
||||
{
|
||||
for (int j = 0; j < _result.ReRoutes[i].DownstreamHostAndPorts.Count; j++)
|
||||
{
|
||||
var result = _result.ReRoutes[i].DownstreamHostAndPorts[j];
|
||||
var expected = expecteds.ReRoutes[i].DownstreamHostAndPorts[j];
|
||||
|
||||
result.Host.ShouldBe(expected.Host);
|
||||
result.Port.ShouldBe(expected.Port);
|
||||
}
|
||||
|
||||
_result.ReRoutes[i].DownstreamPathTemplate.ShouldBe(expecteds.ReRoutes[i].DownstreamPathTemplate);
|
||||
_result.ReRoutes[i].DownstreamScheme.ShouldBe(expecteds.ReRoutes[i].DownstreamScheme);
|
||||
}
|
||||
}
|
||||
|
||||
private void GivenTheConfigurationIs(FileConfiguration fileConfiguration)
|
||||
{
|
||||
_configurationPath = $"{AppContext.BaseDirectory}/ocelot{(string.IsNullOrEmpty(_environmentName) ? string.Empty : ".")}{_environmentName}.json";
|
||||
|
||||
var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration, Formatting.Indented);
|
||||
|
||||
if (File.Exists(_configurationPath))
|
||||
{
|
||||
File.Delete(_configurationPath);
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
_result = _repo.Get().Result.Data;
|
||||
}
|
||||
|
||||
private void ThenTheFollowingIsReturned(FileConfiguration expecteds)
|
||||
{
|
||||
_result.GlobalConfiguration.RequestIdKey.ShouldBe(expecteds.GlobalConfiguration.RequestIdKey);
|
||||
_result.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Host);
|
||||
_result.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Port);
|
||||
|
||||
for(var i = 0; i < _result.ReRoutes.Count; i++)
|
||||
{
|
||||
for (int j = 0; j < _result.ReRoutes[i].DownstreamHostAndPorts.Count; j++)
|
||||
{
|
||||
var result = _result.ReRoutes[i].DownstreamHostAndPorts[j];
|
||||
var expected = expecteds.ReRoutes[i].DownstreamHostAndPorts[j];
|
||||
|
||||
result.Host.ShouldBe(expected.Host);
|
||||
result.Port.ShouldBe(expected.Port);
|
||||
}
|
||||
|
||||
_result.ReRoutes[i].DownstreamPathTemplate.ShouldBe(expecteds.ReRoutes[i].DownstreamPathTemplate);
|
||||
_result.ReRoutes[i].DownstreamScheme.ShouldBe(expecteds.ReRoutes[i].DownstreamScheme);
|
||||
}
|
||||
}
|
||||
|
||||
private FileConfiguration FakeFileConfigurationForSet()
|
||||
{
|
||||
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
|
||||
};
|
||||
}
|
||||
|
||||
private FileConfiguration FakeFileConfigurationForGet()
|
||||
{
|
||||
var reRoutes = new List<FileReRoute>
|
||||
{
|
||||
new FileReRoute
|
||||
{
|
||||
DownstreamHostAndPorts = new List<FileHostAndPort>
|
||||
{
|
||||
new FileHostAndPort
|
||||
{
|
||||
Host = "localhost",
|
||||
Port = 80,
|
||||
}
|
||||
},
|
||||
DownstreamScheme = "https",
|
||||
DownstreamPathTemplate = "/test/test/{test}"
|
||||
}
|
||||
};
|
||||
|
||||
var globalConfiguration = new FileGlobalConfiguration
|
||||
{
|
||||
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
|
||||
{
|
||||
Port = 198,
|
||||
Host = "blah"
|
||||
}
|
||||
};
|
||||
|
||||
return new FileConfiguration
|
||||
{
|
||||
GlobalConfiguration = globalConfiguration,
|
||||
ReRoutes = reRoutes
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace Ocelot.UnitTests.Configuration
|
||||
{
|
||||
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 System.Threading;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Ocelot.Configuration.Repository;
|
||||
|
||||
public class DiskFileConfigurationRepositoryTests : IDisposable
|
||||
{
|
||||
private readonly Mock<IHostingEnvironment> _hostingEnvironment;
|
||||
private IFileConfigurationRepository _repo;
|
||||
private string _environmentSpecificPath;
|
||||
private string _ocelotJsonPath;
|
||||
private FileConfiguration _result;
|
||||
private FileConfiguration _fileConfiguration;
|
||||
|
||||
// This is a bit dirty and it is dev.dev so that the ConfigurationBuilderExtensionsTests
|
||||
// cant pick it up if they run in parralel..and the semaphore stops them running at the same time...sigh
|
||||
// these are not really unit tests but whatever...
|
||||
private string _environmentName = "DEV.DEV";
|
||||
private static SemaphoreSlim _semaphore;
|
||||
|
||||
public DiskFileConfigurationRepositoryTests()
|
||||
{
|
||||
_semaphore = new SemaphoreSlim(1, 1);
|
||||
_semaphore.Wait();
|
||||
_hostingEnvironment = new Mock<IHostingEnvironment>();
|
||||
_hostingEnvironment.Setup(he => he.EnvironmentName).Returns(_environmentName);
|
||||
_repo = new DiskFileConfigurationRepository(_hostingEnvironment.Object);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_return_file_configuration()
|
||||
{
|
||||
var config = FakeFileConfigurationForGet();
|
||||
|
||||
this.Given(_ => GivenTheConfigurationIs(config))
|
||||
.When(_ => WhenIGetTheReRoutes())
|
||||
.Then(_ => ThenTheFollowingIsReturned(config))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_return_file_configuration_if_environment_name_is_unavailable()
|
||||
{
|
||||
var config = FakeFileConfigurationForGet();
|
||||
|
||||
this.Given(_ => GivenTheEnvironmentNameIsUnavailable())
|
||||
.And(_ => GivenTheConfigurationIs(config))
|
||||
.When(_ => WhenIGetTheReRoutes())
|
||||
.Then(_ => ThenTheFollowingIsReturned(config))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_set_file_configuration()
|
||||
{
|
||||
var config = FakeFileConfigurationForSet();
|
||||
|
||||
this.Given(_ => GivenIHaveAConfiguration(config))
|
||||
.When(_ => WhenISetTheConfiguration())
|
||||
.Then(_ => ThenTheConfigurationIsStoredAs(config))
|
||||
.And(_ => ThenTheConfigurationJsonIsIndented(config))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_set_file_configuration_if_environment_name_is_unavailable()
|
||||
{
|
||||
var config = FakeFileConfigurationForSet();
|
||||
|
||||
this.Given(_ => GivenIHaveAConfiguration(config))
|
||||
.And(_ => GivenTheEnvironmentNameIsUnavailable())
|
||||
.When(_ => WhenISetTheConfiguration())
|
||||
.Then(_ => ThenTheConfigurationIsStoredAs(config))
|
||||
.And(_ => ThenTheConfigurationJsonIsIndented(config))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_set_environment_file_configuration_and_ocelot_file_configuration()
|
||||
{
|
||||
var config = FakeFileConfigurationForSet();
|
||||
|
||||
this.Given(_ => GivenIHaveAConfiguration(config))
|
||||
.And(_ => GivenTheConfigurationIs(config))
|
||||
.And(_ => GivenTheUserAddedOcelotJson())
|
||||
.When(_ => WhenISetTheConfiguration())
|
||||
.Then(_ => ThenTheConfigurationIsStoredAs(config))
|
||||
.And(_ => ThenTheConfigurationJsonIsIndented(config))
|
||||
.Then(_ => ThenTheOcelotJsonIsStoredAs(config))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void GivenTheUserAddedOcelotJson()
|
||||
{
|
||||
_ocelotJsonPath = $"{AppContext.BaseDirectory}/ocelot.json";
|
||||
|
||||
if (File.Exists(_ocelotJsonPath))
|
||||
{
|
||||
File.Delete(_ocelotJsonPath);
|
||||
}
|
||||
|
||||
File.WriteAllText(_ocelotJsonPath, "Doesnt matter");
|
||||
}
|
||||
|
||||
private void GivenTheEnvironmentNameIsUnavailable()
|
||||
{
|
||||
_environmentName = null;
|
||||
_hostingEnvironment.Setup(he => he.EnvironmentName).Returns(_environmentName);
|
||||
_repo = new DiskFileConfigurationRepository(_hostingEnvironment.Object);
|
||||
}
|
||||
|
||||
private void GivenIHaveAConfiguration(FileConfiguration fileConfiguration)
|
||||
{
|
||||
_fileConfiguration = fileConfiguration;
|
||||
}
|
||||
|
||||
private void WhenISetTheConfiguration()
|
||||
{
|
||||
_repo.Set(_fileConfiguration);
|
||||
_result = _repo.Get().Result.Data;
|
||||
}
|
||||
|
||||
private void ThenTheConfigurationIsStoredAs(FileConfiguration expecteds)
|
||||
{
|
||||
_result.GlobalConfiguration.RequestIdKey.ShouldBe(expecteds.GlobalConfiguration.RequestIdKey);
|
||||
_result.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Host);
|
||||
_result.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Port);
|
||||
|
||||
for(var i = 0; i < _result.ReRoutes.Count; i++)
|
||||
{
|
||||
for (int j = 0; j < _result.ReRoutes[i].DownstreamHostAndPorts.Count; j++)
|
||||
{
|
||||
var result = _result.ReRoutes[i].DownstreamHostAndPorts[j];
|
||||
var expected = expecteds.ReRoutes[i].DownstreamHostAndPorts[j];
|
||||
|
||||
result.Host.ShouldBe(expected.Host);
|
||||
result.Port.ShouldBe(expected.Port);
|
||||
}
|
||||
|
||||
_result.ReRoutes[i].DownstreamPathTemplate.ShouldBe(expecteds.ReRoutes[i].DownstreamPathTemplate);
|
||||
_result.ReRoutes[i].DownstreamScheme.ShouldBe(expecteds.ReRoutes[i].DownstreamScheme);
|
||||
}
|
||||
}
|
||||
|
||||
private void ThenTheOcelotJsonIsStoredAs(FileConfiguration expecteds)
|
||||
{
|
||||
var resultText = File.ReadAllText(_ocelotJsonPath);
|
||||
var expectedText = JsonConvert.SerializeObject(expecteds, Formatting.Indented);
|
||||
resultText.ShouldBe(expectedText);
|
||||
}
|
||||
|
||||
private void GivenTheConfigurationIs(FileConfiguration fileConfiguration)
|
||||
{
|
||||
_environmentSpecificPath = $"{AppContext.BaseDirectory}/ocelot{(string.IsNullOrEmpty(_environmentName) ? string.Empty : ".")}{_environmentName}.json";
|
||||
|
||||
var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration, Formatting.Indented);
|
||||
|
||||
if (File.Exists(_environmentSpecificPath))
|
||||
{
|
||||
File.Delete(_environmentSpecificPath);
|
||||
}
|
||||
|
||||
File.WriteAllText(_environmentSpecificPath, jsonConfiguration);
|
||||
}
|
||||
|
||||
private void ThenTheConfigurationJsonIsIndented(FileConfiguration expecteds)
|
||||
{
|
||||
var path = !string.IsNullOrEmpty(_environmentSpecificPath) ? _environmentSpecificPath : _environmentSpecificPath = $"{AppContext.BaseDirectory}/ocelot{(string.IsNullOrEmpty(_environmentName) ? string.Empty : ".")}{_environmentName}.json";
|
||||
|
||||
var resultText = File.ReadAllText(path);
|
||||
var expectedText = JsonConvert.SerializeObject(expecteds, Formatting.Indented);
|
||||
resultText.ShouldBe(expectedText);
|
||||
}
|
||||
|
||||
private void WhenIGetTheReRoutes()
|
||||
{
|
||||
_result = _repo.Get().Result.Data;
|
||||
}
|
||||
|
||||
private void ThenTheFollowingIsReturned(FileConfiguration expecteds)
|
||||
{
|
||||
_result.GlobalConfiguration.RequestIdKey.ShouldBe(expecteds.GlobalConfiguration.RequestIdKey);
|
||||
_result.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Host);
|
||||
_result.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Port);
|
||||
|
||||
for(var i = 0; i < _result.ReRoutes.Count; i++)
|
||||
{
|
||||
for (int j = 0; j < _result.ReRoutes[i].DownstreamHostAndPorts.Count; j++)
|
||||
{
|
||||
var result = _result.ReRoutes[i].DownstreamHostAndPorts[j];
|
||||
var expected = expecteds.ReRoutes[i].DownstreamHostAndPorts[j];
|
||||
|
||||
result.Host.ShouldBe(expected.Host);
|
||||
result.Port.ShouldBe(expected.Port);
|
||||
}
|
||||
|
||||
_result.ReRoutes[i].DownstreamPathTemplate.ShouldBe(expecteds.ReRoutes[i].DownstreamPathTemplate);
|
||||
_result.ReRoutes[i].DownstreamScheme.ShouldBe(expecteds.ReRoutes[i].DownstreamScheme);
|
||||
}
|
||||
}
|
||||
|
||||
private FileConfiguration FakeFileConfigurationForSet()
|
||||
{
|
||||
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
|
||||
};
|
||||
}
|
||||
|
||||
private FileConfiguration FakeFileConfigurationForGet()
|
||||
{
|
||||
var reRoutes = new List<FileReRoute>
|
||||
{
|
||||
new FileReRoute
|
||||
{
|
||||
DownstreamHostAndPorts = new List<FileHostAndPort>
|
||||
{
|
||||
new FileHostAndPort
|
||||
{
|
||||
Host = "localhost",
|
||||
Port = 80,
|
||||
}
|
||||
},
|
||||
DownstreamScheme = "https",
|
||||
DownstreamPathTemplate = "/test/test/{test}"
|
||||
}
|
||||
};
|
||||
|
||||
var globalConfiguration = new FileGlobalConfiguration
|
||||
{
|
||||
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
|
||||
{
|
||||
Port = 198,
|
||||
Host = "blah"
|
||||
}
|
||||
};
|
||||
|
||||
return new FileConfiguration
|
||||
{
|
||||
GlobalConfiguration = globalConfiguration,
|
||||
ReRoutes = reRoutes
|
||||
};
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_semaphore.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
{
|
||||
@ -69,7 +71,7 @@ namespace Ocelot.UnitTests.Configuration
|
||||
}
|
||||
};
|
||||
|
||||
this.Given(x => WhenTheConfigIsChangedInConsul(newConfig, 0))
|
||||
this.Given(x => WhenTheConfigIsChanged(newConfig, 0))
|
||||
.Then(x => ThenTheSetterIsCalledAtLeast(newConfig, 1))
|
||||
.BDDfy();
|
||||
}
|
||||
@ -94,13 +96,13 @@ namespace Ocelot.UnitTests.Configuration
|
||||
}
|
||||
};
|
||||
|
||||
this.Given(x => WhenTheConfigIsChangedInConsul(newConfig, 10))
|
||||
this.Given(x => WhenTheConfigIsChanged(newConfig, 10))
|
||||
.Then(x => ThenTheSetterIsCalled(newConfig, 1))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_do_nothing_if_call_to_consul_fails()
|
||||
public void should_do_nothing_if_call_to_provider_fails()
|
||||
{
|
||||
var newConfig = new FileConfiguration
|
||||
{
|
||||
@ -119,19 +121,19 @@ namespace Ocelot.UnitTests.Configuration
|
||||
}
|
||||
};
|
||||
|
||||
this.Given(x => WhenConsulErrors())
|
||||
this.Given(x => WhenProviderErrors())
|
||||
.Then(x => ThenTheSetterIsCalled(newConfig, 0))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void WhenConsulErrors()
|
||||
private void WhenProviderErrors()
|
||||
{
|
||||
_repo
|
||||
.Setup(x => x.Get())
|
||||
.ReturnsAsync(new ErrorResponse<FileConfiguration>(new AnyError()));
|
||||
}
|
||||
|
||||
private void WhenTheConfigIsChangedInConsul(FileConfiguration newConfig, int delay)
|
||||
private void WhenTheConfigIsChanged(FileConfiguration newConfig, int delay)
|
||||
{
|
||||
_repo
|
||||
.Setup(x => x.Get())
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@
|
||||
using Ocelot.Errors;
|
||||
using Ocelot.UnitTests.TestData;
|
||||
using Ocelot.Values;
|
||||
using System;
|
||||
|
||||
public class FileInternalConfigurationCreatorTests
|
||||
{
|
||||
@ -35,7 +36,7 @@
|
||||
private readonly Mock<IRateLimitOptionsCreator> _rateLimitOptions;
|
||||
private readonly Mock<IRegionCreator> _regionCreator;
|
||||
private readonly Mock<IHttpHandlerOptionsCreator> _httpHandlerOptionsCreator;
|
||||
private readonly Mock<IAdministrationPath> _adminPath;
|
||||
private readonly Mock<IServiceProvider> _serviceProvider;
|
||||
private readonly Mock<IHeaderFindAndReplaceCreator> _headerFindAndReplaceCreator;
|
||||
private readonly Mock<IDownstreamAddressesCreator> _downstreamAddressesCreator;
|
||||
|
||||
@ -53,7 +54,7 @@
|
||||
_rateLimitOptions = new Mock<IRateLimitOptionsCreator>();
|
||||
_regionCreator = new Mock<IRegionCreator>();
|
||||
_httpHandlerOptionsCreator = new Mock<IHttpHandlerOptionsCreator>();
|
||||
_adminPath = new Mock<IAdministrationPath>();
|
||||
_serviceProvider = new Mock<IServiceProvider>();
|
||||
_headerFindAndReplaceCreator = new Mock<IHeaderFindAndReplaceCreator>();
|
||||
_downstreamAddressesCreator = new Mock<IDownstreamAddressesCreator>();
|
||||
|
||||
@ -70,7 +71,7 @@
|
||||
_rateLimitOptions.Object,
|
||||
_regionCreator.Object,
|
||||
_httpHandlerOptionsCreator.Object,
|
||||
_adminPath.Object,
|
||||
_serviceProvider.Object,
|
||||
_headerFindAndReplaceCreator.Object,
|
||||
_downstreamAddressesCreator.Object);
|
||||
}
|
||||
@ -821,6 +822,54 @@
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_set_up_dynamic_re_routes()
|
||||
{
|
||||
var reRouteOptions = new ReRouteOptionsBuilder()
|
||||
.Build();
|
||||
|
||||
var downstreamReRoute = new DownstreamReRouteBuilder()
|
||||
.WithEnableRateLimiting(true)
|
||||
.WithRateLimitOptions(new RateLimitOptionsBuilder().Build())
|
||||
.Build();
|
||||
|
||||
var rateLimitOptions = new RateLimitOptionsBuilder()
|
||||
.WithRateLimitRule(new RateLimitRule("1s", 1, 1))
|
||||
.Build();
|
||||
|
||||
this.Given(x => x.GivenTheConfigIs(new FileConfiguration
|
||||
{
|
||||
DynamicReRoutes = new List<FileDynamicReRoute>
|
||||
{
|
||||
new FileDynamicReRoute
|
||||
{
|
||||
ServiceName = "test",
|
||||
RateLimitRule = new FileRateLimitRule
|
||||
{
|
||||
Period = "1s",
|
||||
PeriodTimespan = 1,
|
||||
Limit = 1
|
||||
}
|
||||
}
|
||||
},
|
||||
}))
|
||||
.And(x => x.GivenTheConfigIsValid())
|
||||
.And(x => GivenTheRateLimitCreatorReturns(rateLimitOptions))
|
||||
.And(x => GivenTheDownstreamAddresses())
|
||||
.And(x => GivenTheHeaderFindAndReplaceCreatorReturns())
|
||||
.And(x => x.GivenTheFollowingOptionsAreReturned(reRouteOptions))
|
||||
.When(x => x.WhenICreateTheConfig())
|
||||
.Then(x => x.ThenTheDynamicReRouteIsSetUp("test", rateLimitOptions.RateLimitRule))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void GivenTheRateLimitCreatorReturns(RateLimitOptions rateLimitOptions)
|
||||
{
|
||||
_rateLimitOptions
|
||||
.Setup(x => x.Create(It.IsAny<FileRateLimitRule>(), It.IsAny<FileGlobalConfiguration>()))
|
||||
.Returns(rateLimitOptions);
|
||||
}
|
||||
|
||||
private void GivenTheConfigIsInvalid(List<Error> errors)
|
||||
{
|
||||
_validator
|
||||
@ -844,7 +893,7 @@
|
||||
private void ThenTheRateLimitOptionsCreatorIsCalledCorrectly()
|
||||
{
|
||||
_rateLimitOptions
|
||||
.Verify(x => x.Create(It.IsAny<FileReRoute>(), It.IsAny<FileGlobalConfiguration>(), It.IsAny<bool>()), Times.Once);
|
||||
.Verify(x => x.Create(It.IsAny<FileRateLimitRule>(), It.IsAny<FileGlobalConfiguration>()), Times.Once);
|
||||
}
|
||||
|
||||
private void GivenTheConfigIsValid()
|
||||
@ -864,6 +913,16 @@
|
||||
_config = _internalConfigurationCreator.Create(_fileConfiguration).Result;
|
||||
}
|
||||
|
||||
private void ThenTheDynamicReRouteIsSetUp(string serviceName, RateLimitRule rateLimitOptions)
|
||||
{
|
||||
var dynamic = _config.Data.ReRoutes[0].DownstreamReRoute[0];
|
||||
dynamic.ServiceName.ShouldBe(serviceName);
|
||||
dynamic.EnableEndpointEndpointRateLimiting.ShouldBeTrue();
|
||||
dynamic.RateLimitOptions.RateLimitRule.Period.ShouldBe(rateLimitOptions.Period);
|
||||
dynamic.RateLimitOptions.RateLimitRule.Limit.ShouldBe(rateLimitOptions.Limit);
|
||||
dynamic.RateLimitOptions.RateLimitRule.PeriodTimespan.ShouldBe(rateLimitOptions.PeriodTimespan);
|
||||
}
|
||||
|
||||
private void ThenTheReRoutesAre(List<ReRoute> expectedReRoutes)
|
||||
{
|
||||
for (int i = 0; i < _config.Data.ReRoutes.Count; i++)
|
||||
|
@ -1,175 +1,182 @@
|
||||
using System;
|
||||
using Butterfly.Client.Tracing;
|
||||
using Butterfly.OpenTracing;
|
||||
using Ocelot.Configuration;
|
||||
using Ocelot.Configuration.Creator;
|
||||
using Ocelot.Configuration.File;
|
||||
using Ocelot.Requester;
|
||||
using Shouldly;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
|
||||
namespace Ocelot.UnitTests.Configuration
|
||||
{
|
||||
public class HttpHandlerOptionsCreatorTests
|
||||
{
|
||||
private IHttpHandlerOptionsCreator _httpHandlerOptionsCreator;
|
||||
private FileReRoute _fileReRoute;
|
||||
private HttpHandlerOptions _httpHandlerOptions;
|
||||
private IServiceTracer _serviceTracer;
|
||||
|
||||
public HttpHandlerOptionsCreatorTests()
|
||||
{
|
||||
_serviceTracer = new FakeServiceTracer();
|
||||
_httpHandlerOptionsCreator = new HttpHandlerOptionsCreator(_serviceTracer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_not_use_tracing_if_fake_tracer_registered()
|
||||
{
|
||||
var fileReRoute = new FileReRoute
|
||||
{
|
||||
HttpHandlerOptions = new FileHttpHandlerOptions
|
||||
{
|
||||
UseTracing = true
|
||||
}
|
||||
};
|
||||
|
||||
var expectedOptions = new HttpHandlerOptions(false, false, false, true);
|
||||
|
||||
this.Given(x => GivenTheFollowing(fileReRoute))
|
||||
.When(x => WhenICreateHttpHandlerOptions())
|
||||
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_use_tracing_if_real_tracer_registered()
|
||||
{
|
||||
var fileReRoute = new FileReRoute
|
||||
{
|
||||
HttpHandlerOptions = new FileHttpHandlerOptions
|
||||
{
|
||||
UseTracing = true
|
||||
}
|
||||
};
|
||||
|
||||
var expectedOptions = new HttpHandlerOptions(false, false, true, true);
|
||||
|
||||
this.Given(x => GivenTheFollowing(fileReRoute))
|
||||
.And(x => GivenARealTracer())
|
||||
.When(x => WhenICreateHttpHandlerOptions())
|
||||
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_create_options_with_useCookie_false_and_allowAutoRedirect_true_as_default()
|
||||
{
|
||||
var fileReRoute = new FileReRoute();
|
||||
var expectedOptions = new HttpHandlerOptions(false, false, false, true);
|
||||
|
||||
this.Given(x => GivenTheFollowing(fileReRoute))
|
||||
.When(x => WhenICreateHttpHandlerOptions())
|
||||
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_create_options_with_specified_useCookie_and_allowAutoRedirect()
|
||||
{
|
||||
var fileReRoute = new FileReRoute
|
||||
{
|
||||
HttpHandlerOptions = new FileHttpHandlerOptions
|
||||
{
|
||||
AllowAutoRedirect = false,
|
||||
UseCookieContainer = false,
|
||||
UseTracing = false
|
||||
}
|
||||
};
|
||||
|
||||
var expectedOptions = new HttpHandlerOptions(false, false, false, true);
|
||||
|
||||
this.Given(x => GivenTheFollowing(fileReRoute))
|
||||
.When(x => WhenICreateHttpHandlerOptions())
|
||||
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
|
||||
.BDDfy();
|
||||
using System;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Ocelot.Configuration;
|
||||
using Ocelot.Configuration.Creator;
|
||||
using Ocelot.Configuration.File;
|
||||
using Ocelot.Requester;
|
||||
using Shouldly;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
|
||||
namespace Ocelot.UnitTests.Configuration
|
||||
{
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Ocelot.Logging;
|
||||
|
||||
public class HttpHandlerOptionsCreatorTests
|
||||
{
|
||||
private IHttpHandlerOptionsCreator _httpHandlerOptionsCreator;
|
||||
private FileReRoute _fileReRoute;
|
||||
private HttpHandlerOptions _httpHandlerOptions;
|
||||
private IServiceProvider _serviceProvider;
|
||||
private IServiceCollection _serviceCollection;
|
||||
|
||||
public HttpHandlerOptionsCreatorTests()
|
||||
{
|
||||
_serviceCollection = new ServiceCollection();
|
||||
_serviceProvider = _serviceCollection.BuildServiceProvider();
|
||||
_httpHandlerOptionsCreator = new HttpHandlerOptionsCreator(_serviceProvider);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_create_options_with_useproxy_true_as_default()
|
||||
{
|
||||
var fileReRoute = new FileReRoute
|
||||
{
|
||||
HttpHandlerOptions = new FileHttpHandlerOptions()
|
||||
};
|
||||
|
||||
var expectedOptions = new HttpHandlerOptions(false, false, false, true);
|
||||
|
||||
this.Given(x => GivenTheFollowing(fileReRoute))
|
||||
.When(x => WhenICreateHttpHandlerOptions())
|
||||
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
|
||||
.BDDfy();
|
||||
[Fact]
|
||||
public void should_not_use_tracing_if_fake_tracer_registered()
|
||||
{
|
||||
var fileReRoute = new FileReRoute
|
||||
{
|
||||
HttpHandlerOptions = new FileHttpHandlerOptions
|
||||
{
|
||||
UseTracing = true
|
||||
}
|
||||
};
|
||||
|
||||
var expectedOptions = new HttpHandlerOptions(false, false, false, true);
|
||||
|
||||
this.Given(x => GivenTheFollowing(fileReRoute))
|
||||
.When(x => WhenICreateHttpHandlerOptions())
|
||||
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_create_options_with_specified_useproxy()
|
||||
{
|
||||
var fileReRoute = new FileReRoute
|
||||
{
|
||||
HttpHandlerOptions = new FileHttpHandlerOptions
|
||||
{
|
||||
UseProxy = false
|
||||
}
|
||||
};
|
||||
|
||||
var expectedOptions = new HttpHandlerOptions(false, false, false, false);
|
||||
|
||||
this.Given(x => GivenTheFollowing(fileReRoute))
|
||||
.When(x => WhenICreateHttpHandlerOptions())
|
||||
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void GivenTheFollowing(FileReRoute fileReRoute)
|
||||
{
|
||||
_fileReRoute = fileReRoute;
|
||||
}
|
||||
|
||||
private void WhenICreateHttpHandlerOptions()
|
||||
{
|
||||
_httpHandlerOptions = _httpHandlerOptionsCreator.Create(_fileReRoute.HttpHandlerOptions);
|
||||
}
|
||||
|
||||
private void ThenTheFollowingOptionsReturned(HttpHandlerOptions expected)
|
||||
{
|
||||
_httpHandlerOptions.ShouldNotBeNull();
|
||||
_httpHandlerOptions.AllowAutoRedirect.ShouldBe(expected.AllowAutoRedirect);
|
||||
_httpHandlerOptions.UseCookieContainer.ShouldBe(expected.UseCookieContainer);
|
||||
[Fact]
|
||||
public void should_use_tracing_if_real_tracer_registered()
|
||||
{
|
||||
var fileReRoute = new FileReRoute
|
||||
{
|
||||
HttpHandlerOptions = new FileHttpHandlerOptions
|
||||
{
|
||||
UseTracing = true
|
||||
}
|
||||
};
|
||||
|
||||
var expectedOptions = new HttpHandlerOptions(false, false, true, true);
|
||||
|
||||
this.Given(x => GivenTheFollowing(fileReRoute))
|
||||
.And(x => GivenARealTracer())
|
||||
.When(x => WhenICreateHttpHandlerOptions())
|
||||
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_create_options_with_useCookie_false_and_allowAutoRedirect_true_as_default()
|
||||
{
|
||||
var fileReRoute = new FileReRoute();
|
||||
var expectedOptions = new HttpHandlerOptions(false, false, false, true);
|
||||
|
||||
this.Given(x => GivenTheFollowing(fileReRoute))
|
||||
.When(x => WhenICreateHttpHandlerOptions())
|
||||
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_create_options_with_specified_useCookie_and_allowAutoRedirect()
|
||||
{
|
||||
var fileReRoute = new FileReRoute
|
||||
{
|
||||
HttpHandlerOptions = new FileHttpHandlerOptions
|
||||
{
|
||||
AllowAutoRedirect = false,
|
||||
UseCookieContainer = false,
|
||||
UseTracing = false
|
||||
}
|
||||
};
|
||||
|
||||
var expectedOptions = new HttpHandlerOptions(false, false, false, true);
|
||||
|
||||
this.Given(x => GivenTheFollowing(fileReRoute))
|
||||
.When(x => WhenICreateHttpHandlerOptions())
|
||||
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_create_options_with_useproxy_true_as_default()
|
||||
{
|
||||
var fileReRoute = new FileReRoute
|
||||
{
|
||||
HttpHandlerOptions = new FileHttpHandlerOptions()
|
||||
};
|
||||
|
||||
var expectedOptions = new HttpHandlerOptions(false, false, false, true);
|
||||
|
||||
this.Given(x => GivenTheFollowing(fileReRoute))
|
||||
.When(x => WhenICreateHttpHandlerOptions())
|
||||
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_create_options_with_specified_useproxy()
|
||||
{
|
||||
var fileReRoute = new FileReRoute
|
||||
{
|
||||
HttpHandlerOptions = new FileHttpHandlerOptions
|
||||
{
|
||||
UseProxy = false
|
||||
}
|
||||
};
|
||||
|
||||
var expectedOptions = new HttpHandlerOptions(false, false, false, false);
|
||||
|
||||
this.Given(x => GivenTheFollowing(fileReRoute))
|
||||
.When(x => WhenICreateHttpHandlerOptions())
|
||||
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void GivenTheFollowing(FileReRoute fileReRoute)
|
||||
{
|
||||
_fileReRoute = fileReRoute;
|
||||
}
|
||||
|
||||
private void WhenICreateHttpHandlerOptions()
|
||||
{
|
||||
_httpHandlerOptions = _httpHandlerOptionsCreator.Create(_fileReRoute.HttpHandlerOptions);
|
||||
}
|
||||
|
||||
private void ThenTheFollowingOptionsReturned(HttpHandlerOptions expected)
|
||||
{
|
||||
_httpHandlerOptions.ShouldNotBeNull();
|
||||
_httpHandlerOptions.AllowAutoRedirect.ShouldBe(expected.AllowAutoRedirect);
|
||||
_httpHandlerOptions.UseCookieContainer.ShouldBe(expected.UseCookieContainer);
|
||||
_httpHandlerOptions.UseTracing.ShouldBe(expected.UseTracing);
|
||||
_httpHandlerOptions.UseProxy.ShouldBe(expected.UseProxy);
|
||||
}
|
||||
|
||||
private void GivenARealTracer()
|
||||
{
|
||||
var tracer = new RealTracer();
|
||||
_httpHandlerOptionsCreator = new HttpHandlerOptionsCreator(tracer);
|
||||
}
|
||||
|
||||
class RealTracer : IServiceTracer
|
||||
{
|
||||
public ITracer Tracer => throw new NotImplementedException();
|
||||
|
||||
public string ServiceName => throw new NotImplementedException();
|
||||
|
||||
public string Environment => throw new NotImplementedException();
|
||||
|
||||
public string Identity => throw new NotImplementedException();
|
||||
|
||||
public ISpan Start(ISpanBuilder spanBuilder)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_httpHandlerOptions.UseProxy.ShouldBe(expected.UseProxy);
|
||||
}
|
||||
|
||||
private void GivenARealTracer()
|
||||
{
|
||||
var tracer = new FakeTracer();
|
||||
_serviceCollection.AddSingleton<ITracer, FakeTracer>();
|
||||
_serviceProvider = _serviceCollection.BuildServiceProvider();
|
||||
_httpHandlerOptionsCreator = new HttpHandlerOptionsCreator(_serviceProvider);
|
||||
}
|
||||
|
||||
class FakeTracer : ITracer
|
||||
{
|
||||
public void Event(HttpContext httpContext, string @event)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken, Action<string> addTraceIdToRepo,
|
||||
Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> baseSendAsync)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +0,0 @@
|
||||
using Ocelot.Configuration.Creator;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Ocelot.UnitTests.Configuration
|
||||
{
|
||||
public class IdentityServerConfigurationCreatorTests
|
||||
{
|
||||
[Fact]
|
||||
public void happy_path_only_exists_for_test_coverage_even_uncle_bob_probably_wouldnt_test_this()
|
||||
{
|
||||
var result = IdentityServerConfigurationCreator.GetIdentityServerConfiguration("secret");
|
||||
result.ApiName.ShouldBe("admin");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,108 +1,108 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Ocelot.Configuration;
|
||||
using Ocelot.Configuration.Builder;
|
||||
using Ocelot.Configuration.Creator;
|
||||
using Ocelot.Configuration.File;
|
||||
using Shouldly;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
|
||||
namespace Ocelot.UnitTests.Configuration
|
||||
{
|
||||
public class RateLimitOptionsCreatorTests
|
||||
{
|
||||
private FileReRoute _fileReRoute;
|
||||
private FileGlobalConfiguration _fileGlobalConfig;
|
||||
private bool _enabled;
|
||||
private RateLimitOptionsCreator _creator;
|
||||
private RateLimitOptions _result;
|
||||
|
||||
public RateLimitOptionsCreatorTests()
|
||||
{
|
||||
_creator = new RateLimitOptionsCreator();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_create_rate_limit_options()
|
||||
{
|
||||
var fileReRoute = new FileReRoute
|
||||
{
|
||||
RateLimitOptions = new FileRateLimitRule
|
||||
{
|
||||
ClientWhitelist = new List<string>(),
|
||||
Period = "Period",
|
||||
Limit = 1,
|
||||
PeriodTimespan = 1,
|
||||
EnableRateLimiting = true
|
||||
}
|
||||
};
|
||||
var fileGlobalConfig = new FileGlobalConfiguration
|
||||
{
|
||||
RateLimitOptions = new FileRateLimitOptions
|
||||
{
|
||||
ClientIdHeader = "ClientIdHeader",
|
||||
DisableRateLimitHeaders = true,
|
||||
QuotaExceededMessage = "QuotaExceededMessage",
|
||||
RateLimitCounterPrefix = "RateLimitCounterPrefix",
|
||||
HttpStatusCode = 200
|
||||
}
|
||||
};
|
||||
var expected = new RateLimitOptionsBuilder()
|
||||
.WithClientIdHeader("ClientIdHeader")
|
||||
.WithClientWhiteList(fileReRoute.RateLimitOptions.ClientWhitelist)
|
||||
.WithDisableRateLimitHeaders(true)
|
||||
.WithEnableRateLimiting(true)
|
||||
.WithHttpStatusCode(200)
|
||||
.WithQuotaExceededMessage("QuotaExceededMessage")
|
||||
.WithRateLimitCounterPrefix("RateLimitCounterPrefix")
|
||||
.WithRateLimitRule(new RateLimitRule(fileReRoute.RateLimitOptions.Period,
|
||||
fileReRoute.RateLimitOptions.PeriodTimespan,
|
||||
fileReRoute.RateLimitOptions.Limit))
|
||||
.Build();
|
||||
|
||||
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
|
||||
.And(x => x.GivenTheFollowingFileGlobalConfig(fileGlobalConfig))
|
||||
.And(x => x.GivenRateLimitingIsEnabled())
|
||||
.When(x => x.WhenICreate())
|
||||
.Then(x => x.ThenTheFollowingIsReturned(expected))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void GivenTheFollowingFileReRoute(FileReRoute fileReRoute)
|
||||
{
|
||||
_fileReRoute = fileReRoute;
|
||||
}
|
||||
|
||||
private void GivenTheFollowingFileGlobalConfig(FileGlobalConfiguration fileGlobalConfig)
|
||||
{
|
||||
_fileGlobalConfig = fileGlobalConfig;
|
||||
}
|
||||
|
||||
private void GivenRateLimitingIsEnabled()
|
||||
{
|
||||
_enabled = true;
|
||||
}
|
||||
|
||||
private void WhenICreate()
|
||||
{
|
||||
_result = _creator.Create(_fileReRoute, _fileGlobalConfig, _enabled);
|
||||
}
|
||||
|
||||
private void ThenTheFollowingIsReturned(RateLimitOptions expected)
|
||||
{
|
||||
_result.ClientIdHeader.ShouldBe(expected.ClientIdHeader);
|
||||
_result.ClientWhitelist.ShouldBe(expected.ClientWhitelist);
|
||||
_result.DisableRateLimitHeaders.ShouldBe(expected.DisableRateLimitHeaders);
|
||||
_result.EnableRateLimiting.ShouldBe(expected.EnableRateLimiting);
|
||||
_result.HttpStatusCode.ShouldBe(expected.HttpStatusCode);
|
||||
_result.QuotaExceededMessage.ShouldBe(expected.QuotaExceededMessage);
|
||||
_result.RateLimitCounterPrefix.ShouldBe(expected.RateLimitCounterPrefix);
|
||||
_result.RateLimitRule.Limit.ShouldBe(expected.RateLimitRule.Limit);
|
||||
_result.RateLimitRule.Period.ShouldBe(expected.RateLimitRule.Period);
|
||||
TimeSpan.FromSeconds(_result.RateLimitRule.PeriodTimespan).Ticks.ShouldBe(TimeSpan.FromSeconds(expected.RateLimitRule.PeriodTimespan).Ticks);
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Ocelot.Configuration;
|
||||
using Ocelot.Configuration.Builder;
|
||||
using Ocelot.Configuration.Creator;
|
||||
using Ocelot.Configuration.File;
|
||||
using Shouldly;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
|
||||
namespace Ocelot.UnitTests.Configuration
|
||||
{
|
||||
public class RateLimitOptionsCreatorTests
|
||||
{
|
||||
private FileReRoute _fileReRoute;
|
||||
private FileGlobalConfiguration _fileGlobalConfig;
|
||||
private bool _enabled;
|
||||
private RateLimitOptionsCreator _creator;
|
||||
private RateLimitOptions _result;
|
||||
|
||||
public RateLimitOptionsCreatorTests()
|
||||
{
|
||||
_creator = new RateLimitOptionsCreator();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_create_rate_limit_options()
|
||||
{
|
||||
var fileReRoute = new FileReRoute
|
||||
{
|
||||
RateLimitOptions = new FileRateLimitRule
|
||||
{
|
||||
ClientWhitelist = new List<string>(),
|
||||
Period = "Period",
|
||||
Limit = 1,
|
||||
PeriodTimespan = 1,
|
||||
EnableRateLimiting = true
|
||||
}
|
||||
};
|
||||
var fileGlobalConfig = new FileGlobalConfiguration
|
||||
{
|
||||
RateLimitOptions = new FileRateLimitOptions
|
||||
{
|
||||
ClientIdHeader = "ClientIdHeader",
|
||||
DisableRateLimitHeaders = true,
|
||||
QuotaExceededMessage = "QuotaExceededMessage",
|
||||
RateLimitCounterPrefix = "RateLimitCounterPrefix",
|
||||
HttpStatusCode = 200
|
||||
}
|
||||
};
|
||||
var expected = new RateLimitOptionsBuilder()
|
||||
.WithClientIdHeader("ClientIdHeader")
|
||||
.WithClientWhiteList(fileReRoute.RateLimitOptions.ClientWhitelist)
|
||||
.WithDisableRateLimitHeaders(true)
|
||||
.WithEnableRateLimiting(true)
|
||||
.WithHttpStatusCode(200)
|
||||
.WithQuotaExceededMessage("QuotaExceededMessage")
|
||||
.WithRateLimitCounterPrefix("RateLimitCounterPrefix")
|
||||
.WithRateLimitRule(new RateLimitRule(fileReRoute.RateLimitOptions.Period,
|
||||
fileReRoute.RateLimitOptions.PeriodTimespan,
|
||||
fileReRoute.RateLimitOptions.Limit))
|
||||
.Build();
|
||||
|
||||
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
|
||||
.And(x => x.GivenTheFollowingFileGlobalConfig(fileGlobalConfig))
|
||||
.And(x => x.GivenRateLimitingIsEnabled())
|
||||
.When(x => x.WhenICreate())
|
||||
.Then(x => x.ThenTheFollowingIsReturned(expected))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void GivenTheFollowingFileReRoute(FileReRoute fileReRoute)
|
||||
{
|
||||
_fileReRoute = fileReRoute;
|
||||
}
|
||||
|
||||
private void GivenTheFollowingFileGlobalConfig(FileGlobalConfiguration fileGlobalConfig)
|
||||
{
|
||||
_fileGlobalConfig = fileGlobalConfig;
|
||||
}
|
||||
|
||||
private void GivenRateLimitingIsEnabled()
|
||||
{
|
||||
_enabled = true;
|
||||
}
|
||||
|
||||
private void WhenICreate()
|
||||
{
|
||||
_result = _creator.Create(_fileReRoute.RateLimitOptions, _fileGlobalConfig);
|
||||
}
|
||||
|
||||
private void ThenTheFollowingIsReturned(RateLimitOptions expected)
|
||||
{
|
||||
_result.ClientIdHeader.ShouldBe(expected.ClientIdHeader);
|
||||
_result.ClientWhitelist.ShouldBe(expected.ClientWhitelist);
|
||||
_result.DisableRateLimitHeaders.ShouldBe(expected.DisableRateLimitHeaders);
|
||||
_result.EnableRateLimiting.ShouldBe(expected.EnableRateLimiting);
|
||||
_result.HttpStatusCode.ShouldBe(expected.HttpStatusCode);
|
||||
_result.QuotaExceededMessage.ShouldBe(expected.QuotaExceededMessage);
|
||||
_result.RateLimitCounterPrefix.ShouldBe(expected.RateLimitCounterPrefix);
|
||||
_result.RateLimitRule.Limit.ShouldBe(expected.RateLimitRule.Limit);
|
||||
_result.RateLimitRule.Period.ShouldBe(expected.RateLimitRule.Period);
|
||||
TimeSpan.FromSeconds(_result.RateLimitRule.PeriodTimespan).Ticks.ShouldBe(TimeSpan.FromSeconds(expected.RateLimitRule.PeriodTimespan).Ticks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,14 +8,11 @@ using Ocelot.Responses;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
using Shouldly;
|
||||
using Ocelot.Raft;
|
||||
using Rafty.Concensus;
|
||||
using Ocelot.Configuration;
|
||||
|
||||
namespace Ocelot.UnitTests.Controllers
|
||||
{
|
||||
using Ocelot.Configuration.Repository;
|
||||
using Rafty.Concensus.Node;
|
||||
|
||||
public class FileConfigurationControllerTests
|
||||
{
|
||||
@ -25,7 +22,6 @@ namespace Ocelot.UnitTests.Controllers
|
||||
private IActionResult _result;
|
||||
private FileConfiguration _fileConfiguration;
|
||||
private readonly Mock<IServiceProvider> _provider;
|
||||
private Mock<INode> _node;
|
||||
|
||||
public FileConfigurationControllerTests()
|
||||
{
|
||||
@ -70,33 +66,6 @@ namespace Ocelot.UnitTests.Controllers
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_post_file_configuration_using_raft_node()
|
||||
{
|
||||
var expected = new FileConfiguration();
|
||||
|
||||
this.Given(x => GivenTheFileConfiguration(expected))
|
||||
.And(x => GivenARaftNodeIsRegistered())
|
||||
.And(x => GivenTheNodeReturnsOK())
|
||||
.And(x => GivenTheConfigSetterReturns(new OkResponse()))
|
||||
.When(x => WhenIPostTheFileConfiguration())
|
||||
.Then(x => x.ThenTheNodeIsCalledCorrectly())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_return_error_when_cannot_set_config_using_raft_node()
|
||||
{
|
||||
var expected = new FileConfiguration();
|
||||
|
||||
this.Given(x => GivenTheFileConfiguration(expected))
|
||||
.And(x => GivenARaftNodeIsRegistered())
|
||||
.And(x => GivenTheNodeReturnsError())
|
||||
.When(x => WhenIPostTheFileConfiguration())
|
||||
.Then(x => ThenTheResponseIs<BadRequestObjectResult>())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_return_error_when_cannot_set_config()
|
||||
{
|
||||
@ -110,33 +79,6 @@ namespace Ocelot.UnitTests.Controllers
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void ThenTheNodeIsCalledCorrectly()
|
||||
{
|
||||
_node.Verify(x => x.Accept(It.IsAny<UpdateFileConfiguration>()), Times.Once);
|
||||
}
|
||||
|
||||
private void GivenARaftNodeIsRegistered()
|
||||
{
|
||||
_node = new Mock<INode>();
|
||||
_provider
|
||||
.Setup(x => x.GetService(typeof(INode)))
|
||||
.Returns(_node.Object);
|
||||
}
|
||||
|
||||
private void GivenTheNodeReturnsOK()
|
||||
{
|
||||
_node
|
||||
.Setup(x => x.Accept(It.IsAny<UpdateFileConfiguration>()))
|
||||
.ReturnsAsync(new Rafty.Infrastructure.OkResponse<UpdateFileConfiguration>(new UpdateFileConfiguration(new FileConfiguration())));
|
||||
}
|
||||
|
||||
private void GivenTheNodeReturnsError()
|
||||
{
|
||||
_node
|
||||
.Setup(x => x.Accept(It.IsAny<UpdateFileConfiguration>()))
|
||||
.ReturnsAsync(new Rafty.Infrastructure.ErrorResponse<UpdateFileConfiguration>("error", new UpdateFileConfiguration(new FileConfiguration())));
|
||||
}
|
||||
|
||||
private void GivenTheConfigSetterReturns(Response response)
|
||||
{
|
||||
_setter
|
||||
|
@ -46,7 +46,7 @@
|
||||
[Fact]
|
||||
public void should_merge_files()
|
||||
{
|
||||
this.Given(_ => GivenMultipleConfigurationFiles(false))
|
||||
this.Given(_ => GivenMultipleConfigurationFiles("", false))
|
||||
.When(_ => WhenIAddOcelotConfiguration(false))
|
||||
.Then(_ => ThenTheConfigsAreMerged())
|
||||
.BDDfy();
|
||||
@ -55,15 +55,30 @@
|
||||
[Fact]
|
||||
public void should_merge_files_except_env()
|
||||
{
|
||||
this.Given(_ => GivenMultipleConfigurationFiles(true))
|
||||
this.Given(_ => GivenMultipleConfigurationFiles("", true))
|
||||
.When(_ => WhenIAddOcelotConfiguration(true))
|
||||
.Then(_ => ThenTheConfigsAreMerged())
|
||||
.And(_ => NotContainsEnvSpecificConfig())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void GivenMultipleConfigurationFiles(bool addEnvSpecificConfig)
|
||||
[Fact]
|
||||
public void should_merge_files_in_specific_folder()
|
||||
{
|
||||
string configFolder = "ConfigFiles";
|
||||
this.Given(_ => GivenMultipleConfigurationFiles(configFolder, false))
|
||||
.When(_ => WhenIAddOcelotConfigurationWithSpecificFolder(configFolder))
|
||||
.Then(_ => ThenTheConfigsAreMerged())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void GivenMultipleConfigurationFiles(string folder, bool addEnvSpecificConfig)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(folder))
|
||||
{
|
||||
Directory.CreateDirectory(folder);
|
||||
}
|
||||
|
||||
_globalConfig = new FileConfiguration
|
||||
{
|
||||
GlobalConfiguration = new FileGlobalConfiguration
|
||||
@ -209,14 +224,20 @@
|
||||
}
|
||||
};
|
||||
|
||||
File.WriteAllText("ocelot.global.json", JsonConvert.SerializeObject(_globalConfig));
|
||||
File.WriteAllText("ocelot.reRoutesA.json", JsonConvert.SerializeObject(_reRouteA));
|
||||
File.WriteAllText("ocelot.reRoutesB.json", JsonConvert.SerializeObject(_reRouteB));
|
||||
File.WriteAllText("ocelot.aggregates.json", JsonConvert.SerializeObject(_aggregate));
|
||||
string globalFilename = Path.Combine(folder, "ocelot.global.json");
|
||||
string reroutesAFilename = Path.Combine(folder, "ocelot.reRoutesA.json");
|
||||
string reroutesBFilename = Path.Combine(folder, "ocelot.reRoutesB.json");
|
||||
string aggregatesFilename = Path.Combine(folder, "ocelot.aggregates.json");
|
||||
|
||||
File.WriteAllText(globalFilename, JsonConvert.SerializeObject(_globalConfig));
|
||||
File.WriteAllText(reroutesAFilename, JsonConvert.SerializeObject(_reRouteA));
|
||||
File.WriteAllText(reroutesBFilename, JsonConvert.SerializeObject(_reRouteB));
|
||||
File.WriteAllText(aggregatesFilename, JsonConvert.SerializeObject(_aggregate));
|
||||
|
||||
if (addEnvSpecificConfig)
|
||||
{
|
||||
File.WriteAllText("ocelot.Env.json", JsonConvert.SerializeObject(_envSpecific));
|
||||
string envSpecificFilename = Path.Combine(folder, "ocelot.Env.json");
|
||||
File.WriteAllText(envSpecificFilename, JsonConvert.SerializeObject(_envSpecific));
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,6 +253,13 @@
|
||||
_configRoot = builder.Build();
|
||||
}
|
||||
|
||||
private void WhenIAddOcelotConfigurationWithSpecificFolder(string folder)
|
||||
{
|
||||
IConfigurationBuilder builder = new ConfigurationBuilder();
|
||||
builder.AddOcelot(folder);
|
||||
_configRoot = builder.Build();
|
||||
}
|
||||
|
||||
private void ThenTheConfigsAreMerged()
|
||||
{
|
||||
var fc = (FileConfiguration)_configRoot.Get(typeof(FileConfiguration));
|
||||
|
@ -1,28 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using CacheManager.Core;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Hosting.Internal;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Ocelot.Cache;
|
||||
using Ocelot.Configuration;
|
||||
using Ocelot.Configuration.File;
|
||||
using Ocelot.Configuration.Setter;
|
||||
using Ocelot.DependencyInjection;
|
||||
using Ocelot.Requester;
|
||||
using Ocelot.UnitTests.Requester;
|
||||
using Shouldly;
|
||||
using IdentityServer4.AccessTokenValidation;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
using static Ocelot.UnitTests.Middleware.UserDefinedResponseAggregatorTests;
|
||||
using Ocelot.Middleware.Multiplexer;
|
||||
|
||||
namespace Ocelot.UnitTests.DependencyInjection
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Hosting.Internal;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Ocelot.Configuration.Setter;
|
||||
using Ocelot.DependencyInjection;
|
||||
using Ocelot.Requester;
|
||||
using Ocelot.UnitTests.Requester;
|
||||
using Shouldly;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
using static Ocelot.UnitTests.Middleware.UserDefinedResponseAggregatorTests;
|
||||
using Ocelot.Middleware.Multiplexer;
|
||||
|
||||
public class OcelotBuilderTests
|
||||
{
|
||||
private readonly IServiceCollection _services;
|
||||
@ -79,57 +74,6 @@ namespace Ocelot.UnitTests.DependencyInjection
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_set_up_cache_manager()
|
||||
{
|
||||
this.Given(x => WhenISetUpOcelotServices())
|
||||
.When(x => WhenISetUpCacheManager())
|
||||
.Then(x => ThenAnExceptionIsntThrown())
|
||||
.And(x => OnlyOneVersionOfEachCacheIsRegistered())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_set_up_consul()
|
||||
{
|
||||
this.Given(x => WhenISetUpOcelotServices())
|
||||
.When(x => WhenISetUpConsul())
|
||||
.Then(x => ThenAnExceptionIsntThrown())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_set_up_rafty()
|
||||
{
|
||||
this.Given(x => WhenISetUpOcelotServices())
|
||||
.When(x => WhenISetUpRafty())
|
||||
.Then(x => ThenAnExceptionIsntThrown())
|
||||
.Then(x => ThenTheCorrectAdminPathIsRegitered())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_set_up_administration_with_identity_server_options()
|
||||
{
|
||||
Action<IdentityServerAuthenticationOptions> options = o => {};
|
||||
|
||||
this.Given(x => WhenISetUpOcelotServices())
|
||||
.When(x => WhenISetUpAdministration(options))
|
||||
.Then(x => ThenAnExceptionIsntThrown())
|
||||
.Then(x => ThenTheCorrectAdminPathIsRegitered())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_set_up_administration()
|
||||
{
|
||||
this.Given(x => WhenISetUpOcelotServices())
|
||||
.When(x => WhenISetUpAdministration())
|
||||
.Then(x => ThenAnExceptionIsntThrown())
|
||||
.Then(x => ThenTheCorrectAdminPathIsRegitered())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_use_logger_factory()
|
||||
{
|
||||
@ -140,15 +84,6 @@ namespace Ocelot.UnitTests.DependencyInjection
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_set_up_tracing()
|
||||
{
|
||||
this.Given(x => WhenISetUpOcelotServices())
|
||||
.When(x => WhenISetUpOpentracing())
|
||||
.When(x => WhenIAccessOcelotHttpTracingHandler())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_set_up_without_passing_in_config()
|
||||
{
|
||||
@ -191,15 +126,6 @@ namespace Ocelot.UnitTests.DependencyInjection
|
||||
_ocelotBuilder.AddTransientDefinedAggregator<T>();
|
||||
}
|
||||
|
||||
private void ThenTheSpecificHandlersAreSingleton()
|
||||
{
|
||||
var handlers = _serviceProvider.GetServices<DelegatingHandler>().ToList();
|
||||
var first = handlers[0];
|
||||
handlers = _serviceProvider.GetServices<DelegatingHandler>().ToList();
|
||||
var second = handlers[0];
|
||||
first.ShouldBe(second);
|
||||
}
|
||||
|
||||
private void ThenTheSpecificHandlersAreTransient()
|
||||
{
|
||||
var handlers = _serviceProvider.GetServices<DelegatingHandler>().ToList();
|
||||
@ -218,16 +144,6 @@ namespace Ocelot.UnitTests.DependencyInjection
|
||||
first.ShouldNotBe(second);
|
||||
}
|
||||
|
||||
private void WhenISetUpAdministration()
|
||||
{
|
||||
_ocelotBuilder.AddAdministration("/administration", "secret");
|
||||
}
|
||||
|
||||
private void WhenISetUpAdministration(Action<IdentityServerAuthenticationOptions> options)
|
||||
{
|
||||
_ocelotBuilder.AddAdministration("/administration", options);
|
||||
}
|
||||
|
||||
private void AddTransientGlobalDelegatingHandler<T>()
|
||||
where T : DelegatingHandler
|
||||
{
|
||||
@ -240,13 +156,6 @@ namespace Ocelot.UnitTests.DependencyInjection
|
||||
_ocelotBuilder.AddDelegatingHandler<T>();
|
||||
}
|
||||
|
||||
private void ThenTheCorrectAdminPathIsRegitered()
|
||||
{
|
||||
_serviceProvider = _services.BuildServiceProvider();
|
||||
var path = _serviceProvider.GetService<IAdministrationPath>();
|
||||
path.Path.ShouldBe("/administration");
|
||||
}
|
||||
|
||||
private void ThenTheProviderIsRegisteredAndReturnsHandlers<TOne, TWo>()
|
||||
{
|
||||
_serviceProvider = _services.BuildServiceProvider();
|
||||
@ -289,60 +198,6 @@ namespace Ocelot.UnitTests.DependencyInjection
|
||||
first.ShouldBe(second);
|
||||
}
|
||||
|
||||
private void OnlyOneVersionOfEachCacheIsRegistered()
|
||||
{
|
||||
var outputCache = _services.Single(x => x.ServiceType == typeof(IOcelotCache<CachedResponse>));
|
||||
var outputCacheManager = _services.Single(x => x.ServiceType == typeof(ICacheManager<CachedResponse>));
|
||||
var instance = (ICacheManager<CachedResponse>)outputCacheManager.ImplementationInstance;
|
||||
var ocelotConfigCache = _services.Single(x => x.ServiceType == typeof(IOcelotCache<IInternalConfiguration>));
|
||||
var ocelotConfigCacheManager = _services.Single(x => x.ServiceType == typeof(ICacheManager<IInternalConfiguration>));
|
||||
var fileConfigCache = _services.Single(x => x.ServiceType == typeof(IOcelotCache<FileConfiguration>));
|
||||
var fileConfigCacheManager = _services.Single(x => x.ServiceType == typeof(ICacheManager<FileConfiguration>));
|
||||
|
||||
instance.Configuration.MaxRetries.ShouldBe(_maxRetries);
|
||||
outputCache.ShouldNotBeNull();
|
||||
ocelotConfigCache.ShouldNotBeNull();
|
||||
ocelotConfigCacheManager.ShouldNotBeNull();
|
||||
fileConfigCache.ShouldNotBeNull();
|
||||
fileConfigCacheManager.ShouldNotBeNull();
|
||||
}
|
||||
|
||||
private void WhenISetUpConsul()
|
||||
{
|
||||
try
|
||||
{
|
||||
_ocelotBuilder.AddStoreOcelotConfigurationInConsul();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_ex = e;
|
||||
}
|
||||
}
|
||||
|
||||
private void WhenISetUpRafty()
|
||||
{
|
||||
try
|
||||
{
|
||||
_ocelotBuilder.AddAdministration("/administration", "secret").AddRafty();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_ex = e;
|
||||
}
|
||||
}
|
||||
|
||||
private void AddGlobalDelegatingHandler<T>()
|
||||
where T : DelegatingHandler
|
||||
{
|
||||
_ocelotBuilder.AddDelegatingHandler<T>(true);
|
||||
}
|
||||
|
||||
private void AddSpecificDelegatingHandler<T>()
|
||||
where T : DelegatingHandler
|
||||
{
|
||||
_ocelotBuilder.AddDelegatingHandler<T>();
|
||||
}
|
||||
|
||||
private void ThenAnOcelotBuilderIsReturned()
|
||||
{
|
||||
_ocelotBuilder.ShouldBeOfType<OcelotBuilder>();
|
||||
@ -372,39 +227,6 @@ namespace Ocelot.UnitTests.DependencyInjection
|
||||
}
|
||||
}
|
||||
|
||||
private void WhenISetUpCacheManager()
|
||||
{
|
||||
try
|
||||
{
|
||||
_ocelotBuilder.AddCacheManager(x => {
|
||||
x.WithMaxRetries(_maxRetries);
|
||||
x.WithDictionaryHandle();
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_ex = e;
|
||||
}
|
||||
}
|
||||
|
||||
private void WhenISetUpOpentracing()
|
||||
{
|
||||
try
|
||||
{
|
||||
_ocelotBuilder.AddOpenTracing(
|
||||
option =>
|
||||
{
|
||||
option.CollectorUrl = "http://localhost:9618";
|
||||
option.Service = "Ocelot.ManualTest";
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_ex = e;
|
||||
}
|
||||
}
|
||||
|
||||
private void WhenIAccessLoggerFactory()
|
||||
{
|
||||
try
|
||||
@ -419,19 +241,6 @@ namespace Ocelot.UnitTests.DependencyInjection
|
||||
}
|
||||
}
|
||||
|
||||
private void WhenIAccessOcelotHttpTracingHandler()
|
||||
{
|
||||
try
|
||||
{
|
||||
var tracingHandler = _serviceProvider.GetService<OcelotHttpTracingHandler>();
|
||||
tracingHandler.ShouldNotBeNull();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_ex = e;
|
||||
}
|
||||
}
|
||||
|
||||
private void WhenIValidateScopes()
|
||||
{
|
||||
try
|
||||
|
@ -1,9 +1,3 @@
|
||||
using Ocelot.DownstreamRouteFinder.Finder;
|
||||
using Xunit;
|
||||
using Shouldly;
|
||||
using Ocelot.Configuration;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace Ocelot.UnitTests.DownstreamRouteFinder
|
||||
{
|
||||
using System;
|
||||
@ -14,6 +8,12 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
|
||||
using Ocelot.LoadBalancer.LoadBalancers;
|
||||
using Responses;
|
||||
using TestStack.BDDfy;
|
||||
using Ocelot.DownstreamRouteFinder.Finder;
|
||||
using Xunit;
|
||||
using Shouldly;
|
||||
using Ocelot.Configuration;
|
||||
using System.Net.Http;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class DownstreamRouteCreatorTests
|
||||
{
|
||||
@ -53,6 +53,34 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_create_downstream_route_with_rate_limit_options()
|
||||
{
|
||||
var rateLimitOptions = new RateLimitOptionsBuilder()
|
||||
.WithEnableRateLimiting(true)
|
||||
.WithClientIdHeader("test")
|
||||
.Build();
|
||||
|
||||
var downstreamReRoute = new DownstreamReRouteBuilder()
|
||||
.WithServiceName("auth")
|
||||
.WithRateLimitOptions(rateLimitOptions)
|
||||
.Build();
|
||||
|
||||
var reRoute = new ReRouteBuilder()
|
||||
.WithDownstreamReRoute(downstreamReRoute)
|
||||
.Build();
|
||||
|
||||
var reRoutes = new List<ReRoute> { reRoute };
|
||||
|
||||
var configuration = new InternalConfiguration(reRoutes, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions);
|
||||
|
||||
this.Given(_ => GivenTheConfiguration(configuration))
|
||||
.When(_ => WhenICreate())
|
||||
.Then(_ => ThenTheDownstreamRouteIsCreated())
|
||||
.And(_ => WithRateLimitOptions(rateLimitOptions))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_cache_downstream_route()
|
||||
{
|
||||
@ -174,6 +202,13 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
|
||||
.Returns(options);
|
||||
}
|
||||
|
||||
private void WithRateLimitOptions(RateLimitOptions expected)
|
||||
{
|
||||
_result.Data.ReRoute.DownstreamReRoute[0].EnableEndpointEndpointRateLimiting.ShouldBeTrue();
|
||||
_result.Data.ReRoute.DownstreamReRoute[0].RateLimitOptions.EnableRateLimiting.ShouldBe(expected.EnableRateLimiting);
|
||||
_result.Data.ReRoute.DownstreamReRoute[0].RateLimitOptions.ClientIdHeader.ShouldBe(expected.ClientIdHeader);
|
||||
}
|
||||
|
||||
private void ThenTheDownstreamRouteIsCreated()
|
||||
{
|
||||
_result.Data.ReRoute.DownstreamReRoute[0].DownstreamPathTemplate.Value.ShouldBe("/test");
|
||||
|
@ -53,6 +53,21 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_return_downstream_route_finder_when_not_dynamic_re_route_and_service_discovery_on()
|
||||
{
|
||||
var spConfig = new ServiceProviderConfigurationBuilder().WithHost("test").WithPort(50).WithType("test").Build();
|
||||
var reRoutes = new List<ReRoute>
|
||||
{
|
||||
new ReRouteBuilder().WithUpstreamPathTemplate("woot").Build()
|
||||
};
|
||||
|
||||
this.Given(_ => GivenTheReRoutes(reRoutes, spConfig))
|
||||
.When(_ => WhenIGet())
|
||||
.Then(_ => ThenTheResultShouldBe<Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteFinder>())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_return_downstream_route_finder_as_no_service_discovery_given_no_host()
|
||||
{
|
||||
@ -101,6 +116,21 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_return_downstream_route_creator_with_dynamic_re_route()
|
||||
{
|
||||
var spConfig = new ServiceProviderConfigurationBuilder().WithHost("test").WithPort(50).WithType("test").Build();
|
||||
var reRoutes = new List<ReRoute>
|
||||
{
|
||||
new ReRouteBuilder().Build()
|
||||
};
|
||||
|
||||
this.Given(_ => GivenTheReRoutes(reRoutes, spConfig))
|
||||
.When(_ => WhenIGet())
|
||||
.Then(_ => ThenTheResultShouldBe<Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteCreator>())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void ThenTheResultShouldBe<T>()
|
||||
{
|
||||
_result.ShouldBeOfType<T>();
|
||||
|
@ -289,6 +289,39 @@
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void issue_473_should_not_remove_additional_query_string()
|
||||
{
|
||||
var downstreamReRoute = new DownstreamReRouteBuilder()
|
||||
.WithDownstreamPathTemplate("/Authorized/{action}?server={server}")
|
||||
.WithUpstreamHttpMethod(new List<string> { "Post", "Get" })
|
||||
.WithDownstreamScheme("http")
|
||||
.WithUpstreamPathTemplate("/uc/Authorized/{server}/{action}")
|
||||
.Build();
|
||||
|
||||
var config = new ServiceProviderConfigurationBuilder()
|
||||
.Build();
|
||||
|
||||
this.Given(x => x.GivenTheDownStreamRouteIs(
|
||||
new DownstreamRoute(
|
||||
new List<PlaceholderNameAndValue>
|
||||
{
|
||||
new PlaceholderNameAndValue("{action}", "1"),
|
||||
new PlaceholderNameAndValue("{server}", "2")
|
||||
},
|
||||
new ReRouteBuilder()
|
||||
.WithDownstreamReRoute(downstreamReRoute)
|
||||
.WithUpstreamHttpMethod(new List<string> { "Post", "Get" })
|
||||
.Build())))
|
||||
.And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:5000/uc/Authorized/2/1/refresh?refreshToken=2288356cfb1338fdc5ff4ca558ec785118dfe1ff2864340937da8226863ff66d"))
|
||||
.And(x => GivenTheServiceProviderConfigIs(config))
|
||||
.And(x => x.GivenTheUrlReplacerWillReturn("/Authorized/1?server=2"))
|
||||
.When(x => x.WhenICallTheMiddleware())
|
||||
.Then(x => x.ThenTheDownstreamRequestUriIs("http://localhost:5000/Authorized/1?refreshToken=2288356cfb1338fdc5ff4ca558ec785118dfe1ff2864340937da8226863ff66d&server=2"))
|
||||
.And(x => ThenTheQueryStringIs("?refreshToken=2288356cfb1338fdc5ff4ca558ec785118dfe1ff2864340937da8226863ff66d&server=2"))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void GivenTheServiceProviderConfigIs(ServiceProviderConfiguration config)
|
||||
{
|
||||
var configuration = new InternalConfiguration(null, null, config, null, null, null, null, null);
|
||||
|
@ -1,197 +1,197 @@
|
||||
namespace Ocelot.UnitTests.Errors
|
||||
{
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Ocelot.Errors.Middleware;
|
||||
using Ocelot.Logging;
|
||||
using Shouldly;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Moq;
|
||||
using Ocelot.Configuration;
|
||||
using Ocelot.Errors;
|
||||
using Ocelot.Infrastructure.RequestData;
|
||||
using Ocelot.Middleware;
|
||||
using Ocelot.Configuration.Repository;
|
||||
|
||||
public class ExceptionHandlerMiddlewareTests
|
||||
{
|
||||
bool _shouldThrowAnException;
|
||||
private readonly Mock<IInternalConfigurationRepository> _configRepo;
|
||||
private readonly Mock<IRequestScopedDataRepository> _repo;
|
||||
private Mock<IOcelotLoggerFactory> _loggerFactory;
|
||||
private Mock<IOcelotLogger> _logger;
|
||||
private readonly ExceptionHandlerMiddleware _middleware;
|
||||
private readonly DownstreamContext _downstreamContext;
|
||||
private OcelotRequestDelegate _next;
|
||||
|
||||
public ExceptionHandlerMiddlewareTests()
|
||||
{
|
||||
_configRepo = new Mock<IInternalConfigurationRepository>();
|
||||
_repo = new Mock<IRequestScopedDataRepository>();
|
||||
_downstreamContext = new DownstreamContext(new DefaultHttpContext());
|
||||
_loggerFactory = new Mock<IOcelotLoggerFactory>();
|
||||
_logger = new Mock<IOcelotLogger>();
|
||||
_loggerFactory.Setup(x => x.CreateLogger<ExceptionHandlerMiddleware>()).Returns(_logger.Object);
|
||||
_next = async context => {
|
||||
await Task.CompletedTask;
|
||||
|
||||
if (_shouldThrowAnException)
|
||||
{
|
||||
throw new Exception("BOOM");
|
||||
}
|
||||
|
||||
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.OK;
|
||||
};
|
||||
_middleware = new ExceptionHandlerMiddleware(_next, _loggerFactory.Object, _configRepo.Object, _repo.Object);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NoDownstreamException()
|
||||
{
|
||||
var config = new InternalConfiguration(null, null, null, null, null, null, null, null);
|
||||
|
||||
this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream())
|
||||
.And(_ => GivenTheConfigurationIs(config))
|
||||
.When(_ => WhenICallTheMiddleware())
|
||||
.Then(_ => ThenTheResponseIsOk())
|
||||
.And(_ => TheAspDotnetRequestIdIsSet())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DownstreamException()
|
||||
{
|
||||
var config = new InternalConfiguration(null, null, null, null, null, null, null, null);
|
||||
|
||||
this.Given(_ => GivenAnExceptionWillBeThrownDownstream())
|
||||
.And(_ => GivenTheConfigurationIs(config))
|
||||
.When(_ => WhenICallTheMiddleware())
|
||||
.Then(_ => ThenTheResponseIsError())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldSetRequestId()
|
||||
{
|
||||
var config = new InternalConfiguration(null, null, null, "requestidkey", null, null, null, null);
|
||||
|
||||
this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream())
|
||||
.And(_ => GivenTheConfigurationIs(config))
|
||||
.When(_ => WhenICallTheMiddlewareWithTheRequestIdKey("requestidkey", "1234"))
|
||||
.Then(_ => ThenTheResponseIsOk())
|
||||
.And(_ => TheRequestIdIsSet("RequestId", "1234"))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldSetAspDotNetRequestId()
|
||||
{
|
||||
var config = new InternalConfiguration(null, null, null, null, null, null, null, null);
|
||||
|
||||
this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream())
|
||||
.And(_ => GivenTheConfigurationIs(config))
|
||||
.When(_ => WhenICallTheMiddlewareWithTheRequestIdKey("requestidkey", "1234"))
|
||||
.Then(_ => ThenTheResponseIsOk())
|
||||
.And(_ => TheAspDotnetRequestIdIsSet())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_throw_exception_if_config_provider_returns_error()
|
||||
{
|
||||
this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream())
|
||||
.And(_ => GivenTheConfigReturnsError())
|
||||
.When(_ => WhenICallTheMiddlewareWithTheRequestIdKey("requestidkey", "1234"))
|
||||
.Then(_ => ThenAnExceptionIsThrown())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_throw_exception_if_config_provider_throws()
|
||||
{
|
||||
this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream())
|
||||
.And(_ => GivenTheConfigThrows())
|
||||
.When(_ => WhenICallTheMiddlewareWithTheRequestIdKey("requestidkey", "1234"))
|
||||
.Then(_ => ThenAnExceptionIsThrown())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void WhenICallTheMiddlewareWithTheRequestIdKey(string key, string value)
|
||||
{
|
||||
_downstreamContext.HttpContext.Request.Headers.Add(key, value);
|
||||
_middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
private void WhenICallTheMiddleware()
|
||||
{
|
||||
_middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
private void GivenTheConfigThrows()
|
||||
{
|
||||
var ex = new Exception("outer", new Exception("inner"));
|
||||
_configRepo
|
||||
.Setup(x => x.Get()).Throws(ex);
|
||||
}
|
||||
|
||||
private void ThenAnExceptionIsThrown()
|
||||
{
|
||||
_downstreamContext.HttpContext.Response.StatusCode.ShouldBe(500);
|
||||
}
|
||||
|
||||
private void GivenTheConfigReturnsError()
|
||||
{
|
||||
var response = new Responses.ErrorResponse<IInternalConfiguration>(new FakeError());
|
||||
_configRepo
|
||||
.Setup(x => x.Get()).Returns(response);
|
||||
}
|
||||
|
||||
private void TheRequestIdIsSet(string key, string value)
|
||||
{
|
||||
_repo.Verify(x => x.Add(key, value), Times.Once);
|
||||
}
|
||||
|
||||
private void GivenTheConfigurationIs(IInternalConfiguration config)
|
||||
{
|
||||
var response = new Responses.OkResponse<IInternalConfiguration>(config);
|
||||
_configRepo
|
||||
.Setup(x => x.Get()).Returns(response);
|
||||
}
|
||||
|
||||
private void GivenAnExceptionWillNotBeThrownDownstream()
|
||||
{
|
||||
_shouldThrowAnException = false;
|
||||
}
|
||||
|
||||
private void GivenAnExceptionWillBeThrownDownstream()
|
||||
{
|
||||
_shouldThrowAnException = true;
|
||||
}
|
||||
|
||||
private void ThenTheResponseIsOk()
|
||||
{
|
||||
_downstreamContext.HttpContext.Response.StatusCode.ShouldBe(200);
|
||||
}
|
||||
|
||||
private void ThenTheResponseIsError()
|
||||
{
|
||||
_downstreamContext.HttpContext.Response.StatusCode.ShouldBe(500);
|
||||
}
|
||||
|
||||
private void TheAspDotnetRequestIdIsSet()
|
||||
{
|
||||
_repo.Verify(x => x.Add(It.IsAny<string>(), It.IsAny<string>()), Times.Once);
|
||||
}
|
||||
|
||||
class FakeError : Error
|
||||
{
|
||||
internal FakeError()
|
||||
: base("meh", OcelotErrorCode.CannotAddDataError)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace Ocelot.UnitTests.Errors
|
||||
{
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Ocelot.Errors.Middleware;
|
||||
using Ocelot.Logging;
|
||||
using Shouldly;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Moq;
|
||||
using Ocelot.Configuration;
|
||||
using Ocelot.Errors;
|
||||
using Ocelot.Infrastructure.RequestData;
|
||||
using Ocelot.Middleware;
|
||||
using Ocelot.Configuration.Repository;
|
||||
|
||||
public class ExceptionHandlerMiddlewareTests
|
||||
{
|
||||
bool _shouldThrowAnException;
|
||||
private readonly Mock<IInternalConfigurationRepository> _configRepo;
|
||||
private readonly Mock<IRequestScopedDataRepository> _repo;
|
||||
private Mock<IOcelotLoggerFactory> _loggerFactory;
|
||||
private Mock<IOcelotLogger> _logger;
|
||||
private readonly ExceptionHandlerMiddleware _middleware;
|
||||
private readonly DownstreamContext _downstreamContext;
|
||||
private OcelotRequestDelegate _next;
|
||||
|
||||
public ExceptionHandlerMiddlewareTests()
|
||||
{
|
||||
_configRepo = new Mock<IInternalConfigurationRepository>();
|
||||
_repo = new Mock<IRequestScopedDataRepository>();
|
||||
_downstreamContext = new DownstreamContext(new DefaultHttpContext());
|
||||
_loggerFactory = new Mock<IOcelotLoggerFactory>();
|
||||
_logger = new Mock<IOcelotLogger>();
|
||||
_loggerFactory.Setup(x => x.CreateLogger<ExceptionHandlerMiddleware>()).Returns(_logger.Object);
|
||||
_next = async context => {
|
||||
await Task.CompletedTask;
|
||||
|
||||
if (_shouldThrowAnException)
|
||||
{
|
||||
throw new Exception("BOOM");
|
||||
}
|
||||
|
||||
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.OK;
|
||||
};
|
||||
_middleware = new ExceptionHandlerMiddleware(_next, _loggerFactory.Object, _configRepo.Object, _repo.Object);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NoDownstreamException()
|
||||
{
|
||||
var config = new InternalConfiguration(null, null, null, null, null, null, null, null);
|
||||
|
||||
this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream())
|
||||
.And(_ => GivenTheConfigurationIs(config))
|
||||
.When(_ => WhenICallTheMiddleware())
|
||||
.Then(_ => ThenTheResponseIsOk())
|
||||
.And(_ => TheAspDotnetRequestIdIsSet())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DownstreamException()
|
||||
{
|
||||
var config = new InternalConfiguration(null, null, null, null, null, null, null, null);
|
||||
|
||||
this.Given(_ => GivenAnExceptionWillBeThrownDownstream())
|
||||
.And(_ => GivenTheConfigurationIs(config))
|
||||
.When(_ => WhenICallTheMiddleware())
|
||||
.Then(_ => ThenTheResponseIsError())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldSetRequestId()
|
||||
{
|
||||
var config = new InternalConfiguration(null, null, null, "requestidkey", null, null, null, null);
|
||||
|
||||
this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream())
|
||||
.And(_ => GivenTheConfigurationIs(config))
|
||||
.When(_ => WhenICallTheMiddlewareWithTheRequestIdKey("requestidkey", "1234"))
|
||||
.Then(_ => ThenTheResponseIsOk())
|
||||
.And(_ => TheRequestIdIsSet("RequestId", "1234"))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldSetAspDotNetRequestId()
|
||||
{
|
||||
var config = new InternalConfiguration(null, null, null, null, null, null, null, null);
|
||||
|
||||
this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream())
|
||||
.And(_ => GivenTheConfigurationIs(config))
|
||||
.When(_ => WhenICallTheMiddlewareWithTheRequestIdKey("requestidkey", "1234"))
|
||||
.Then(_ => ThenTheResponseIsOk())
|
||||
.And(_ => TheAspDotnetRequestIdIsSet())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_throw_exception_if_config_provider_returns_error()
|
||||
{
|
||||
this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream())
|
||||
.And(_ => GivenTheConfigReturnsError())
|
||||
.When(_ => WhenICallTheMiddlewareWithTheRequestIdKey("requestidkey", "1234"))
|
||||
.Then(_ => ThenAnExceptionIsThrown())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_throw_exception_if_config_provider_throws()
|
||||
{
|
||||
this.Given(_ => GivenAnExceptionWillNotBeThrownDownstream())
|
||||
.And(_ => GivenTheConfigThrows())
|
||||
.When(_ => WhenICallTheMiddlewareWithTheRequestIdKey("requestidkey", "1234"))
|
||||
.Then(_ => ThenAnExceptionIsThrown())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void WhenICallTheMiddlewareWithTheRequestIdKey(string key, string value)
|
||||
{
|
||||
_downstreamContext.HttpContext.Request.Headers.Add(key, value);
|
||||
_middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
private void WhenICallTheMiddleware()
|
||||
{
|
||||
_middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
private void GivenTheConfigThrows()
|
||||
{
|
||||
var ex = new Exception("outer", new Exception("inner"));
|
||||
_configRepo
|
||||
.Setup(x => x.Get()).Throws(ex);
|
||||
}
|
||||
|
||||
private void ThenAnExceptionIsThrown()
|
||||
{
|
||||
_downstreamContext.HttpContext.Response.StatusCode.ShouldBe(500);
|
||||
}
|
||||
|
||||
private void GivenTheConfigReturnsError()
|
||||
{
|
||||
var response = new Responses.ErrorResponse<IInternalConfiguration>(new FakeError());
|
||||
_configRepo
|
||||
.Setup(x => x.Get()).Returns(response);
|
||||
}
|
||||
|
||||
private void TheRequestIdIsSet(string key, string value)
|
||||
{
|
||||
_repo.Verify(x => x.Add(key, value), Times.Once);
|
||||
}
|
||||
|
||||
private void GivenTheConfigurationIs(IInternalConfiguration config)
|
||||
{
|
||||
var response = new Responses.OkResponse<IInternalConfiguration>(config);
|
||||
_configRepo
|
||||
.Setup(x => x.Get()).Returns(response);
|
||||
}
|
||||
|
||||
private void GivenAnExceptionWillNotBeThrownDownstream()
|
||||
{
|
||||
_shouldThrowAnException = false;
|
||||
}
|
||||
|
||||
private void GivenAnExceptionWillBeThrownDownstream()
|
||||
{
|
||||
_shouldThrowAnException = true;
|
||||
}
|
||||
|
||||
private void ThenTheResponseIsOk()
|
||||
{
|
||||
_downstreamContext.HttpContext.Response.StatusCode.ShouldBe(200);
|
||||
}
|
||||
|
||||
private void ThenTheResponseIsError()
|
||||
{
|
||||
_downstreamContext.HttpContext.Response.StatusCode.ShouldBe(500);
|
||||
}
|
||||
|
||||
private void TheAspDotnetRequestIdIsSet()
|
||||
{
|
||||
_repo.Verify(x => x.Add(It.IsAny<string>(), It.IsAny<string>()), Times.Once);
|
||||
}
|
||||
|
||||
class FakeError : Error
|
||||
{
|
||||
internal FakeError()
|
||||
: base("meh", OcelotErrorCode.CannotAddDataError)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ namespace Ocelot.UnitTests.Infrastructure
|
||||
called = true;
|
||||
});
|
||||
_bus.Publish(new object(), 1);
|
||||
await Task.Delay(10);
|
||||
await Task.Delay(100);
|
||||
called.ShouldBeTrue();
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ using Xunit;
|
||||
using Ocelot.Middleware;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Ocelot.UnitTests.Logging
|
||||
{
|
||||
@ -15,7 +16,8 @@ namespace Ocelot.UnitTests.Logging
|
||||
private readonly OcelotDiagnosticListener _listener;
|
||||
private Mock<IOcelotLoggerFactory> _factory;
|
||||
private readonly Mock<IOcelotLogger> _logger;
|
||||
private IServiceTracer _tracer;
|
||||
private IServiceCollection _serviceCollection;
|
||||
private IServiceProvider _serviceProvider;
|
||||
private DownstreamContext _downstreamContext;
|
||||
private string _name;
|
||||
private Exception _exception;
|
||||
@ -24,9 +26,10 @@ namespace Ocelot.UnitTests.Logging
|
||||
{
|
||||
_factory = new Mock<IOcelotLoggerFactory>();
|
||||
_logger = new Mock<IOcelotLogger>();
|
||||
_tracer = new FakeServiceTracer();
|
||||
_serviceCollection = new ServiceCollection();
|
||||
_serviceProvider = _serviceCollection.BuildServiceProvider();
|
||||
_factory.Setup(x => x.CreateLogger<OcelotDiagnosticListener>()).Returns(_logger.Object);
|
||||
_listener = new OcelotDiagnosticListener(_factory.Object, _tracer);
|
||||
_listener = new OcelotDiagnosticListener(_factory.Object, _serviceProvider);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -3,12 +3,14 @@ namespace Ocelot.UnitTests.Middleware
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Ocelot.DependencyInjection;
|
||||
using Ocelot.DownstreamRouteFinder.Middleware;
|
||||
using Ocelot.DownstreamUrlCreator.Middleware;
|
||||
using Ocelot.LoadBalancer.Middleware;
|
||||
using Ocelot.Middleware;
|
||||
using Ocelot.Middleware.Pipeline;
|
||||
using Pivotal.Discovery.Client;
|
||||
using Ocelot.Request.Middleware;
|
||||
using Ocelot.WebSockets.Middleware;
|
||||
using Shouldly;
|
||||
using Steeltoe.Common.Discovery;
|
||||
using Steeltoe.Discovery.Eureka;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
|
||||
@ -26,6 +28,15 @@ namespace Ocelot.UnitTests.Middleware
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_expand_pipeline()
|
||||
{
|
||||
this.Given(_ => GivenTheDepedenciesAreSetUp())
|
||||
.When(_ => WhenIExpandBuild())
|
||||
.Then(_ => ThenThePipelineIsBuilt())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void ThenThePipelineIsBuilt()
|
||||
{
|
||||
_handlers.ShouldNotBeNull();
|
||||
@ -36,21 +47,28 @@ namespace Ocelot.UnitTests.Middleware
|
||||
_handlers = _builder.BuildOcelotPipeline(new OcelotPipelineConfiguration());
|
||||
}
|
||||
|
||||
private void WhenIExpandBuild()
|
||||
{
|
||||
OcelotPipelineConfiguration configuration = new OcelotPipelineConfiguration();
|
||||
configuration.MapWhenOcelotPipeline.Add((app) =>
|
||||
{
|
||||
app.UseDownstreamRouteFinderMiddleware();
|
||||
app.UseDownstreamRequestInitialiser();
|
||||
app.UseLoadBalancingMiddleware();
|
||||
app.UseDownstreamUrlCreatorMiddleware();
|
||||
app.UseWebSocketsProxyMiddleware();
|
||||
|
||||
return context => context.HttpContext.WebSockets.IsWebSocketRequest;
|
||||
});
|
||||
_handlers = _builder.BuildOcelotPipeline(new OcelotPipelineConfiguration());
|
||||
}
|
||||
|
||||
private void GivenTheDepedenciesAreSetUp()
|
||||
{
|
||||
IConfigurationBuilder test = new ConfigurationBuilder();
|
||||
var root = test.Build();
|
||||
var services = new ServiceCollection();
|
||||
services.AddSingleton<IConfiguration>(root);
|
||||
services.AddDiscoveryClient(new DiscoveryOptions
|
||||
{
|
||||
ClientType = DiscoveryClientType.EUREKA,
|
||||
ClientOptions = new EurekaClientOptions()
|
||||
{
|
||||
ShouldFetchRegistry = false,
|
||||
ShouldRegisterWithEureka = false
|
||||
}
|
||||
});
|
||||
services.AddOcelot();
|
||||
var provider = services.BuildServiceProvider();
|
||||
_builder = new OcelotPipelineBuilder(provider);
|
||||
|
@ -79,6 +79,8 @@ namespace Ocelot.UnitTests.Middleware
|
||||
del.Invoke(_downstreamContext);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void ThenTheFuncIsInThePipeline()
|
||||
{
|
||||
_counter.ShouldBe(1);
|
||||
|
@ -57,7 +57,6 @@
|
||||
<PackageReference Include="TestStack.BDDfy" Version="4.3.2" />
|
||||
<PackageReference Include="xunit" Version="2.3.1" />
|
||||
<PackageReference Include="Butterfly.Client.AspNetCore" Version="0.0.8" />
|
||||
<PackageReference Include="Rafty" Version="0.4.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,45 +0,0 @@
|
||||
using Moq;
|
||||
using Ocelot.Configuration.Setter;
|
||||
using Ocelot.Raft;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
|
||||
namespace Ocelot.UnitTests.Raft
|
||||
{
|
||||
public class OcelotFiniteStateMachineTests
|
||||
{
|
||||
private UpdateFileConfiguration _command;
|
||||
private OcelotFiniteStateMachine _fsm;
|
||||
private Mock<IFileConfigurationSetter> _setter;
|
||||
|
||||
public OcelotFiniteStateMachineTests()
|
||||
{
|
||||
_setter = new Mock<IFileConfigurationSetter>();
|
||||
_fsm = new OcelotFiniteStateMachine(_setter.Object);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_handle_update_file_configuration_command()
|
||||
{
|
||||
this.Given(x => GivenACommand(new UpdateFileConfiguration(new Ocelot.Configuration.File.FileConfiguration())))
|
||||
.When(x => WhenTheCommandIsHandled())
|
||||
.Then(x => ThenTheStateIsUpdated())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void GivenACommand(UpdateFileConfiguration command)
|
||||
{
|
||||
_command = command;
|
||||
}
|
||||
|
||||
private void WhenTheCommandIsHandled()
|
||||
{
|
||||
_fsm.Handle(new Rafty.Log.LogEntry(_command, _command.GetType(), 0));
|
||||
}
|
||||
|
||||
private void ThenTheStateIsUpdated()
|
||||
{
|
||||
_setter.Verify(x => x.Set(_command.Configuration), Times.Once);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,407 +1,442 @@
|
||||
namespace Ocelot.UnitTests.Request.Mapper
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Internal;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Ocelot.Request.Mapper;
|
||||
using Ocelot.Responses;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
using Shouldly;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
public class RequestMapperTests
|
||||
{
|
||||
readonly HttpRequest _inputRequest;
|
||||
|
||||
readonly RequestMapper _requestMapper;
|
||||
|
||||
Response<HttpRequestMessage> _mappedRequest;
|
||||
|
||||
List<KeyValuePair<string, StringValues>> _inputHeaders = null;
|
||||
|
||||
public RequestMapperTests()
|
||||
{
|
||||
_inputRequest = new DefaultHttpRequest(new DefaultHttpContext());
|
||||
|
||||
_requestMapper = new RequestMapper();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("https", "my.url:123", "/abc/DEF", "?a=1&b=2", "https://my.url:123/abc/DEF?a=1&b=2")]
|
||||
[InlineData("http", "blah.com", "/d ef", "?abc=123", "http://blah.com/d%20ef?abc=123")] // note! the input is encoded when building the input request
|
||||
[InlineData("http", "myusername:mypassword@abc.co.uk", null, null, "http://myusername:mypassword@abc.co.uk/")]
|
||||
[InlineData("http", "點看.com", null, null, "http://xn--c1yn36f.com/")]
|
||||
[InlineData("http", "xn--c1yn36f.com", null, null, "http://xn--c1yn36f.com/")]
|
||||
public void Should_map_valid_request_uri(string scheme, string host, string path, string queryString, string expectedUri)
|
||||
{
|
||||
this.Given(_ => GivenTheInputRequestHasMethod("GET"))
|
||||
.And(_ => GivenTheInputRequestHasScheme(scheme))
|
||||
.And(_ => GivenTheInputRequestHasHost(host))
|
||||
.And(_ => GivenTheInputRequestHasPath(path))
|
||||
.And(_ => GivenTheInputRequestHasQueryString(queryString))
|
||||
.When(_ => WhenMapped())
|
||||
.Then(_ => ThenNoErrorIsReturned())
|
||||
.And(_ => ThenTheMappedRequestHasUri(expectedUri))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("ftp", "google.com", "/abc/DEF", "?a=1&b=2")]
|
||||
public void Should_error_on_unsupported_request_uri(string scheme, string host, string path, string queryString)
|
||||
{
|
||||
this.Given(_ => GivenTheInputRequestHasMethod("GET"))
|
||||
.And(_ => GivenTheInputRequestHasScheme(scheme))
|
||||
.And(_ => GivenTheInputRequestHasHost(host))
|
||||
.And(_ => GivenTheInputRequestHasPath(path))
|
||||
.And(_ => GivenTheInputRequestHasQueryString(queryString))
|
||||
.When(_ => WhenMapped())
|
||||
.Then(_ => ThenAnErrorIsReturned())
|
||||
.And(_ => ThenTheMappedRequestIsNull())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("GET")]
|
||||
[InlineData("POST")]
|
||||
[InlineData("WHATEVER")]
|
||||
public void Should_map_method(string method)
|
||||
{
|
||||
this.Given(_ => GivenTheInputRequestHasMethod(method))
|
||||
.And(_ => GivenTheInputRequestHasAValidUri())
|
||||
.When(_ => WhenMapped())
|
||||
.Then(_ => ThenNoErrorIsReturned())
|
||||
.And(_ => ThenTheMappedRequestHasMethod(method))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_map_all_headers()
|
||||
{
|
||||
this.Given(_ => GivenTheInputRequestHasHeaders())
|
||||
.And(_ => GivenTheInputRequestHasMethod("GET"))
|
||||
.And(_ => GivenTheInputRequestHasAValidUri())
|
||||
.When(_ => WhenMapped())
|
||||
.Then(_ => ThenNoErrorIsReturned())
|
||||
.And(_ => ThenTheMappedRequestHasEachHeader())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_handle_no_headers()
|
||||
{
|
||||
this.Given(_ => GivenTheInputRequestHasNoHeaders())
|
||||
.And(_ => GivenTheInputRequestHasMethod("GET"))
|
||||
.And(_ => GivenTheInputRequestHasAValidUri())
|
||||
.When(_ => WhenMapped())
|
||||
.Then(_ => ThenNoErrorIsReturned())
|
||||
.And(_ => ThenTheMappedRequestHasNoHeaders())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_map_content()
|
||||
{
|
||||
this.Given(_ => GivenTheInputRequestHasContent("This is my content"))
|
||||
.And(_ => GivenTheInputRequestHasMethod("GET"))
|
||||
.And(_ => GivenTheInputRequestHasAValidUri())
|
||||
.When(_ => WhenMapped())
|
||||
.Then(_ => ThenNoErrorIsReturned())
|
||||
.And(_ => ThenTheMappedRequestHasContent("This is my content"))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_handle_no_content()
|
||||
{
|
||||
this.Given(_ => GivenTheInputRequestHasNoContent())
|
||||
.And(_ => GivenTheInputRequestHasMethod("GET"))
|
||||
.And(_ => GivenTheInputRequestHasAValidUri())
|
||||
.When(_ => WhenMapped())
|
||||
.Then(_ => ThenNoErrorIsReturned())
|
||||
.And(_ => ThenTheMappedRequestHasNoContent())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_map_content_headers()
|
||||
{
|
||||
byte[] md5bytes = new byte[0];
|
||||
using (var md5 = MD5.Create())
|
||||
{
|
||||
md5bytes = md5.ComputeHash(Encoding.UTF8.GetBytes("some md5"));
|
||||
}
|
||||
|
||||
this.Given(_ => GivenTheInputRequestHasContent("This is my content"))
|
||||
.And(_ => GivenTheContentTypeIs("application/json"))
|
||||
.And(_ => GivenTheContentEncodingIs("gzip, compress"))
|
||||
.And(_ => GivenTheContentLanguageIs("english"))
|
||||
.And(_ => GivenTheContentLocationIs("/my-receipts/38"))
|
||||
.And(_ => GivenTheContentRangeIs("bytes 1-2/*"))
|
||||
.And(_ => GivenTheContentDispositionIs("inline"))
|
||||
.And(_ => GivenTheContentMD5Is(md5bytes))
|
||||
.And(_ => GivenTheInputRequestHasMethod("GET"))
|
||||
.And(_ => GivenTheInputRequestHasAValidUri())
|
||||
.When(_ => WhenMapped())
|
||||
.Then(_ => ThenNoErrorIsReturned())
|
||||
.And(_ => ThenTheMappedRequestHasContentTypeHeader("application/json"))
|
||||
.And(_ => ThenTheMappedRequestHasContentEncodingHeader("gzip", "compress"))
|
||||
.And(_ => ThenTheMappedRequestHasContentLanguageHeader("english"))
|
||||
.And(_ => ThenTheMappedRequestHasContentLocationHeader("/my-receipts/38"))
|
||||
.And(_ => ThenTheMappedRequestHasContentMD5Header(md5bytes))
|
||||
.And(_ => ThenTheMappedRequestHasContentRangeHeader())
|
||||
.And(_ => ThenTheMappedRequestHasContentDispositionHeader("inline"))
|
||||
.And(_ => ThenTheMappedRequestHasContentSize("This is my content".Length))
|
||||
.And(_ => ThenTheContentHeadersAreNotAddedToNonContentHeaders())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_not_add_content_headers()
|
||||
{
|
||||
this.Given(_ => GivenTheInputRequestHasContent("This is my content"))
|
||||
.And(_ => GivenTheContentTypeIs("application/json"))
|
||||
.And(_ => GivenTheInputRequestHasMethod("POST"))
|
||||
.And(_ => GivenTheInputRequestHasAValidUri())
|
||||
.When(_ => WhenMapped())
|
||||
.Then(_ => ThenNoErrorIsReturned())
|
||||
.And(_ => ThenTheMappedRequestHasContentTypeHeader("application/json"))
|
||||
.And(_ => ThenTheMappedRequestHasContentSize("This is my content".Length))
|
||||
.And(_ => ThenTheOtherContentTypeHeadersAreNotMapped())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void ThenTheContentHeadersAreNotAddedToNonContentHeaders()
|
||||
{
|
||||
_mappedRequest.Data.Headers.ShouldNotContain(x => x.Key == "Content-Disposition");
|
||||
_mappedRequest.Data.Headers.ShouldNotContain(x => x.Key == "Content-ContentMD5");
|
||||
_mappedRequest.Data.Headers.ShouldNotContain(x => x.Key == "Content-ContentRange");
|
||||
_mappedRequest.Data.Headers.ShouldNotContain(x => x.Key == "Content-ContentLanguage");
|
||||
_mappedRequest.Data.Headers.ShouldNotContain(x => x.Key == "Content-ContentEncoding");
|
||||
_mappedRequest.Data.Headers.ShouldNotContain(x => x.Key == "Content-ContentLocation");
|
||||
_mappedRequest.Data.Headers.ShouldNotContain(x => x.Key == "Content-Length");
|
||||
_mappedRequest.Data.Headers.ShouldNotContain(x => x.Key == "Content-Type");
|
||||
}
|
||||
|
||||
private void ThenTheOtherContentTypeHeadersAreNotMapped()
|
||||
{
|
||||
_mappedRequest.Data.Content.Headers.ContentDisposition.ShouldBeNull();
|
||||
_mappedRequest.Data.Content.Headers.ContentMD5.ShouldBeNull();
|
||||
_mappedRequest.Data.Content.Headers.ContentRange.ShouldBeNull();
|
||||
_mappedRequest.Data.Content.Headers.ContentLanguage.ShouldBeEmpty();
|
||||
_mappedRequest.Data.Content.Headers.ContentEncoding.ShouldBeEmpty();
|
||||
_mappedRequest.Data.Content.Headers.ContentLocation.ShouldBeNull();
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasContentDispositionHeader(string expected)
|
||||
{
|
||||
_mappedRequest.Data.Content.Headers.ContentDisposition.DispositionType.ShouldBe(expected);
|
||||
}
|
||||
|
||||
private void GivenTheContentDispositionIs(string input)
|
||||
{
|
||||
_inputRequest.Headers.Add("Content-Disposition", input);
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasContentMD5Header(byte[] expected)
|
||||
{
|
||||
_mappedRequest.Data.Content.Headers.ContentMD5.ShouldBe(expected);
|
||||
}
|
||||
|
||||
private void GivenTheContentMD5Is(byte[] input)
|
||||
{
|
||||
var base64 = Convert.ToBase64String(input);
|
||||
_inputRequest.Headers.Add("Content-MD5", base64);
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasContentRangeHeader()
|
||||
{
|
||||
_mappedRequest.Data.Content.Headers.ContentRange.From.ShouldBe(1);
|
||||
_mappedRequest.Data.Content.Headers.ContentRange.To.ShouldBe(2);
|
||||
}
|
||||
|
||||
private void GivenTheContentRangeIs(string input)
|
||||
{
|
||||
_inputRequest.Headers.Add("Content-Range", input);
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasContentLocationHeader(string expected)
|
||||
{
|
||||
_mappedRequest.Data.Content.Headers.ContentLocation.OriginalString.ShouldBe(expected);
|
||||
}
|
||||
|
||||
private void GivenTheContentLocationIs(string input)
|
||||
{
|
||||
_inputRequest.Headers.Add("Content-Location", input);
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasContentLanguageHeader(string expected)
|
||||
{
|
||||
_mappedRequest.Data.Content.Headers.ContentLanguage.First().ShouldBe(expected);
|
||||
}
|
||||
|
||||
private void GivenTheContentLanguageIs(string input)
|
||||
{
|
||||
_inputRequest.Headers.Add("Content-Language", input);
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasContentEncodingHeader(string expected, string expectedTwo)
|
||||
{
|
||||
_mappedRequest.Data.Content.Headers.ContentEncoding.ToArray()[0].ShouldBe(expected);
|
||||
_mappedRequest.Data.Content.Headers.ContentEncoding.ToArray()[1].ShouldBe(expectedTwo);
|
||||
}
|
||||
|
||||
private void GivenTheContentEncodingIs(string input)
|
||||
{
|
||||
_inputRequest.Headers.Add("Content-Encoding", input);
|
||||
}
|
||||
|
||||
private void GivenTheContentTypeIs(string contentType)
|
||||
{
|
||||
_inputRequest.ContentType = contentType;
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasContentTypeHeader(string expected)
|
||||
{
|
||||
_mappedRequest.Data.Content.Headers.ContentType.MediaType.ShouldBe(expected);
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasContentSize(long expected)
|
||||
{
|
||||
_mappedRequest.Data.Content.Headers.ContentLength.ShouldBe(expected);
|
||||
}
|
||||
|
||||
private void GivenTheInputRequestHasMethod(string method)
|
||||
{
|
||||
_inputRequest.Method = method;
|
||||
}
|
||||
|
||||
private void GivenTheInputRequestHasScheme(string scheme)
|
||||
{
|
||||
_inputRequest.Scheme = scheme;
|
||||
}
|
||||
|
||||
private void GivenTheInputRequestHasHost(string host)
|
||||
{
|
||||
_inputRequest.Host = new HostString(host);
|
||||
}
|
||||
|
||||
private void GivenTheInputRequestHasPath(string path)
|
||||
{
|
||||
if (path != null)
|
||||
{
|
||||
_inputRequest.Path = path;
|
||||
}
|
||||
}
|
||||
|
||||
private void GivenTheInputRequestHasQueryString(string querystring)
|
||||
{
|
||||
if (querystring != null)
|
||||
{
|
||||
_inputRequest.QueryString = new QueryString(querystring);
|
||||
}
|
||||
}
|
||||
|
||||
private void GivenTheInputRequestHasAValidUri()
|
||||
{
|
||||
GivenTheInputRequestHasScheme("http");
|
||||
GivenTheInputRequestHasHost("www.google.com");
|
||||
}
|
||||
|
||||
private void GivenTheInputRequestHasHeaders()
|
||||
{
|
||||
_inputHeaders = new List<KeyValuePair<string, StringValues>>()
|
||||
{
|
||||
new KeyValuePair<string, StringValues>("abc", new StringValues(new string[]{"123","456" })),
|
||||
new KeyValuePair<string, StringValues>("def", new StringValues(new string[]{"789","012" })),
|
||||
};
|
||||
|
||||
foreach (var inputHeader in _inputHeaders)
|
||||
{
|
||||
_inputRequest.Headers.Add(inputHeader);
|
||||
}
|
||||
}
|
||||
|
||||
private void GivenTheInputRequestHasNoHeaders()
|
||||
{
|
||||
_inputRequest.Headers.Clear();
|
||||
}
|
||||
|
||||
private void GivenTheInputRequestHasContent(string content)
|
||||
{
|
||||
_inputRequest.Body = new MemoryStream(Encoding.UTF8.GetBytes(content));
|
||||
}
|
||||
|
||||
private void GivenTheInputRequestHasNoContent()
|
||||
{
|
||||
_inputRequest.Body = null;
|
||||
}
|
||||
|
||||
private void WhenMapped()
|
||||
{
|
||||
_mappedRequest = _requestMapper.Map(_inputRequest).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
private void ThenNoErrorIsReturned()
|
||||
{
|
||||
_mappedRequest.IsError.ShouldBeFalse();
|
||||
}
|
||||
|
||||
private void ThenAnErrorIsReturned()
|
||||
{
|
||||
_mappedRequest.IsError.ShouldBeTrue();
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasUri(string expectedUri)
|
||||
{
|
||||
_mappedRequest.Data.RequestUri.OriginalString.ShouldBe(expectedUri);
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasMethod(string expectedMethod)
|
||||
{
|
||||
_mappedRequest.Data.Method.ToString().ShouldBe(expectedMethod);
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasEachHeader()
|
||||
{
|
||||
_mappedRequest.Data.Headers.Count().ShouldBe(_inputHeaders.Count);
|
||||
foreach(var header in _mappedRequest.Data.Headers)
|
||||
{
|
||||
var inputHeader = _inputHeaders.First(h => h.Key == header.Key);
|
||||
inputHeader.ShouldNotBeNull();
|
||||
inputHeader.Value.Count().ShouldBe(header.Value.Count());
|
||||
foreach(var inputHeaderValue in inputHeader.Value)
|
||||
{
|
||||
header.Value.Any(v => v == inputHeaderValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasNoHeaders()
|
||||
{
|
||||
_mappedRequest.Data.Headers.Count().ShouldBe(0);
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasContent(string expectedContent)
|
||||
{
|
||||
_mappedRequest.Data.Content.ReadAsStringAsync().GetAwaiter().GetResult().ShouldBe(expectedContent);
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasNoContent()
|
||||
{
|
||||
_mappedRequest.Data.Content.ShouldBeNull();
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestIsNull()
|
||||
{
|
||||
_mappedRequest.Data.ShouldBeNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace Ocelot.UnitTests.Request.Mapper
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Internal;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Ocelot.Request.Mapper;
|
||||
using Ocelot.Responses;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
using Shouldly;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class RequestMapperTests
|
||||
{
|
||||
readonly HttpRequest _inputRequest;
|
||||
|
||||
readonly RequestMapper _requestMapper;
|
||||
|
||||
Response<HttpRequestMessage> _mappedRequest;
|
||||
|
||||
List<KeyValuePair<string, StringValues>> _inputHeaders = null;
|
||||
|
||||
public RequestMapperTests()
|
||||
{
|
||||
_inputRequest = new DefaultHttpRequest(new DefaultHttpContext());
|
||||
|
||||
_requestMapper = new RequestMapper();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("https", "my.url:123", "/abc/DEF", "?a=1&b=2", "https://my.url:123/abc/DEF?a=1&b=2")]
|
||||
[InlineData("http", "blah.com", "/d ef", "?abc=123", "http://blah.com/d%20ef?abc=123")] // note! the input is encoded when building the input request
|
||||
[InlineData("http", "myusername:mypassword@abc.co.uk", null, null, "http://myusername:mypassword@abc.co.uk/")]
|
||||
[InlineData("http", "點看.com", null, null, "http://xn--c1yn36f.com/")]
|
||||
[InlineData("http", "xn--c1yn36f.com", null, null, "http://xn--c1yn36f.com/")]
|
||||
public void Should_map_valid_request_uri(string scheme, string host, string path, string queryString, string expectedUri)
|
||||
{
|
||||
this.Given(_ => GivenTheInputRequestHasMethod("GET"))
|
||||
.And(_ => GivenTheInputRequestHasScheme(scheme))
|
||||
.And(_ => GivenTheInputRequestHasHost(host))
|
||||
.And(_ => GivenTheInputRequestHasPath(path))
|
||||
.And(_ => GivenTheInputRequestHasQueryString(queryString))
|
||||
.When(_ => WhenMapped())
|
||||
.Then(_ => ThenNoErrorIsReturned())
|
||||
.And(_ => ThenTheMappedRequestHasUri(expectedUri))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("ftp", "google.com", "/abc/DEF", "?a=1&b=2")]
|
||||
public void Should_error_on_unsupported_request_uri(string scheme, string host, string path, string queryString)
|
||||
{
|
||||
this.Given(_ => GivenTheInputRequestHasMethod("GET"))
|
||||
.And(_ => GivenTheInputRequestHasScheme(scheme))
|
||||
.And(_ => GivenTheInputRequestHasHost(host))
|
||||
.And(_ => GivenTheInputRequestHasPath(path))
|
||||
.And(_ => GivenTheInputRequestHasQueryString(queryString))
|
||||
.When(_ => WhenMapped())
|
||||
.Then(_ => ThenAnErrorIsReturned())
|
||||
.And(_ => ThenTheMappedRequestIsNull())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("GET")]
|
||||
[InlineData("POST")]
|
||||
[InlineData("WHATEVER")]
|
||||
public void Should_map_method(string method)
|
||||
{
|
||||
this.Given(_ => GivenTheInputRequestHasMethod(method))
|
||||
.And(_ => GivenTheInputRequestHasAValidUri())
|
||||
.When(_ => WhenMapped())
|
||||
.Then(_ => ThenNoErrorIsReturned())
|
||||
.And(_ => ThenTheMappedRequestHasMethod(method))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_map_all_headers()
|
||||
{
|
||||
this.Given(_ => GivenTheInputRequestHasHeaders())
|
||||
.And(_ => GivenTheInputRequestHasMethod("GET"))
|
||||
.And(_ => GivenTheInputRequestHasAValidUri())
|
||||
.When(_ => WhenMapped())
|
||||
.Then(_ => ThenNoErrorIsReturned())
|
||||
.And(_ => ThenTheMappedRequestHasEachHeader())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_handle_no_headers()
|
||||
{
|
||||
this.Given(_ => GivenTheInputRequestHasNoHeaders())
|
||||
.And(_ => GivenTheInputRequestHasMethod("GET"))
|
||||
.And(_ => GivenTheInputRequestHasAValidUri())
|
||||
.When(_ => WhenMapped())
|
||||
.Then(_ => ThenNoErrorIsReturned())
|
||||
.And(_ => ThenTheMappedRequestHasNoHeaders())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_map_content()
|
||||
{
|
||||
this.Given(_ => GivenTheInputRequestHasContent("This is my content"))
|
||||
.And(_ => GivenTheInputRequestHasMethod("GET"))
|
||||
.And(_ => GivenTheInputRequestHasAValidUri())
|
||||
.When(_ => WhenMapped())
|
||||
.Then(_ => ThenNoErrorIsReturned())
|
||||
.And(_ => ThenTheMappedRequestHasContent("This is my content"))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_handle_no_content()
|
||||
{
|
||||
this.Given(_ => GivenTheInputRequestHasNullContent())
|
||||
.And(_ => GivenTheInputRequestHasMethod("GET"))
|
||||
.And(_ => GivenTheInputRequestHasAValidUri())
|
||||
.When(_ => WhenMapped())
|
||||
.Then(_ => ThenNoErrorIsReturned())
|
||||
.And(_ => ThenTheMappedRequestHasNoContent())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_handle_no_content_type()
|
||||
{
|
||||
this.Given(_ => GivenTheInputRequestHasNoContentType())
|
||||
.And(_ => GivenTheInputRequestHasMethod("GET"))
|
||||
.And(_ => GivenTheInputRequestHasAValidUri())
|
||||
.When(_ => WhenMapped())
|
||||
.Then(_ => ThenNoErrorIsReturned())
|
||||
.And(_ => ThenTheMappedRequestHasNoContent())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_handle_no_content_length()
|
||||
{
|
||||
this.Given(_ => GivenTheInputRequestHasNoContentLength())
|
||||
.And(_ => GivenTheInputRequestHasMethod("GET"))
|
||||
.And(_ => GivenTheInputRequestHasAValidUri())
|
||||
.When(_ => WhenMapped())
|
||||
.Then(_ => ThenNoErrorIsReturned())
|
||||
.And(_ => ThenTheMappedRequestHasNoContent())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void GivenTheInputRequestHasNoContentLength()
|
||||
{
|
||||
_inputRequest.ContentLength = null;
|
||||
}
|
||||
|
||||
private void GivenTheInputRequestHasNoContentType()
|
||||
{
|
||||
_inputRequest.ContentType = null;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_map_content_headers()
|
||||
{
|
||||
byte[] md5bytes = new byte[0];
|
||||
using (var md5 = MD5.Create())
|
||||
{
|
||||
md5bytes = md5.ComputeHash(Encoding.UTF8.GetBytes("some md5"));
|
||||
}
|
||||
|
||||
this.Given(_ => GivenTheInputRequestHasContent("This is my content"))
|
||||
.And(_ => GivenTheContentTypeIs("application/json"))
|
||||
.And(_ => GivenTheContentEncodingIs("gzip, compress"))
|
||||
.And(_ => GivenTheContentLanguageIs("english"))
|
||||
.And(_ => GivenTheContentLocationIs("/my-receipts/38"))
|
||||
.And(_ => GivenTheContentRangeIs("bytes 1-2/*"))
|
||||
.And(_ => GivenTheContentDispositionIs("inline"))
|
||||
.And(_ => GivenTheContentMD5Is(md5bytes))
|
||||
.And(_ => GivenTheInputRequestHasMethod("GET"))
|
||||
.And(_ => GivenTheInputRequestHasAValidUri())
|
||||
.When(_ => WhenMapped())
|
||||
.Then(_ => ThenNoErrorIsReturned())
|
||||
.And(_ => ThenTheMappedRequestHasContentTypeHeader("application/json"))
|
||||
.And(_ => ThenTheMappedRequestHasContentEncodingHeader("gzip", "compress"))
|
||||
.And(_ => ThenTheMappedRequestHasContentLanguageHeader("english"))
|
||||
.And(_ => ThenTheMappedRequestHasContentLocationHeader("/my-receipts/38"))
|
||||
.And(_ => ThenTheMappedRequestHasContentMD5Header(md5bytes))
|
||||
.And(_ => ThenTheMappedRequestHasContentRangeHeader())
|
||||
.And(_ => ThenTheMappedRequestHasContentDispositionHeader("inline"))
|
||||
.And(_ => ThenTheMappedRequestHasContentSize("This is my content".Length))
|
||||
.And(_ => ThenTheContentHeadersAreNotAddedToNonContentHeaders())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_not_add_content_headers()
|
||||
{
|
||||
this.Given(_ => GivenTheInputRequestHasContent("This is my content"))
|
||||
.And(_ => GivenTheContentTypeIs("application/json"))
|
||||
.And(_ => GivenTheInputRequestHasMethod("POST"))
|
||||
.And(_ => GivenTheInputRequestHasAValidUri())
|
||||
.When(_ => WhenMapped())
|
||||
.Then(_ => ThenNoErrorIsReturned())
|
||||
.And(_ => ThenTheMappedRequestHasContentTypeHeader("application/json"))
|
||||
.And(_ => ThenTheMappedRequestHasContentSize("This is my content".Length))
|
||||
.And(_ => ThenTheOtherContentTypeHeadersAreNotMapped())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void ThenTheContentHeadersAreNotAddedToNonContentHeaders()
|
||||
{
|
||||
_mappedRequest.Data.Headers.ShouldNotContain(x => x.Key == "Content-Disposition");
|
||||
_mappedRequest.Data.Headers.ShouldNotContain(x => x.Key == "Content-ContentMD5");
|
||||
_mappedRequest.Data.Headers.ShouldNotContain(x => x.Key == "Content-ContentRange");
|
||||
_mappedRequest.Data.Headers.ShouldNotContain(x => x.Key == "Content-ContentLanguage");
|
||||
_mappedRequest.Data.Headers.ShouldNotContain(x => x.Key == "Content-ContentEncoding");
|
||||
_mappedRequest.Data.Headers.ShouldNotContain(x => x.Key == "Content-ContentLocation");
|
||||
_mappedRequest.Data.Headers.ShouldNotContain(x => x.Key == "Content-Length");
|
||||
_mappedRequest.Data.Headers.ShouldNotContain(x => x.Key == "Content-Type");
|
||||
}
|
||||
|
||||
private void ThenTheOtherContentTypeHeadersAreNotMapped()
|
||||
{
|
||||
_mappedRequest.Data.Content.Headers.ContentDisposition.ShouldBeNull();
|
||||
_mappedRequest.Data.Content.Headers.ContentMD5.ShouldBeNull();
|
||||
_mappedRequest.Data.Content.Headers.ContentRange.ShouldBeNull();
|
||||
_mappedRequest.Data.Content.Headers.ContentLanguage.ShouldBeEmpty();
|
||||
_mappedRequest.Data.Content.Headers.ContentEncoding.ShouldBeEmpty();
|
||||
_mappedRequest.Data.Content.Headers.ContentLocation.ShouldBeNull();
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasContentDispositionHeader(string expected)
|
||||
{
|
||||
_mappedRequest.Data.Content.Headers.ContentDisposition.DispositionType.ShouldBe(expected);
|
||||
}
|
||||
|
||||
private void GivenTheContentDispositionIs(string input)
|
||||
{
|
||||
_inputRequest.Headers.Add("Content-Disposition", input);
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasContentMD5Header(byte[] expected)
|
||||
{
|
||||
_mappedRequest.Data.Content.Headers.ContentMD5.ShouldBe(expected);
|
||||
}
|
||||
|
||||
private void GivenTheContentMD5Is(byte[] input)
|
||||
{
|
||||
var base64 = Convert.ToBase64String(input);
|
||||
_inputRequest.Headers.Add("Content-MD5", base64);
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasContentRangeHeader()
|
||||
{
|
||||
_mappedRequest.Data.Content.Headers.ContentRange.From.ShouldBe(1);
|
||||
_mappedRequest.Data.Content.Headers.ContentRange.To.ShouldBe(2);
|
||||
}
|
||||
|
||||
private void GivenTheContentRangeIs(string input)
|
||||
{
|
||||
_inputRequest.Headers.Add("Content-Range", input);
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasContentLocationHeader(string expected)
|
||||
{
|
||||
_mappedRequest.Data.Content.Headers.ContentLocation.OriginalString.ShouldBe(expected);
|
||||
}
|
||||
|
||||
private void GivenTheContentLocationIs(string input)
|
||||
{
|
||||
_inputRequest.Headers.Add("Content-Location", input);
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasContentLanguageHeader(string expected)
|
||||
{
|
||||
_mappedRequest.Data.Content.Headers.ContentLanguage.First().ShouldBe(expected);
|
||||
}
|
||||
|
||||
private void GivenTheContentLanguageIs(string input)
|
||||
{
|
||||
_inputRequest.Headers.Add("Content-Language", input);
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasContentEncodingHeader(string expected, string expectedTwo)
|
||||
{
|
||||
_mappedRequest.Data.Content.Headers.ContentEncoding.ToArray()[0].ShouldBe(expected);
|
||||
_mappedRequest.Data.Content.Headers.ContentEncoding.ToArray()[1].ShouldBe(expectedTwo);
|
||||
}
|
||||
|
||||
private void GivenTheContentEncodingIs(string input)
|
||||
{
|
||||
_inputRequest.Headers.Add("Content-Encoding", input);
|
||||
}
|
||||
|
||||
private void GivenTheContentTypeIs(string contentType)
|
||||
{
|
||||
_inputRequest.ContentType = contentType;
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasContentTypeHeader(string expected)
|
||||
{
|
||||
_mappedRequest.Data.Content.Headers.ContentType.MediaType.ShouldBe(expected);
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasContentSize(long expected)
|
||||
{
|
||||
_mappedRequest.Data.Content.Headers.ContentLength.ShouldBe(expected);
|
||||
}
|
||||
|
||||
private void GivenTheInputRequestHasMethod(string method)
|
||||
{
|
||||
_inputRequest.Method = method;
|
||||
}
|
||||
|
||||
private void GivenTheInputRequestHasScheme(string scheme)
|
||||
{
|
||||
_inputRequest.Scheme = scheme;
|
||||
}
|
||||
|
||||
private void GivenTheInputRequestHasHost(string host)
|
||||
{
|
||||
_inputRequest.Host = new HostString(host);
|
||||
}
|
||||
|
||||
private void GivenTheInputRequestHasPath(string path)
|
||||
{
|
||||
if (path != null)
|
||||
{
|
||||
_inputRequest.Path = path;
|
||||
}
|
||||
}
|
||||
|
||||
private void GivenTheInputRequestHasQueryString(string querystring)
|
||||
{
|
||||
if (querystring != null)
|
||||
{
|
||||
_inputRequest.QueryString = new QueryString(querystring);
|
||||
}
|
||||
}
|
||||
|
||||
private void GivenTheInputRequestHasAValidUri()
|
||||
{
|
||||
GivenTheInputRequestHasScheme("http");
|
||||
GivenTheInputRequestHasHost("www.google.com");
|
||||
}
|
||||
|
||||
private void GivenTheInputRequestHasHeaders()
|
||||
{
|
||||
_inputHeaders = new List<KeyValuePair<string, StringValues>>()
|
||||
{
|
||||
new KeyValuePair<string, StringValues>("abc", new StringValues(new string[]{"123","456" })),
|
||||
new KeyValuePair<string, StringValues>("def", new StringValues(new string[]{"789","012" })),
|
||||
};
|
||||
|
||||
foreach (var inputHeader in _inputHeaders)
|
||||
{
|
||||
_inputRequest.Headers.Add(inputHeader);
|
||||
}
|
||||
}
|
||||
|
||||
private void GivenTheInputRequestHasNoHeaders()
|
||||
{
|
||||
_inputRequest.Headers.Clear();
|
||||
}
|
||||
|
||||
private void GivenTheInputRequestHasContent(string content)
|
||||
{
|
||||
_inputRequest.Body = new MemoryStream(Encoding.UTF8.GetBytes(content));
|
||||
}
|
||||
|
||||
private void GivenTheInputRequestHasNullContent()
|
||||
{
|
||||
_inputRequest.Body = null;
|
||||
}
|
||||
|
||||
private async Task WhenMapped()
|
||||
{
|
||||
_mappedRequest = await _requestMapper.Map(_inputRequest);
|
||||
}
|
||||
|
||||
private void ThenNoErrorIsReturned()
|
||||
{
|
||||
_mappedRequest.IsError.ShouldBeFalse();
|
||||
}
|
||||
|
||||
private void ThenAnErrorIsReturned()
|
||||
{
|
||||
_mappedRequest.IsError.ShouldBeTrue();
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasUri(string expectedUri)
|
||||
{
|
||||
_mappedRequest.Data.RequestUri.OriginalString.ShouldBe(expectedUri);
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasMethod(string expectedMethod)
|
||||
{
|
||||
_mappedRequest.Data.Method.ToString().ShouldBe(expectedMethod);
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasEachHeader()
|
||||
{
|
||||
_mappedRequest.Data.Headers.Count().ShouldBe(_inputHeaders.Count);
|
||||
foreach(var header in _mappedRequest.Data.Headers)
|
||||
{
|
||||
var inputHeader = _inputHeaders.First(h => h.Key == header.Key);
|
||||
inputHeader.ShouldNotBeNull();
|
||||
inputHeader.Value.Count().ShouldBe(header.Value.Count());
|
||||
foreach(var inputHeaderValue in inputHeader.Value)
|
||||
{
|
||||
header.Value.Any(v => v == inputHeaderValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasNoHeaders()
|
||||
{
|
||||
_mappedRequest.Data.Headers.Count().ShouldBe(0);
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasContent(string expectedContent)
|
||||
{
|
||||
_mappedRequest.Data.Content.ReadAsStringAsync().GetAwaiter().GetResult().ShouldBe(expectedContent);
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestHasNoContent()
|
||||
{
|
||||
_mappedRequest.Data.Content.ShouldBeNull();
|
||||
}
|
||||
|
||||
private void ThenTheMappedRequestIsNull()
|
||||
{
|
||||
_mappedRequest.Data.ShouldBeNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,30 @@
|
||||
using Butterfly.Client.Tracing;
|
||||
using Moq;
|
||||
using Ocelot.Infrastructure.RequestData;
|
||||
using Ocelot.Requester;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
namespace Ocelot.UnitTests.Requester
|
||||
{
|
||||
using System;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Moq;
|
||||
using Ocelot.Infrastructure.RequestData;
|
||||
using Ocelot.Requester;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
using Ocelot.Logging;
|
||||
|
||||
public class TracingHandlerFactoryTests
|
||||
{
|
||||
private TracingHandlerFactory _factory;
|
||||
private Mock<IServiceTracer> _tracer;
|
||||
private readonly TracingHandlerFactory _factory;
|
||||
private Mock<ITracer> _tracer;
|
||||
private IServiceCollection _serviceCollection;
|
||||
private IServiceProvider _serviceProvider;
|
||||
private Mock<IRequestScopedDataRepository> _repo;
|
||||
|
||||
public TracingHandlerFactoryTests()
|
||||
{
|
||||
_tracer = new Mock<IServiceTracer>();
|
||||
_tracer = new Mock<ITracer>();
|
||||
_serviceCollection = new ServiceCollection();
|
||||
_serviceCollection.AddSingleton<ITracer>(_tracer.Object);
|
||||
_serviceProvider = _serviceCollection.BuildServiceProvider();
|
||||
_repo = new Mock<IRequestScopedDataRepository>();
|
||||
_factory = new TracingHandlerFactory(_tracer.Object, _repo.Object);
|
||||
_factory = new TracingHandlerFactory(_serviceProvider, _repo.Object);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -27,4 +34,4 @@ namespace Ocelot.UnitTests.Requester
|
||||
handler.ShouldBeOfType<OcelotHttpTracingHandler>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -72,7 +72,6 @@ namespace Ocelot.UnitTests.Responder
|
||||
[InlineData(OcelotErrorCode.UnableToFindLoadBalancerError)]
|
||||
[InlineData(OcelotErrorCode.UnableToFindServiceDiscoveryProviderError)]
|
||||
[InlineData(OcelotErrorCode.UnableToFindQoSProviderError)]
|
||||
[InlineData(OcelotErrorCode.UnableToSetConfigInConsulError)]
|
||||
[InlineData(OcelotErrorCode.UnknownError)]
|
||||
[InlineData(OcelotErrorCode.UnmappableRequestError)]
|
||||
[InlineData(OcelotErrorCode.UnsupportedAuthenticationProviderError)]
|
||||
@ -126,7 +125,7 @@ namespace Ocelot.UnitTests.Responder
|
||||
// If this test fails then it's because the number of error codes has changed.
|
||||
// You should make the appropriate changes to the test cases here to ensure
|
||||
// they cover all the error codes, and then modify this assertion.
|
||||
Enum.GetNames(typeof(OcelotErrorCode)).Length.ShouldBe(35, "Looks like the number of error codes has changed. Do you need to modify ErrorsToHttpStatusCodeMapper?");
|
||||
Enum.GetNames(typeof(OcelotErrorCode)).Length.ShouldBe(34, "Looks like the number of error codes has changed. Do you need to modify ErrorsToHttpStatusCodeMapper?");
|
||||
}
|
||||
|
||||
private void ShouldMapErrorToStatusCode(OcelotErrorCode errorCode, HttpStatusCode expectedHttpStatusCode)
|
||||
|
@ -1,249 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Consul;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Moq;
|
||||
using Ocelot.Infrastructure.Consul;
|
||||
using Ocelot.Logging;
|
||||
using Ocelot.ServiceDiscovery.Configuration;
|
||||
using Ocelot.ServiceDiscovery.Providers;
|
||||
using Ocelot.Values;
|
||||
using Xunit;
|
||||
using TestStack.BDDfy;
|
||||
using Shouldly;
|
||||
|
||||
namespace Ocelot.UnitTests.ServiceDiscovery
|
||||
{
|
||||
public class ConsulServiceDiscoveryProviderTests : IDisposable
|
||||
{
|
||||
private IWebHost _fakeConsulBuilder;
|
||||
private readonly List<ServiceEntry> _serviceEntries;
|
||||
private ConsulServiceDiscoveryProvider _provider;
|
||||
private readonly string _serviceName;
|
||||
private readonly int _port;
|
||||
private readonly string _consulHost;
|
||||
private readonly string _fakeConsulServiceDiscoveryUrl;
|
||||
private List<Service> _services;
|
||||
private readonly Mock<IOcelotLoggerFactory> _factory;
|
||||
private readonly Mock<IOcelotLogger> _logger;
|
||||
private string _receivedToken;
|
||||
private IConsulClientFactory _clientFactory;
|
||||
|
||||
public ConsulServiceDiscoveryProviderTests()
|
||||
{
|
||||
_serviceName = "test";
|
||||
_port = 8500;
|
||||
_consulHost = "localhost";
|
||||
_fakeConsulServiceDiscoveryUrl = $"http://{_consulHost}:{_port}";
|
||||
_serviceEntries = new List<ServiceEntry>();
|
||||
|
||||
_factory = new Mock<IOcelotLoggerFactory>();
|
||||
_clientFactory = new ConsulClientFactory();
|
||||
_logger = new Mock<IOcelotLogger>();
|
||||
_factory.Setup(x => x.CreateLogger<ConsulServiceDiscoveryProvider>()).Returns(_logger.Object);
|
||||
|
||||
var config = new ConsulRegistryConfiguration(_consulHost, _port, _serviceName, null);
|
||||
_provider = new ConsulServiceDiscoveryProvider(config, _factory.Object, _clientFactory);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_return_service_from_consul()
|
||||
{
|
||||
var serviceEntryOne = new ServiceEntry()
|
||||
{
|
||||
Service = new AgentService()
|
||||
{
|
||||
Service = _serviceName,
|
||||
Address = "localhost",
|
||||
Port = 50881,
|
||||
ID = Guid.NewGuid().ToString(),
|
||||
Tags = new string[0]
|
||||
},
|
||||
};
|
||||
|
||||
this.Given(x =>GivenThereIsAFakeConsulServiceDiscoveryProvider(_fakeConsulServiceDiscoveryUrl, _serviceName))
|
||||
.And(x => GivenTheServicesAreRegisteredWithConsul(serviceEntryOne))
|
||||
.When(x => WhenIGetTheServices())
|
||||
.Then(x => ThenTheCountIs(1))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_use_token()
|
||||
{
|
||||
var token = "test token";
|
||||
var config = new ConsulRegistryConfiguration(_consulHost, _port, _serviceName, token);
|
||||
_provider = new ConsulServiceDiscoveryProvider(config, _factory.Object, _clientFactory);
|
||||
|
||||
var serviceEntryOne = new ServiceEntry()
|
||||
{
|
||||
Service = new AgentService()
|
||||
{
|
||||
Service = _serviceName,
|
||||
Address = "localhost",
|
||||
Port = 50881,
|
||||
ID = Guid.NewGuid().ToString(),
|
||||
Tags = new string[0]
|
||||
},
|
||||
};
|
||||
|
||||
this.Given(_ => GivenThereIsAFakeConsulServiceDiscoveryProvider(_fakeConsulServiceDiscoveryUrl, _serviceName))
|
||||
.And(_ => GivenTheServicesAreRegisteredWithConsul(serviceEntryOne))
|
||||
.When(_ => WhenIGetTheServices())
|
||||
.Then(_ => ThenTheCountIs(1))
|
||||
.And(_ => _receivedToken.ShouldBe(token))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_not_return_services_with_invalid_address()
|
||||
{
|
||||
var serviceEntryOne = new ServiceEntry()
|
||||
{
|
||||
Service = new AgentService()
|
||||
{
|
||||
Service = _serviceName,
|
||||
Address = "http://localhost",
|
||||
Port = 50881,
|
||||
ID = Guid.NewGuid().ToString(),
|
||||
Tags = new string[0]
|
||||
},
|
||||
};
|
||||
|
||||
var serviceEntryTwo = new ServiceEntry()
|
||||
{
|
||||
Service = new AgentService()
|
||||
{
|
||||
Service = _serviceName,
|
||||
Address = "http://localhost",
|
||||
Port = 50888,
|
||||
ID = Guid.NewGuid().ToString(),
|
||||
Tags = new string[0]
|
||||
},
|
||||
};
|
||||
|
||||
this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(_fakeConsulServiceDiscoveryUrl, _serviceName))
|
||||
.And(x => GivenTheServicesAreRegisteredWithConsul(serviceEntryOne, serviceEntryTwo))
|
||||
.When(x => WhenIGetTheServices())
|
||||
.Then(x => ThenTheCountIs(0))
|
||||
.And(x => ThenTheLoggerHasBeenCalledCorrectlyForInvalidAddress())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_not_return_services_with_invalid_port()
|
||||
{
|
||||
var serviceEntryOne = new ServiceEntry()
|
||||
{
|
||||
Service = new AgentService()
|
||||
{
|
||||
Service = _serviceName,
|
||||
Address = "localhost",
|
||||
Port = -1,
|
||||
ID = Guid.NewGuid().ToString(),
|
||||
Tags = new string[0]
|
||||
},
|
||||
};
|
||||
|
||||
var serviceEntryTwo = new ServiceEntry()
|
||||
{
|
||||
Service = new AgentService()
|
||||
{
|
||||
Service = _serviceName,
|
||||
Address = "localhost",
|
||||
Port = 0,
|
||||
ID = Guid.NewGuid().ToString(),
|
||||
Tags = new string[0]
|
||||
},
|
||||
};
|
||||
|
||||
this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(_fakeConsulServiceDiscoveryUrl, _serviceName))
|
||||
.And(x => GivenTheServicesAreRegisteredWithConsul(serviceEntryOne, serviceEntryTwo))
|
||||
.When(x => WhenIGetTheServices())
|
||||
.Then(x => ThenTheCountIs(0))
|
||||
.And(x => ThenTheLoggerHasBeenCalledCorrectlyForInvalidPorts())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void ThenTheLoggerHasBeenCalledCorrectlyForInvalidAddress()
|
||||
{
|
||||
_logger.Verify(
|
||||
x => x.LogWarning(
|
||||
"Unable to use service Address: http://localhost and Port: 50881 as it is invalid. Address must contain host only e.g. localhost and port must be greater than 0"),
|
||||
Times.Once);
|
||||
|
||||
_logger.Verify(
|
||||
x => x.LogWarning(
|
||||
"Unable to use service Address: http://localhost and Port: 50888 as it is invalid. Address must contain host only e.g. localhost and port must be greater than 0"),
|
||||
Times.Once);
|
||||
}
|
||||
|
||||
private void ThenTheLoggerHasBeenCalledCorrectlyForInvalidPorts()
|
||||
{
|
||||
_logger.Verify(
|
||||
x => x.LogWarning(
|
||||
"Unable to use service Address: localhost and Port: -1 as it is invalid. Address must contain host only e.g. localhost and port must be greater than 0"),
|
||||
Times.Once);
|
||||
|
||||
_logger.Verify(
|
||||
x => x.LogWarning(
|
||||
"Unable to use service Address: localhost and Port: 0 as it is invalid. Address must contain host only e.g. localhost and port must be greater than 0"),
|
||||
Times.Once);
|
||||
}
|
||||
|
||||
private void ThenTheCountIs(int count)
|
||||
{
|
||||
_services.Count.ShouldBe(count);
|
||||
}
|
||||
|
||||
private void WhenIGetTheServices()
|
||||
{
|
||||
_services = _provider.Get().GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
private void GivenTheServicesAreRegisteredWithConsul(params ServiceEntry[] serviceEntries)
|
||||
{
|
||||
foreach (var serviceEntry in serviceEntries)
|
||||
{
|
||||
_serviceEntries.Add(serviceEntry);
|
||||
}
|
||||
}
|
||||
|
||||
private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url, string serviceName)
|
||||
{
|
||||
_fakeConsulBuilder = new WebHostBuilder()
|
||||
.UseUrls(url)
|
||||
.UseKestrel()
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.UseIISIntegration()
|
||||
.UseUrls(url)
|
||||
.Configure(app =>
|
||||
{
|
||||
app.Run(async context =>
|
||||
{
|
||||
if (context.Request.Path.Value == $"/v1/health/service/{serviceName}")
|
||||
{
|
||||
if (context.Request.Headers.TryGetValue("X-Consul-Token", out var values))
|
||||
{
|
||||
_receivedToken = values.First();
|
||||
}
|
||||
|
||||
await context.Response.WriteJsonAsync(_serviceEntries);
|
||||
}
|
||||
});
|
||||
})
|
||||
.Build();
|
||||
|
||||
_fakeConsulBuilder.Start();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_fakeConsulBuilder?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,118 +0,0 @@
|
||||
namespace Ocelot.UnitTests.ServiceDiscovery
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Moq;
|
||||
using Ocelot.ServiceDiscovery.Providers;
|
||||
using Pivotal.Discovery.Client;
|
||||
using Shouldly;
|
||||
using Steeltoe.Common.Discovery;
|
||||
using TestStack.BDDfy;
|
||||
using Values;
|
||||
using Xunit;
|
||||
|
||||
public class EurekaServiceDiscoveryProviderTests
|
||||
{
|
||||
private readonly EurekaServiceDiscoveryProvider _provider;
|
||||
private readonly Mock<IDiscoveryClient> _client;
|
||||
private readonly string _serviceId;
|
||||
private List<IServiceInstance> _instances;
|
||||
private List<Service> _result;
|
||||
|
||||
public EurekaServiceDiscoveryProviderTests()
|
||||
{
|
||||
_serviceId = "Laura";
|
||||
_client = new Mock<IDiscoveryClient>();
|
||||
_provider = new EurekaServiceDiscoveryProvider(_serviceId, _client.Object);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_return_empty_services()
|
||||
{
|
||||
this.When(_ => WhenIGet())
|
||||
.Then(_ => ThenTheCountIs(0))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_return_service_from_client()
|
||||
{
|
||||
var instances = new List<IServiceInstance>
|
||||
{
|
||||
new EurekaService(_serviceId, "somehost", 801, false, new Uri("http://somehost:801"), new Dictionary<string, string>())
|
||||
};
|
||||
|
||||
this.Given(_ => GivenThe(instances))
|
||||
.When(_ => WhenIGet())
|
||||
.Then(_ => ThenTheCountIs(1))
|
||||
.And(_ => ThenTheClientIsCalledCorrectly())
|
||||
.And(_ => ThenTheServiceIsMapped())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_return_services_from_client()
|
||||
{
|
||||
var instances = new List<IServiceInstance>
|
||||
{
|
||||
new EurekaService(_serviceId, "somehost", 801, false, new Uri("http://somehost:801"), new Dictionary<string, string>()),
|
||||
new EurekaService(_serviceId, "somehost", 801, false, new Uri("http://somehost:801"), new Dictionary<string, string>())
|
||||
};
|
||||
|
||||
this.Given(_ => GivenThe(instances))
|
||||
.When(_ => WhenIGet())
|
||||
.Then(_ => ThenTheCountIs(2))
|
||||
.And(_ => ThenTheClientIsCalledCorrectly())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void ThenTheServiceIsMapped()
|
||||
{
|
||||
_result[0].HostAndPort.DownstreamHost.ShouldBe("somehost");
|
||||
_result[0].HostAndPort.DownstreamPort.ShouldBe(801);
|
||||
_result[0].Name.ShouldBe(_serviceId);
|
||||
}
|
||||
|
||||
private void ThenTheCountIs(int expected)
|
||||
{
|
||||
_result.Count.ShouldBe(expected);
|
||||
}
|
||||
|
||||
private void ThenTheClientIsCalledCorrectly()
|
||||
{
|
||||
_client.Verify(x => x.GetInstances(_serviceId), Times.Once);
|
||||
}
|
||||
|
||||
private async Task WhenIGet()
|
||||
{
|
||||
_result = await _provider.Get();
|
||||
}
|
||||
|
||||
private void GivenThe(List<IServiceInstance> instances)
|
||||
{
|
||||
_instances = instances;
|
||||
_client.Setup(x => x.GetInstances(It.IsAny<string>())).Returns(instances);
|
||||
}
|
||||
}
|
||||
|
||||
public class EurekaService : IServiceInstance
|
||||
{
|
||||
public EurekaService(string serviceId, string host, int port, bool isSecure, Uri uri, IDictionary<string, string> metadata)
|
||||
{
|
||||
ServiceId = serviceId;
|
||||
Host = host;
|
||||
Port = port;
|
||||
IsSecure = isSecure;
|
||||
Uri = uri;
|
||||
Metadata = metadata;
|
||||
}
|
||||
|
||||
public string ServiceId { get; }
|
||||
public string Host { get; }
|
||||
public int Port { get; }
|
||||
public bool IsSecure { get; }
|
||||
public Uri Uri { get; }
|
||||
public IDictionary<string, string> Metadata { get; }
|
||||
}
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
namespace Ocelot.UnitTests.ServiceDiscovery
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Moq;
|
||||
using Ocelot.Logging;
|
||||
using Ocelot.ServiceDiscovery.Providers;
|
||||
using Ocelot.Values;
|
||||
using Xunit;
|
||||
using TestStack.BDDfy;
|
||||
using Shouldly;
|
||||
using static Ocelot.Infrastructure.Wait;
|
||||
|
||||
public class PollingConsulServiceDiscoveryProviderTests
|
||||
{
|
||||
private readonly int _delay;
|
||||
private PollingConsulServiceDiscoveryProvider _provider;
|
||||
private readonly List<Service> _services;
|
||||
private readonly Mock<IOcelotLoggerFactory> _factory;
|
||||
private readonly Mock<IOcelotLogger> _logger;
|
||||
private readonly Mock<IServiceDiscoveryProvider> _consulServiceDiscoveryProvider;
|
||||
private List<Service> _result;
|
||||
|
||||
public PollingConsulServiceDiscoveryProviderTests()
|
||||
{
|
||||
_services = new List<Service>();
|
||||
_delay = 1;
|
||||
_factory = new Mock<IOcelotLoggerFactory>();
|
||||
_logger = new Mock<IOcelotLogger>();
|
||||
_factory.Setup(x => x.CreateLogger<PollingConsulServiceDiscoveryProvider>()).Returns(_logger.Object);
|
||||
_consulServiceDiscoveryProvider = new Mock<IServiceDiscoveryProvider>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_return_service_from_consul()
|
||||
{
|
||||
var service = new Service("", new ServiceHostAndPort("", 0), "", "", new List<string>());
|
||||
|
||||
this.Given(x => GivenConsulReturns(service))
|
||||
.When(x => WhenIGetTheServices(1))
|
||||
.Then(x => ThenTheCountIs(1))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void GivenConsulReturns(Service service)
|
||||
{
|
||||
_services.Add(service);
|
||||
_consulServiceDiscoveryProvider.Setup(x => x.Get()).ReturnsAsync(_services);
|
||||
}
|
||||
|
||||
private void ThenTheCountIs(int count)
|
||||
{
|
||||
_result.Count.ShouldBe(count);
|
||||
}
|
||||
|
||||
private void WhenIGetTheServices(int expected)
|
||||
{
|
||||
_provider = new PollingConsulServiceDiscoveryProvider(_delay, "", _factory.Object, _consulServiceDiscoveryProvider.Object);
|
||||
|
||||
var result = WaitFor(3000).Until(() => {
|
||||
try
|
||||
{
|
||||
_result = _provider.Get().GetAwaiter().GetResult();
|
||||
if(_result.Count == expected)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
catch(Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
result.ShouldBeTrue();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,23 +1,12 @@
|
||||
using Ocelot.ServiceDiscovery.Configuration;
|
||||
using Ocelot.ServiceDiscovery.Providers;
|
||||
|
||||
namespace Ocelot.UnitTests.ServiceDiscovery
|
||||
namespace Ocelot.UnitTests.ServiceDiscovery
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Consul;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Moq;
|
||||
using Ocelot.Logging;
|
||||
using Ocelot.ServiceDiscovery;
|
||||
using Ocelot.Values;
|
||||
using Xunit;
|
||||
using TestStack.BDDfy;
|
||||
using Shouldly;
|
||||
using Ocelot.ServiceDiscovery.Configuration;
|
||||
using Ocelot.ServiceDiscovery.Providers;
|
||||
|
||||
public class ServiceFabricServiceDiscoveryProviderTests
|
||||
{
|
||||
|
@ -1,39 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Moq;
|
||||
using Ocelot.Configuration;
|
||||
using Ocelot.Configuration.Builder;
|
||||
using Ocelot.Infrastructure.Consul;
|
||||
using Ocelot.Logging;
|
||||
using Ocelot.ServiceDiscovery;
|
||||
using Ocelot.ServiceDiscovery.Providers;
|
||||
using Shouldly;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
|
||||
namespace Ocelot.UnitTests.ServiceDiscovery
|
||||
{
|
||||
using Pivotal.Discovery.Client;
|
||||
using Steeltoe.Common.Discovery;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Values;
|
||||
using System.Collections.Generic;
|
||||
using Moq;
|
||||
using Ocelot.Configuration;
|
||||
using Ocelot.Configuration.Builder;
|
||||
using Ocelot.Logging;
|
||||
using Ocelot.ServiceDiscovery;
|
||||
using Ocelot.ServiceDiscovery.Providers;
|
||||
using Shouldly;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
|
||||
public class ServiceProviderFactoryTests
|
||||
{
|
||||
private ServiceProviderConfiguration _serviceConfig;
|
||||
private IServiceDiscoveryProvider _result;
|
||||
private readonly ServiceDiscoveryProviderFactory _factory;
|
||||
private ServiceDiscoveryProviderFactory _factory;
|
||||
private DownstreamReRoute _reRoute;
|
||||
private Mock<IOcelotLoggerFactory> _loggerFactory;
|
||||
private Mock<IDiscoveryClient> _discoveryClient;
|
||||
private readonly Mock<IOcelotLoggerFactory> _loggerFactory;
|
||||
private Mock<IOcelotLogger> _logger;
|
||||
private IServiceProvider _provider;
|
||||
private readonly IServiceCollection _collection;
|
||||
|
||||
public ServiceProviderFactoryTests()
|
||||
{
|
||||
_loggerFactory = new Mock<IOcelotLoggerFactory>();
|
||||
_logger = new Mock<IOcelotLogger>();
|
||||
_loggerFactory.Setup(x => x.CreateLogger<PollingConsulServiceDiscoveryProvider>()).Returns(_logger.Object);
|
||||
_discoveryClient = new Mock<IDiscoveryClient>();
|
||||
var consulClient = new Mock<IConsulClientFactory>();
|
||||
_factory = new ServiceDiscoveryProviderFactory(_loggerFactory.Object, consulClient.Object, _discoveryClient.Object);
|
||||
_collection = new ServiceCollection();
|
||||
_provider = _collection.BuildServiceProvider();
|
||||
_factory = new ServiceDiscoveryProviderFactory(_loggerFactory.Object, _provider);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -72,7 +71,7 @@ namespace Ocelot.UnitTests.ServiceDiscovery
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_return_consul_service_provider()
|
||||
public void should_call_delegate()
|
||||
{
|
||||
var reRoute = new DownstreamReRouteBuilder()
|
||||
.WithServiceName("product")
|
||||
@ -83,27 +82,9 @@ namespace Ocelot.UnitTests.ServiceDiscovery
|
||||
.Build();
|
||||
|
||||
this.Given(x => x.GivenTheReRoute(serviceConfig, reRoute))
|
||||
.And(x => GivenAFakeDelegate())
|
||||
.When(x => x.WhenIGetTheServiceProvider())
|
||||
.Then(x => x.ThenTheServiceProviderIs<ConsulServiceDiscoveryProvider>())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_return_polling_consul_service_provider()
|
||||
{
|
||||
var reRoute = new DownstreamReRouteBuilder()
|
||||
.WithServiceName("product")
|
||||
.WithUseServiceDiscovery(true)
|
||||
.Build();
|
||||
|
||||
var serviceConfig = new ServiceProviderConfigurationBuilder()
|
||||
.WithType("PollConsul")
|
||||
.WithPollingInterval(100000)
|
||||
.Build();
|
||||
|
||||
this.Given(x => x.GivenTheReRoute(serviceConfig, reRoute))
|
||||
.When(x => x.WhenIGetTheServiceProvider())
|
||||
.Then(x => x.ThenTheServiceProviderIs<PollingConsulServiceDiscoveryProvider>())
|
||||
.Then(x => x.ThenTheDelegateIsCalled())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
@ -125,22 +106,25 @@ namespace Ocelot.UnitTests.ServiceDiscovery
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_return_eureka_provider()
|
||||
private void GivenAFakeDelegate()
|
||||
{
|
||||
var reRoute = new DownstreamReRouteBuilder()
|
||||
.WithServiceName("product")
|
||||
.WithUseServiceDiscovery(true)
|
||||
.Build();
|
||||
ServiceDiscoveryFinderDelegate fake = (provider, config, name) => new Fake();
|
||||
_collection.AddSingleton(fake);
|
||||
_provider = _collection.BuildServiceProvider();
|
||||
_factory = new ServiceDiscoveryProviderFactory(_loggerFactory.Object, _provider);
|
||||
}
|
||||
|
||||
var serviceConfig = new ServiceProviderConfigurationBuilder()
|
||||
.WithType("Eureka")
|
||||
.Build();
|
||||
class Fake : IServiceDiscoveryProvider
|
||||
{
|
||||
public Task<List<Service>> Get()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
this.Given(x => x.GivenTheReRoute(serviceConfig, reRoute))
|
||||
.When(x => x.WhenIGetTheServiceProvider())
|
||||
.Then(x => x.ThenTheServiceProviderIs<EurekaServiceDiscoveryProvider>())
|
||||
.BDDfy();
|
||||
private void ThenTheDelegateIsCalled()
|
||||
{
|
||||
_result.GetType().Name.ShouldBe("Fake");
|
||||
}
|
||||
|
||||
private void ThenTheFollowingServicesAreReturned(List<DownstreamHostAndPort> downstreamAddresses)
|
||||
|
Reference in New Issue
Block a user