Feature/#295 consul acl (#307)

* removed file

* updated package

* updated package

* updated package

* updated package

* updated package

* updated package

* updated package

* all packages updated

* #295 can add token to service provider config and this will be used by consul clients to get services and configuration

* #295 wait longer for this test
This commit is contained in:
Tom Pallister 2018-04-08 15:54:58 +01:00 committed by GitHub
parent d7ef956935
commit 982eebfc74
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 345 additions and 908 deletions

View File

@ -38,3 +38,18 @@ and LeastConnection algorithm you can use. If no load balancer is specified Ocel
}
When this is set up Ocelot will lookup the downstream host and port from the service discover provider and load balance requests across any available services.
ACL Token
---------
If you are using ACL with Consul Ocelot supports adding the X-Consul-Token header. In order so this to work you must add the additional property below.
.. code-block:: json
"ServiceDiscoveryProvider": {
"Host": "localhost",
"Port": 9500,
"Token": "footoken"
}
Ocelot will add this token to the consul client that it uses to make requests and that is then used for every request.

View File

@ -5,28 +5,35 @@ namespace Ocelot.Configuration.Builder
private string _serviceDiscoveryProviderHost;
private int _serviceDiscoveryProviderPort;
private string _type;
private string _token;
public ServiceProviderConfigurationBuilder WithServiceDiscoveryProviderHost(string serviceDiscoveryProviderHost)
public ServiceProviderConfigurationBuilder WithHost(string serviceDiscoveryProviderHost)
{
_serviceDiscoveryProviderHost = serviceDiscoveryProviderHost;
return this;
}
public ServiceProviderConfigurationBuilder WithServiceDiscoveryProviderPort(int serviceDiscoveryProviderPort)
public ServiceProviderConfigurationBuilder WithPort(int serviceDiscoveryProviderPort)
{
_serviceDiscoveryProviderPort = serviceDiscoveryProviderPort;
return this;
}
public ServiceProviderConfigurationBuilder WithServiceDiscoveryProviderType(string type)
public ServiceProviderConfigurationBuilder WithType(string type)
{
_type = type;
return this;
}
public ServiceProviderConfigurationBuilder WithToken(string token)
{
_token = token;
return this;
}
public ServiceProviderConfiguration Build()
{
return new ServiceProviderConfiguration(_type, _serviceDiscoveryProviderHost, _serviceDiscoveryProviderPort);
return new ServiceProviderConfiguration(_type, _serviceDiscoveryProviderHost, _serviceDiscoveryProviderPort, _token);
}
}
}

View File

@ -11,9 +11,10 @@ namespace Ocelot.Configuration.Creator
var serviceProviderPort = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0;
return new ServiceProviderConfigurationBuilder()
.WithServiceDiscoveryProviderHost(globalConfiguration?.ServiceDiscoveryProvider?.Host)
.WithServiceDiscoveryProviderPort(serviceProviderPort)
.WithServiceDiscoveryProviderType(globalConfiguration?.ServiceDiscoveryProvider?.Type)
.WithHost(globalConfiguration?.ServiceDiscoveryProvider?.Host)
.WithPort(serviceProviderPort)
.WithType(globalConfiguration?.ServiceDiscoveryProvider?.Type)
.WithToken(globalConfiguration?.ServiceDiscoveryProvider?.Token)
.Build();
}
}

View File

@ -5,5 +5,6 @@ namespace Ocelot.Configuration.File
public string Host {get;set;}
public int Port { get; set; }
public string Type { get; set; }
public string Token { get; set; }
}
}

View File

@ -4,8 +4,8 @@ using System.Threading.Tasks;
using Consul;
using Newtonsoft.Json;
using Ocelot.Configuration.File;
using Ocelot.Infrastructure.Consul;
using Ocelot.Responses;
using Ocelot.ServiceDiscovery;
using Ocelot.ServiceDiscovery.Configuration;
namespace Ocelot.Configuration.Repository
@ -13,31 +13,31 @@ namespace Ocelot.Configuration.Repository
public class ConsulFileConfigurationRepository : IFileConfigurationRepository
{
private readonly ConsulClient _consul;
private string _ocelotConfiguration = "OcelotConfiguration";
private const string OcelotConfiguration = "OcelotConfiguration";
private readonly Cache.IOcelotCache<FileConfiguration> _cache;
public ConsulFileConfigurationRepository(Cache.IOcelotCache<FileConfiguration> cache, ServiceProviderConfiguration serviceProviderConfig)
public ConsulFileConfigurationRepository(
Cache.IOcelotCache<FileConfiguration> cache,
ServiceProviderConfiguration serviceProviderConfig,
IConsulClientFactory factory)
{
var consulHost = string.IsNullOrEmpty(serviceProviderConfig?.Host) ? "localhost" : serviceProviderConfig?.Host;
var consulPort = serviceProviderConfig?.Port ?? 8500;
var configuration = new ConsulRegistryConfiguration(consulHost, consulPort, _ocelotConfiguration);
var config = new ConsulRegistryConfiguration(consulHost, consulPort, OcelotConfiguration, serviceProviderConfig?.Token);
_cache = cache;
_consul = new ConsulClient(c =>
{
c.Address = new Uri($"http://{configuration.HostName}:{configuration.Port}");
});
_consul = factory.Get(config);
}
public async Task<Response<FileConfiguration>> Get()
{
var config = _cache.Get(_ocelotConfiguration, _ocelotConfiguration);
var config = _cache.Get(OcelotConfiguration, OcelotConfiguration);
if (config != null)
{
return new OkResponse<FileConfiguration>(config);
}
var queryResult = await _consul.KV.Get(_ocelotConfiguration);
var queryResult = await _consul.KV.Get(OcelotConfiguration);
if (queryResult.Response == null)
{
@ -59,7 +59,7 @@ namespace Ocelot.Configuration.Repository
var bytes = Encoding.UTF8.GetBytes(json);
var kvPair = new KVPair(_ocelotConfiguration)
var kvPair = new KVPair(OcelotConfiguration)
{
Value = bytes
};
@ -68,7 +68,7 @@ namespace Ocelot.Configuration.Repository
if (result.Response)
{
_cache.AddAndDelete(_ocelotConfiguration, ocelotConfiguration, TimeSpan.FromSeconds(3), _ocelotConfiguration);
_cache.AddAndDelete(OcelotConfiguration, ocelotConfiguration, TimeSpan.FromSeconds(3), OcelotConfiguration);
return new OkResponse();
}

View File

@ -2,15 +2,17 @@
{
public class ServiceProviderConfiguration
{
public ServiceProviderConfiguration(string type, string host, int port)
public ServiceProviderConfiguration(string type, string host, int port, string token)
{
Host = host;
Port = port;
Token = token;
Type = type;
}
public string Host { get; private set; }
public int Port { get; private set; }
public string Type { get; private set; }
public string Host { get; }
public int Port { get; }
public string Type { get; }
public string Token { get; }
}
}

View File

@ -53,6 +53,7 @@ namespace Ocelot.DependencyInjection
using System.Net.Http;
using Butterfly.Client.AspNetCore;
using Ocelot.Infrastructure;
using Ocelot.Infrastructure.Consul;
public class OcelotBuilder : IOcelotBuilder
{
@ -152,6 +153,7 @@ namespace Ocelot.DependencyInjection
_services.TryAddSingleton<IConsulPollerConfiguration, InMemoryConsulPollerConfiguration>();
_services.TryAddSingleton<IAddHeadersToResponse, AddHeadersToResponse>();
_services.TryAddSingleton<IPlaceholders, Placeholders>();
_services.TryAddSingleton<IConsulClientFactory, ConsulClientFactory>();
}
public IOcelotAdministrationBuilder AddAdministration(string path, string secret)
@ -236,10 +238,12 @@ namespace Ocelot.DependencyInjection
{
var serviceDiscoveryPort = _configurationRoot.GetValue("GlobalConfiguration:ServiceDiscoveryProvider:Port", 0);
var serviceDiscoveryHost = _configurationRoot.GetValue("GlobalConfiguration:ServiceDiscoveryProvider:Host", string.Empty);
var serviceDiscoveryToken = _configurationRoot.GetValue("GlobalConfiguration:ServiceDiscoveryProvider:Token", string.Empty);
var config = new ServiceProviderConfigurationBuilder()
.WithServiceDiscoveryProviderPort(serviceDiscoveryPort)
.WithServiceDiscoveryProviderHost(serviceDiscoveryHost)
.WithPort(serviceDiscoveryPort)
.WithHost(serviceDiscoveryHost)
.WithToken(serviceDiscoveryToken)
.Build();
_services.AddSingleton<ServiceProviderConfiguration>(config);

View File

@ -0,0 +1,22 @@
using System;
using Consul;
using Ocelot.ServiceDiscovery.Configuration;
namespace Ocelot.Infrastructure.Consul
{
public class ConsulClientFactory : IConsulClientFactory
{
public ConsulClient Get(ConsulRegistryConfiguration config)
{
return new ConsulClient(c =>
{
c.Address = new Uri($"http://{config.Host}:{config.Port}");
if (!string.IsNullOrEmpty(config?.Token))
{
c.Token = config.Token;
}
});
}
}
}

View File

@ -0,0 +1,10 @@
using Consul;
using Ocelot.ServiceDiscovery.Configuration;
namespace Ocelot.Infrastructure.Consul
{
public interface IConsulClientFactory
{
ConsulClient Get(ConsulRegistryConfiguration config);
}
}

View File

@ -26,27 +26,27 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Butterfly.Client.AspNetCore" Version="0.0.8" />
<PackageReference Include="FluentValidation" Version="7.2.1" />
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.DiagnosticAdapter" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.0.0" />
<PackageReference Include="FluentValidation" Version="7.5.2" />
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="2.4.0" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.6" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.DiagnosticAdapter" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.0.1" />
<PackageReference Include="StyleCop.Analyzers" Version="1.0.2">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.0" />
<PackageReference Include="CacheManager.Core" Version="1.1.1" />
<PackageReference Include="CacheManager.Microsoft.Extensions.Configuration" Version="1.1.1" />
<PackageReference Include="CacheManager.Microsoft.Extensions.Logging" Version="1.1.1" />
<PackageReference Include="Consul" Version="0.7.2.3" />
<PackageReference Include="Polly" Version="5.3.1" />
<PackageReference Include="IdentityServer4" Version="2.0.2" />
<PackageReference Include="CacheManager.Core" Version="1.1.2" />
<PackageReference Include="CacheManager.Microsoft.Extensions.Configuration" Version="1.1.2" />
<PackageReference Include="CacheManager.Microsoft.Extensions.Logging" Version="1.1.2" />
<PackageReference Include="Consul" Version="0.7.2.4" />
<PackageReference Include="Polly" Version="5.8.0" />
<PackageReference Include="IdentityServer4" Version="2.1.3" />
<PackageReference Include="Rafty" Version="0.4.2" />
</ItemGroup>
</Project>

View File

@ -2,15 +2,17 @@ namespace Ocelot.ServiceDiscovery.Configuration
{
public class ConsulRegistryConfiguration
{
public ConsulRegistryConfiguration(string hostName, int port, string keyOfServiceInConsul)
public ConsulRegistryConfiguration(string host, int port, string keyOfServiceInConsul, string token)
{
HostName = hostName;
Host = host;
Port = port;
KeyOfServiceInConsul = keyOfServiceInConsul;
Token = token;
}
public string KeyOfServiceInConsul { get; private set; }
public string HostName { get; private set; }
public int Port { get; private set; }
public string KeyOfServiceInConsul { get; }
public string Host { get; }
public int Port { get; }
public string Token { get; }
}
}

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Consul;
using Ocelot.Infrastructure.Consul;
using Ocelot.Infrastructure.Extensions;
using Ocelot.Logging;
using Ocelot.ServiceDiscovery.Configuration;
@ -12,30 +13,27 @@ namespace Ocelot.ServiceDiscovery.Providers
{
public class ConsulServiceDiscoveryProvider : IServiceDiscoveryProvider
{
private readonly ConsulRegistryConfiguration _consulConfig;
private readonly ConsulRegistryConfiguration _config;
private readonly IOcelotLogger _logger;
private readonly ConsulClient _consul;
private const string VersionPrefix = "version-";
public ConsulServiceDiscoveryProvider(ConsulRegistryConfiguration consulRegistryConfiguration, IOcelotLoggerFactory factory)
public ConsulServiceDiscoveryProvider(ConsulRegistryConfiguration config, IOcelotLoggerFactory factory, IConsulClientFactory clientFactory)
{;
_logger = factory.CreateLogger<ConsulServiceDiscoveryProvider>();
var consulHost = string.IsNullOrEmpty(consulRegistryConfiguration?.HostName) ? "localhost" : consulRegistryConfiguration.HostName;
var consulHost = string.IsNullOrEmpty(config?.Host) ? "localhost" : config.Host;
var consulPort = consulRegistryConfiguration?.Port ?? 8500;
var consulPort = config?.Port ?? 8500;
_consulConfig = new ConsulRegistryConfiguration(consulHost, consulPort, consulRegistryConfiguration?.KeyOfServiceInConsul);
_config = new ConsulRegistryConfiguration(consulHost, consulPort, config?.KeyOfServiceInConsul, config?.Token);
_consul = new ConsulClient(config =>
{
config.Address = new Uri($"http://{_consulConfig.HostName}:{_consulConfig.Port}");
});
_consul = clientFactory.Get(_config);
}
public async Task<List<Service>> Get()
{
var queryResult = await _consul.Health.Service(_consulConfig.KeyOfServiceInConsul, string.Empty, true);
var queryResult = await _consul.Health.Service(_config.KeyOfServiceInConsul, string.Empty, true);
var services = new List<Service>();

View File

@ -1,5 +1,6 @@
using System.Collections.Generic;
using Ocelot.Configuration;
using Ocelot.Infrastructure.Consul;
using Ocelot.Logging;
using Ocelot.ServiceDiscovery.Configuration;
using Ocelot.ServiceDiscovery.Providers;
@ -10,10 +11,12 @@ namespace Ocelot.ServiceDiscovery
public class ServiceDiscoveryProviderFactory : IServiceDiscoveryProviderFactory
{
private readonly IOcelotLoggerFactory _factory;
private readonly IConsulClientFactory _clientFactory;
public ServiceDiscoveryProviderFactory(IOcelotLoggerFactory factory)
public ServiceDiscoveryProviderFactory(IOcelotLoggerFactory factory, IConsulClientFactory clientFactory)
{
_factory = factory;
_clientFactory = clientFactory;
}
public IServiceDiscoveryProvider Get(ServiceProviderConfiguration serviceConfig, DownstreamReRoute reRoute)
@ -43,8 +46,8 @@ namespace Ocelot.ServiceDiscovery
return new ServiceFabricServiceDiscoveryProvider(config);
}
var consulRegistryConfiguration = new ConsulRegistryConfiguration(serviceConfig.Host, serviceConfig.Port, serviceName);
return new ConsulServiceDiscoveryProvider(consulRegistryConfiguration, _factory);
var consulRegistryConfiguration = new ConsulRegistryConfiguration(serviceConfig.Host, serviceConfig.Port, serviceName, serviceConfig.Token);
return new ConsulServiceDiscoveryProvider(consulRegistryConfiguration, _factory, _clientFactory);
}
}
}

View File

@ -104,7 +104,7 @@ namespace Ocelot.AcceptanceTests
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Tom"))
.BDDfy();
var commandOnAllStateMachines = WaitFor(5000).Until(() => _butterflyCalled == 4);
var commandOnAllStateMachines = WaitFor(10000).Until(() => _butterflyCalled == 4);
commandOnAllStateMachines.ShouldBeTrue();
}

View File

@ -16,7 +16,6 @@ namespace Ocelot.AcceptanceTests
public class HeaderTests : IDisposable
{
private IWebHost _builder;
private string _cookieValue;
private int _count;
private readonly Steps _steps;
@ -278,26 +277,27 @@ namespace Ocelot.AcceptanceTests
.Configure(app =>
{
app.UsePathBase(basePath);
app.Run(async context =>
app.Run(context =>
{
if(_count == 0)
if (_count == 0)
{
context.Response.Cookies.Append("test", "0");
_count++;
context.Response.StatusCode = statusCode;
return;
return Task.CompletedTask;
}
if(context.Request.Cookies.TryGetValue("test", out var cookieValue) || context.Request.Headers.TryGetValue("Set-Cookie", out var headerValue))
if (context.Request.Cookies.TryGetValue("test", out var cookieValue) || context.Request.Headers.TryGetValue("Set-Cookie", out var headerValue))
{
if(cookieValue == "0" || headerValue == "test=1; path=/")
if (cookieValue == "0" || headerValue == "test=1; path=/")
{
context.Response.StatusCode = statusCode;
return;
return Task.CompletedTask;
}
}
context.Response.StatusCode = 500;
return Task.CompletedTask;
});
})
.Build();

View File

@ -27,26 +27,26 @@
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="CacheManager.Serialization.Json" Version="1.1.1" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0-preview-20171031-01" />
<PackageReference Include="CacheManager.Serialization.Json" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.6" />
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.0.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.0.2">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="2.0.1" />
<PackageReference Include="Microsoft.DotNet.InternalAbstractions" Version="1.0.500-preview2-1-003177" />
<PackageReference Include="Shouldly" Version="3.0.0-beta0003" />
<PackageReference Include="Shouldly" Version="3.0.0" />
<PackageReference Include="TestStack.BDDfy" Version="4.3.2" />
<PackageReference Include="Consul" Version="0.7.2.3" />
<PackageReference Include="Consul" Version="0.7.2.4" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="Butterfly.Client.AspNetCore" Version="0.0.8" />
</ItemGroup>

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using Consul;
using Microsoft.AspNetCore.Builder;
@ -22,9 +23,10 @@ namespace Ocelot.AcceptanceTests
private readonly List<ServiceEntry> _serviceEntries;
private int _counterOne;
private int _counterTwo;
private static readonly object _syncLock = new object();
private static readonly object SyncLock = new object();
private IWebHost _builder;
private string _downstreamPath;
private string _receivedToken;
public ServiceDiscoveryTests()
{
@ -100,13 +102,13 @@ namespace Ocelot.AcceptanceTests
.BDDfy();
}
//test from issue 213
//test from issue #213
[Fact]
public void should_handle_request_to_consul_for_downstream_service_and_make_request()
{
var consulPort = 8505;
var serviceName = "web";
var downstreamServiceOneUrl = "http://localhost:8080";
const int consulPort = 8505;
const string serviceName = "web";
const string downstreamServiceOneUrl = "http://localhost:8080";
var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}";
var serviceEntryOne = new ServiceEntry()
{
@ -116,7 +118,7 @@ namespace Ocelot.AcceptanceTests
Address = "localhost",
Port = 8080,
ID = "web_90_0_2_224_8080",
Tags = new string[1]{"version-v1"}
Tags = new[] {"version-v1"}
},
};
@ -145,14 +147,73 @@ namespace Ocelot.AcceptanceTests
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn(downstreamServiceOneUrl, "/api/home", 200, "Hello from Laura"))
.And(x => x.GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, serviceName))
.And(x => x.GivenTheServicesAreRegisteredWithConsul(serviceEntryOne))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/home"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
this.Given(x => x.GivenThereIsAServiceRunningOn(downstreamServiceOneUrl, "/api/home", 200, "Hello from Laura"))
.And(x => x.GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, serviceName))
.And(x => x.GivenTheServicesAreRegisteredWithConsul(serviceEntryOne))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/home"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
//test from issue #295
[Fact]
public void should_use_token_to_make_request_to_consul()
{
var token = "abctoken";
var consulPort = 8515;
var serviceName = "web";
var downstreamServiceOneUrl = "http://localhost:8081";
var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}";
var serviceEntryOne = new ServiceEntry()
{
Service = new AgentService()
{
Service = serviceName,
Address = "localhost",
Port = 8081,
ID = "web_90_0_2_224_8080",
Tags = new[] { "version-v1" }
},
};
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/api/home",
DownstreamScheme = "http",
UpstreamPathTemplate = "/home",
UpstreamHttpMethod = new List<string> { "Get", "Options" },
ServiceName = serviceName,
LoadBalancer = "LeastConnection",
UseServiceDiscovery = true,
}
},
GlobalConfiguration = new FileGlobalConfiguration()
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Host = "localhost",
Port = consulPort,
Token = token
}
}
};
this.Given(_ => GivenThereIsAServiceRunningOn(downstreamServiceOneUrl, "/api/home", 200, "Hello from Laura"))
.And(_ => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, serviceName))
.And(_ => GivenTheServicesAreRegisteredWithConsul(serviceEntryOne))
.And(_ => _steps.GivenThereIsAConfiguration(configuration))
.And(_ => _steps.GivenOcelotIsRunning())
.When(_ => _steps.WhenIGetUrlOnTheApiGateway("/home"))
.Then(_ => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(_ => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.And(_ => _receivedToken.ShouldBe(token))
.BDDfy();
}
@ -289,6 +350,11 @@ namespace Ocelot.AcceptanceTests
{
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);
}
});
@ -312,8 +378,8 @@ namespace Ocelot.AcceptanceTests
{
try
{
var response = string.Empty;
lock (_syncLock)
string response;
lock (SyncLock)
{
_counterOne++;
response = _counterOne.ToString();
@ -321,7 +387,7 @@ namespace Ocelot.AcceptanceTests
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(response);
}
catch (System.Exception exception)
catch (Exception exception)
{
await context.Response.WriteAsync(exception.StackTrace);
}
@ -346,8 +412,8 @@ namespace Ocelot.AcceptanceTests
{
try
{
var response = string.Empty;
lock (_syncLock)
string response;
lock (SyncLock)
{
_counterTwo++;
response = _counterTwo.ToString();
@ -356,7 +422,7 @@ namespace Ocelot.AcceptanceTests
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(response);
}
catch (System.Exception exception)
catch (Exception exception)
{
await context.Response.WriteAsync(exception.StackTrace);
}

View File

@ -1,722 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using CacheManager.Core;
using IdentityServer4.AccessTokenValidation;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Ocelot.Configuration.File;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
using Shouldly;
using ConfigurationBuilder = Microsoft.Extensions.Configuration.ConfigurationBuilder;
using Ocelot.AcceptanceTests.Caching;
<<<<<<< HEAD
using static Ocelot.AcceptanceTests.HttpDelegatingHandlersTests;
||||||| merged common ancestors
=======
using System.IO.Compression;
using System.Text;
>>>>>>> develop
namespace Ocelot.AcceptanceTests
{
public class Steps : IDisposable
{
private TestServer _ocelotServer;
private HttpClient _ocelotClient;
private HttpResponseMessage _response;
private HttpContent _postContent;
private BearerToken _token;
public HttpClient OcelotClient => _ocelotClient;
public string RequestIdKey = "OcRequestId";
private readonly Random _random;
private IWebHostBuilder _webHostBuilder;
public Steps()
{
_random = new Random();
}
public void GivenThereIsAConfiguration(FileConfiguration fileConfiguration)
{
var configurationPath = TestConfiguration.ConfigurationPath;
var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration);
if (File.Exists(configurationPath))
{
File.Delete(configurationPath);
}
File.WriteAllText(configurationPath, jsonConfiguration);
}
public void GivenThereIsAConfiguration(FileConfiguration fileConfiguration, string configurationPath)
{
var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration);
if (File.Exists(configurationPath))
{
File.Delete(configurationPath);
}
File.WriteAllText(configurationPath, jsonConfiguration);
}
/// <summary>
/// This is annoying cos it should be in the constructor but we need to set up the file before calling startup so its a step.
/// </summary>
public void GivenOcelotIsRunning()
{
_webHostBuilder = new WebHostBuilder();
_webHostBuilder
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddJsonFile("configuration.json");
config.AddEnvironmentVariables();
})
.ConfigureServices(s =>
{
s.AddOcelot();
})
.Configure(app =>
{
app.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}
internal void GivenOcelotIsRunningUsingButterfly(string butterflyUrl)
{
_webHostBuilder = new WebHostBuilder();
_webHostBuilder
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddJsonFile("configuration.json");
config.AddEnvironmentVariables();
})
.ConfigureServices(s =>
{
s.AddOcelot()
.AddOpenTracing(option =>
{
//this is the url that the butterfly collector server is running on...
option.CollectorUrl = butterflyUrl;
option.Service = "Ocelot";
});
})
.Configure(app =>
{
app.Use(async (context, next) =>
{
await next.Invoke();
});
app.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}
/*
public void GivenIHaveAddedXForwardedForHeader(string value)
{
_ocelotClient.DefaultRequestHeaders.TryAddWithoutValidation("X-Forwarded-For", value);
}*/
public void GivenOcelotIsRunningWithMiddleareBeforePipeline<T>(Func<object, Task> callback)
{
_webHostBuilder = new WebHostBuilder();
_webHostBuilder
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddJsonFile("configuration.json");
config.AddEnvironmentVariables();
})
.ConfigureServices(s =>
{
s.AddOcelot();
})
.Configure(app =>
{
app.UseMiddleware<T>(callback);
app.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}
public void GivenOcelotIsRunningWithHandlersRegisteredInDi<TOne, TWo>()
where TOne : DelegatingHandler
where TWo : DelegatingHandler
{
_webHostBuilder = new WebHostBuilder();
_webHostBuilder
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddJsonFile("configuration.json");
config.AddEnvironmentVariables();
})
.ConfigureServices(s =>
{
s.AddSingleton(_webHostBuilder);
s.AddOcelot()
.AddDelegatingHandler<TOne>()
.AddDelegatingHandler<TWo>();
})
.Configure(a =>
{
a.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}
public void GivenOcelotIsRunningWithHandlersRegisteredInDi<TOne>(FakeDependency dependency)
where TOne : DelegatingHandler
{
_webHostBuilder = new WebHostBuilder();
_webHostBuilder
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddJsonFile("configuration.json");
config.AddEnvironmentVariables();
})
.ConfigureServices(s =>
{
s.AddSingleton(_webHostBuilder);
s.AddSingleton<FakeDependency>(dependency);
s.AddOcelot()
.AddDelegatingHandler<TOne>();
})
.Configure(a =>
{
a.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}
/// <summary>
/// This is annoying cos it should be in the constructor but we need to set up the file before calling startup so its a step.
/// </summary>
public void GivenOcelotIsRunning(Action<IdentityServerAuthenticationOptions> options, string authenticationProviderKey)
{
_webHostBuilder = new WebHostBuilder();
_webHostBuilder
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddJsonFile("configuration.json");
config.AddEnvironmentVariables();
})
.ConfigureServices(s =>
{
s.AddOcelot();
s.AddAuthentication()
.AddIdentityServerAuthentication(authenticationProviderKey, options);
})
.Configure(app =>
{
app.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}
public void ThenTheResponseHeaderIs(string key, string value)
{
var header = _response.Headers.GetValues(key);
header.First().ShouldBe(value);
}
public void GivenOcelotIsRunningUsingJsonSerializedCache()
{
_webHostBuilder = new WebHostBuilder();
_webHostBuilder
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddJsonFile("configuration.json");
config.AddEnvironmentVariables();
})
.ConfigureServices(s =>
{
s.AddOcelot()
.AddCacheManager((x) =>
{
x.WithMicrosoftLogging(log =>
{
log.AddConsole(LogLevel.Debug);
})
.WithJsonSerializer()
.WithHandle(typeof(InMemoryJsonHandle<>));
});
})
.Configure(app =>
{
app.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}
public void GivenOcelotIsRunningUsingConsulToStoreConfig()
{
_webHostBuilder = new WebHostBuilder();
_webHostBuilder
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddJsonFile("configuration.json");
config.AddEnvironmentVariables();
})
.ConfigureServices(s =>
{
s.AddOcelot().AddStoreOcelotConfigurationInConsul();
})
.Configure(app =>
{
app.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}
public void GivenOcelotIsRunningUsingConsulToStoreConfigAndJsonSerializedCache()
{
_webHostBuilder = new WebHostBuilder();
_webHostBuilder
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddJsonFile("configuration.json");
config.AddEnvironmentVariables();
})
.ConfigureServices(s =>
{
s.AddOcelot()
.AddCacheManager((x) =>
{
x.WithMicrosoftLogging(log =>
{
log.AddConsole(LogLevel.Debug);
})
.WithJsonSerializer()
.WithHandle(typeof(InMemoryJsonHandle<>));
})
.AddStoreOcelotConfigurationInConsul();
})
.Configure(app =>
{
app.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}
internal void ThenTheResponseShouldBe(FileConfiguration expecteds)
{
var response = JsonConvert.DeserializeObject<FileConfiguration>(_response.Content.ReadAsStringAsync().Result);
response.GlobalConfiguration.RequestIdKey.ShouldBe(expecteds.GlobalConfiguration.RequestIdKey);
response.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Host);
response.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Port);
for (var i = 0; i < response.ReRoutes.Count; i++)
{
for (var j = 0; j < response.ReRoutes[i].DownstreamHostAndPorts.Count; j++)
{
var result = response.ReRoutes[i].DownstreamHostAndPorts[j];
var expected = expecteds.ReRoutes[i].DownstreamHostAndPorts[j];
result.Host.ShouldBe(expected.Host);
result.Port.ShouldBe(expected.Port);
}
response.ReRoutes[i].DownstreamPathTemplate.ShouldBe(expecteds.ReRoutes[i].DownstreamPathTemplate);
response.ReRoutes[i].DownstreamScheme.ShouldBe(expecteds.ReRoutes[i].DownstreamScheme);
response.ReRoutes[i].UpstreamPathTemplate.ShouldBe(expecteds.ReRoutes[i].UpstreamPathTemplate);
response.ReRoutes[i].UpstreamHttpMethod.ShouldBe(expecteds.ReRoutes[i].UpstreamHttpMethod);
}
}
/// <summary>
/// This is annoying cos it should be in the constructor but we need to set up the file before calling startup so its a step.
/// </summary>
public void GivenOcelotIsRunning(OcelotPipelineConfiguration ocelotPipelineConfig)
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile("configuration.json")
.AddEnvironmentVariables();
var configuration = builder.Build();
_webHostBuilder = new WebHostBuilder();
_webHostBuilder.ConfigureServices(s =>
{
s.AddSingleton(_webHostBuilder);
});
_ocelotServer = new TestServer(_webHostBuilder
.UseConfiguration(configuration)
.ConfigureServices(s =>
{
Action<ConfigurationBuilderCachePart> settings = (x) =>
{
x.WithMicrosoftLogging(log =>
{
log.AddConsole(LogLevel.Debug);
})
.WithDictionaryHandle();
};
s.AddOcelot(configuration);
})
.ConfigureLogging(l =>
{
l.AddConsole();
l.AddDebug();
})
.Configure(a =>
{
a.UseOcelot(ocelotPipelineConfig).Wait();
}));
_ocelotClient = _ocelotServer.CreateClient();
}
public void GivenIHaveAddedATokenToMyRequest()
{
_ocelotClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _token.AccessToken);
}
public void GivenIHaveAToken(string url)
{
var tokenUrl = $"{url}/connect/token";
var formData = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("client_id", "client"),
new KeyValuePair<string, string>("client_secret", "secret"),
new KeyValuePair<string, string>("scope", "api"),
new KeyValuePair<string, string>("username", "test"),
new KeyValuePair<string, string>("password", "test"),
new KeyValuePair<string, string>("grant_type", "password")
};
var content = new FormUrlEncodedContent(formData);
using (var httpClient = new HttpClient())
{
var response = httpClient.PostAsync(tokenUrl, content).Result;
var responseContent = response.Content.ReadAsStringAsync().Result;
response.EnsureSuccessStatusCode();
_token = JsonConvert.DeserializeObject<BearerToken>(responseContent);
}
}
public void GivenIHaveATokenForApiReadOnlyScope(string url)
{
var tokenUrl = $"{url}/connect/token";
var formData = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("client_id", "client"),
new KeyValuePair<string, string>("client_secret", "secret"),
new KeyValuePair<string, string>("scope", "api.readOnly"),
new KeyValuePair<string, string>("username", "test"),
new KeyValuePair<string, string>("password", "test"),
new KeyValuePair<string, string>("grant_type", "password")
};
var content = new FormUrlEncodedContent(formData);
using (var httpClient = new HttpClient())
{
var response = httpClient.PostAsync(tokenUrl, content).Result;
var responseContent = response.Content.ReadAsStringAsync().Result;
response.EnsureSuccessStatusCode();
_token = JsonConvert.DeserializeObject<BearerToken>(responseContent);
}
}
public void GivenIHaveATokenForApi2(string url)
{
var tokenUrl = $"{url}/connect/token";
var formData = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("client_id", "client"),
new KeyValuePair<string, string>("client_secret", "secret"),
new KeyValuePair<string, string>("scope", "api2"),
new KeyValuePair<string, string>("username", "test"),
new KeyValuePair<string, string>("password", "test"),
new KeyValuePair<string, string>("grant_type", "password")
};
var content = new FormUrlEncodedContent(formData);
using (var httpClient = new HttpClient())
{
var response = httpClient.PostAsync(tokenUrl, content).Result;
var responseContent = response.Content.ReadAsStringAsync().Result;
response.EnsureSuccessStatusCode();
_token = JsonConvert.DeserializeObject<BearerToken>(responseContent);
}
}
public void GivenIHaveAnOcelotToken(string adminPath)
{
var tokenUrl = $"{adminPath}/connect/token";
var formData = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("client_id", "admin"),
new KeyValuePair<string, string>("client_secret", "secret"),
new KeyValuePair<string, string>("scope", "admin"),
new KeyValuePair<string, string>("username", "admin"),
new KeyValuePair<string, string>("password", "admin"),
new KeyValuePair<string, string>("grant_type", "password")
};
var content = new FormUrlEncodedContent(formData);
var response = _ocelotClient.PostAsync(tokenUrl, content).Result;
var responseContent = response.Content.ReadAsStringAsync().Result;
response.EnsureSuccessStatusCode();
_token = JsonConvert.DeserializeObject<BearerToken>(responseContent);
}
public void VerifyIdentiryServerStarted(string url)
{
using (var httpClient = new HttpClient())
{
var response = httpClient.GetAsync($"{url}/.well-known/openid-configuration").Result;
response.EnsureSuccessStatusCode();
}
}
public void WhenIGetUrlOnTheApiGateway(string url)
{
_response = _ocelotClient.GetAsync(url).Result;
}
public void GivenIAddAHeader(string key, string value)
{
_ocelotClient.DefaultRequestHeaders.Add(key, value);
}
public void WhenIGetUrlOnTheApiGatewayMultipleTimes(string url, int times)
{
var tasks = new Task[times];
for (int i = 0; i < times; i++)
{
var urlCopy = url;
tasks[i] = GetForServiceDiscoveryTest(urlCopy);
Thread.Sleep(_random.Next(40, 60));
}
Task.WaitAll(tasks);
}
private async Task GetForServiceDiscoveryTest(string url)
{
var response = await _ocelotClient.GetAsync(url);
var content = await response.Content.ReadAsStringAsync();
int count = int.Parse(content);
count.ShouldBeGreaterThan(0);
}
public void WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit(string url, int times)
{
for (int i = 0; i < times; i++)
{
var clientId = "ocelotclient1";
var request = new HttpRequestMessage(new HttpMethod("GET"), url);
request.Headers.Add("ClientId", clientId);
_response = _ocelotClient.SendAsync(request).Result;
}
}
public void WhenIGetUrlOnTheApiGateway(string url, string requestId)
{
_ocelotClient.DefaultRequestHeaders.TryAddWithoutValidation(RequestIdKey, requestId);
_response = _ocelotClient.GetAsync(url).Result;
}
public void WhenIPostUrlOnTheApiGateway(string url)
{
_response = _ocelotClient.PostAsync(url, _postContent).Result;
}
public void GivenThePostHasContent(string postcontent)
{
_postContent = new StringContent(postcontent);
}
public void GivenThePostHasGzipContent(object input)
{
string json = JsonConvert.SerializeObject(input);
byte[] jsonBytes = Encoding.UTF8.GetBytes(json);
MemoryStream ms = new MemoryStream();
using (GZipStream gzip = new GZipStream(ms, CompressionMode.Compress, true))
{
gzip.Write(jsonBytes, 0, jsonBytes.Length);
}
ms.Position = 0;
StreamContent content = new StreamContent(ms);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
content.Headers.ContentEncoding.Add("gzip");
_postContent = content;
}
public void ThenTheResponseBodyShouldBe(string expectedBody)
{
_response.Content.ReadAsStringAsync().Result.ShouldBe(expectedBody);
}
public void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode)
{
_response.StatusCode.ShouldBe(expectedHttpStatusCode);
}
public void ThenTheStatusCodeShouldBe(int expectedHttpStatusCode)
{
var responseStatusCode = (int)_response.StatusCode;
responseStatusCode.ShouldBe(expectedHttpStatusCode);
}
public void Dispose()
{
_ocelotClient?.Dispose();
_ocelotServer?.Dispose();
}
public void ThenTheRequestIdIsReturned()
{
_response.Headers.GetValues(RequestIdKey).First().ShouldNotBeNullOrEmpty();
}
public void ThenTheRequestIdIsReturned(string expected)
{
_response.Headers.GetValues(RequestIdKey).First().ShouldBe(expected);
}
public void ThenTheContentLengthIs(int expected)
{
_response.Content.Headers.ContentLength.ShouldBe(expected);
}
public void WhenIMakeLotsOfDifferentRequestsToTheApiGateway()
{
int numberOfRequests = 100;
var aggregateUrl = "/";
var aggregateExpected = "{\"Laura\":{Hello from Laura},\"Tom\":{Hello from Tom}}";
var tomUrl = "/tom";
var tomExpected = "{Hello from Tom}";
var lauraUrl = "/laura";
var lauraExpected = "{Hello from Laura}";
var random = new Random();
var aggregateTasks = new Task[numberOfRequests];
for (int i = 0; i < numberOfRequests; i++)
{
aggregateTasks[i] = Fire(aggregateUrl, aggregateExpected, random);
}
var tomTasks = new Task[numberOfRequests];
for (int i = 0; i < numberOfRequests; i++)
{
tomTasks[i] = Fire(tomUrl, tomExpected, random);
}
var lauraTasks = new Task[numberOfRequests];
for (int i = 0; i < numberOfRequests; i++)
{
lauraTasks[i] = Fire(lauraUrl, lauraExpected, random);
}
Task.WaitAll(lauraTasks);
Task.WaitAll(tomTasks);
Task.WaitAll(aggregateTasks);
}
private async Task Fire(string url, string expectedBody, Random random)
{
var request = new HttpRequestMessage(new HttpMethod("GET"), url);
await Task.Delay(random.Next(0, 2));
var response = await _ocelotClient.SendAsync(request);
var content = await response.Content.ReadAsStringAsync();
content.ShouldBe(expectedBody);
}
}
}

View File

@ -37,7 +37,7 @@ namespace Ocelot.AcceptanceTests
}
[Fact]
public async Task should_proxy_websocket_input_to_downstream_service()
public void should_proxy_websocket_input_to_downstream_service()
{
var downstreamPort = 5001;
var downstreamHost = "localhost";
@ -72,7 +72,7 @@ namespace Ocelot.AcceptanceTests
}
[Fact]
public async Task should_proxy_websocket_input_to_downstream_service_and_use_load_balancer()
public void should_proxy_websocket_input_to_downstream_service_and_use_load_balancer()
{
var downstreamPort = 5005;
var downstreamHost = "localhost";
@ -116,7 +116,7 @@ namespace Ocelot.AcceptanceTests
}
[Fact]
public async Task should_proxy_websocket_input_to_downstream_service_and_use_service_discovery_and_load_balancer()
public void should_proxy_websocket_input_to_downstream_service_and_use_service_discovery_and_load_balancer()
{
var downstreamPort = 5007;
var downstreamHost = "localhost";
@ -274,7 +274,6 @@ namespace Ocelot.AcceptanceTests
{
_firstRecieved.Add(Encoding.UTF8.GetString(buffer, 0, result.Count));
}
else if (result.MessageType == WebSocketMessageType.Close)
{
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
@ -321,7 +320,6 @@ namespace Ocelot.AcceptanceTests
{
_secondRecieved.Add(Encoding.UTF8.GetString(buffer, 0, result.Count));
}
else if (result.MessageType == WebSocketMessageType.Close)
{
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
@ -333,7 +331,6 @@ namespace Ocelot.AcceptanceTests
await Task.WhenAll(sending, receiving);
}
private async Task StartFakeDownstreamService(string url, string path)
{
_firstDownstreamHost = new WebHostBuilder()
@ -380,7 +377,6 @@ namespace Ocelot.AcceptanceTests
await _firstDownstreamHost.StartAsync();
}
private async Task StartSecondFakeDownstreamService(string url, string path)
{
_secondDownstreamHost = new WebHostBuilder()
@ -427,7 +423,6 @@ namespace Ocelot.AcceptanceTests
await _secondDownstreamHost.StartAsync();
}
private async Task Echo(WebSocket webSocket)
{
try

View File

@ -19,7 +19,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.10.12" />
<PackageReference Include="BenchmarkDotNet" Version="0.10.13" />
<PackageReference Include="StyleCop.Analyzers" Version="1.0.2">
<PrivateAssets>all</PrivateAssets>
</PackageReference>

View File

@ -25,26 +25,26 @@
<ProjectReference Include="..\..\src\Ocelot\Ocelot.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0-preview-20171031-01" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.6" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.0.2">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.0.1" />
<PackageReference Include="Microsoft.DotNet.InternalAbstractions" Version="1.0.500-preview2-1-003177" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="IdentityServer4" Version="2.0.2" />
<PackageReference Include="Shouldly" Version="3.0.0-beta0003" />
<PackageReference Include="IdentityServer4" Version="2.1.3" />
<PackageReference Include="Shouldly" Version="3.0.0" />
<PackageReference Include="TestStack.BDDfy" Version="4.3.2" />
<PackageReference Include="Consul" Version="0.7.2.3" />
<PackageReference Include="Consul" Version="0.7.2.4" />
<PackageReference Include="Rafty" Version="0.4.2" />
<PackageReference Include="Microsoft.Data.SQLite" Version="2.0.0" />
<PackageReference Include="Microsoft.Data.SQLite" Version="2.0.1" />
</ItemGroup>
</Project>

View File

@ -21,19 +21,19 @@
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Ocelot\Ocelot.csproj"/>
<ProjectReference Include="..\..\src\Ocelot\Ocelot.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0"/>
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.0"/>
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.0.0"/>
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0"/>
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0"/>
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.0.0"/>
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.0"/>
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.0.0"/>
<PackageReference Include="Consul" Version="0.7.2.3"/>
<PackageReference Include="Polly" Version="5.3.1"/>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.6" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.0.1" />
<PackageReference Include="Consul" Version="0.7.2.4" />
<PackageReference Include="Polly" Version="5.8.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.0.2">
<PrivateAssets>all</PrivateAssets>
</PackageReference>

View File

@ -10,8 +10,7 @@ namespace Ocelot.UnitTests.Configuration
{
public class ServiceProviderCreatorTests
{
private ServiceProviderConfigurationCreator _creator;
private FileReRoute _reRoute;
private readonly ServiceProviderConfigurationCreator _creator;
private FileGlobalConfiguration _globalConfig;
private ServiceProviderConfiguration _result;
@ -23,36 +22,30 @@ namespace Ocelot.UnitTests.Configuration
[Fact]
public void should_create_service_provider_config()
{
var reRoute = new FileReRoute();
var globalConfig = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{
Host = "127.0.0.1",
Port = 1234,
Type = "ServiceFabric"
Type = "ServiceFabric",
Token = "testtoken"
}
};
var expected = new ServiceProviderConfigurationBuilder()
.WithServiceDiscoveryProviderHost("127.0.0.1")
.WithServiceDiscoveryProviderPort(1234)
.WithServiceDiscoveryProviderType("ServiceFabric")
.WithHost("127.0.0.1")
.WithPort(1234)
.WithType("ServiceFabric")
.WithToken("testtoken")
.Build();
this.Given(x => x.GivenTheFollowingReRoute(reRoute))
.And(x => x.GivenTheFollowingGlobalConfig(globalConfig))
this.Given(x => x.GivenTheFollowingGlobalConfig(globalConfig))
.When(x => x.WhenICreate())
.Then(x => x.ThenTheConfigIs(expected))
.BDDfy();
}
private void GivenTheFollowingReRoute(FileReRoute fileReRoute)
{
_reRoute = fileReRoute;
}
private void GivenTheFollowingGlobalConfig(FileGlobalConfiguration fileGlobalConfig)
{
_globalConfig = fileGlobalConfig;
@ -67,6 +60,8 @@ namespace Ocelot.UnitTests.Configuration
{
_result.Host.ShouldBe(expected.Host);
_result.Port.ShouldBe(expected.Port);
_result.Token.ShouldBe(expected.Token);
_result.Type.ShouldBe(expected.Type);
}
}
}

View File

@ -82,9 +82,9 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator
.Build();
var config = new ServiceProviderConfigurationBuilder()
.WithServiceDiscoveryProviderType("ServiceFabric")
.WithServiceDiscoveryProviderHost("localhost")
.WithServiceDiscoveryProviderPort(19081)
.WithType("ServiceFabric")
.WithHost("localhost")
.WithPort(19081)
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(
@ -118,9 +118,9 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator
.Build());
var config = new ServiceProviderConfigurationBuilder()
.WithServiceDiscoveryProviderType("ServiceFabric")
.WithServiceDiscoveryProviderHost("localhost")
.WithServiceDiscoveryProviderPort(19081)
.WithType("ServiceFabric")
.WithHost("localhost")
.WithPort(19081)
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
@ -148,9 +148,9 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator
.Build());
var config = new ServiceProviderConfigurationBuilder()
.WithServiceDiscoveryProviderType("ServiceFabric")
.WithServiceDiscoveryProviderHost("localhost")
.WithServiceDiscoveryProviderPort(19081)
.WithType("ServiceFabric")
.WithHost("localhost")
.WithPort(19081)
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
@ -178,9 +178,9 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator
.Build());
var config = new ServiceProviderConfigurationBuilder()
.WithServiceDiscoveryProviderType("ServiceFabric")
.WithServiceDiscoveryProviderHost("localhost")
.WithServiceDiscoveryProviderPort(19081)
.WithType("ServiceFabric")
.WithHost("localhost")
.WithPort(19081)
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))

View File

@ -25,7 +25,7 @@ namespace Ocelot.UnitTests.LoadBalancer
{
_factory = new Mock<ILoadBalancerFactory>();
_loadBalancerHouse = new LoadBalancerHouse(_factory.Object);
_serviceProviderConfig = new ServiceProviderConfiguration("myType","myHost",123);
_serviceProviderConfig = new ServiceProviderConfiguration("myType","myHost",123, string.Empty);
}
[Fact]

View File

@ -35,23 +35,23 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0-preview-20171031-01" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.6" />
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.0.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.0.2">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<PackageReference Include="Microsoft.DotNet.InternalAbstractions" Version="1.0.500-preview2-1-003177" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.0.0" />
<PackageReference Include="Moq" Version="4.7.142" />
<PackageReference Include="Shouldly" Version="3.0.0-beta0003" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.1" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.0.1" />
<PackageReference Include="Moq" Version="4.8.2" />
<PackageReference Include="Shouldly" Version="3.0.0" />
<PackageReference Include="TestStack.BDDfy" Version="4.3.2" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="Butterfly.Client.AspNetCore" Version="0.0.8" />

View File

@ -1,14 +1,14 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
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;
using Ocelot.ServiceDiscovery.Configuration;
using Ocelot.ServiceDiscovery.Providers;
using Ocelot.Values;
@ -22,14 +22,16 @@ namespace Ocelot.UnitTests.ServiceDiscovery
{
private IWebHost _fakeConsulBuilder;
private readonly List<ServiceEntry> _serviceEntries;
private readonly ConsulServiceDiscoveryProvider _provider;
private ConsulServiceDiscoveryProvider _provider;
private readonly string _serviceName;
private readonly int _port;
private readonly string _consulHost;
private readonly string _fakeConsulServiceDiscoveryUrl;
private List<Service> _services;
private Mock<IOcelotLoggerFactory> _factory;
private readonly Mock<IOcelotLoggerFactory> _factory;
private readonly Mock<IOcelotLogger> _logger;
private string _receivedToken;
private IConsulClientFactory _clientFactory;
public ConsulServiceDiscoveryProviderTests()
{
@ -40,11 +42,12 @@ namespace Ocelot.UnitTests.ServiceDiscovery
_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);
_provider = new ConsulServiceDiscoveryProvider(config, _factory.Object);
var config = new ConsulRegistryConfiguration(_consulHost, _port, _serviceName, null);
_provider = new ConsulServiceDiscoveryProvider(config, _factory.Object, _clientFactory);
}
[Fact]
@ -69,6 +72,33 @@ namespace Ocelot.UnitTests.ServiceDiscovery
.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()
{
@ -197,6 +227,11 @@ namespace Ocelot.UnitTests.ServiceDiscovery
{
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);
}
});

View File

@ -3,6 +3,7 @@ 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;
@ -19,11 +20,13 @@ namespace Ocelot.UnitTests.ServiceDiscovery
private readonly ServiceDiscoveryProviderFactory _factory;
private DownstreamReRoute _reRoute;
private Mock<IOcelotLoggerFactory> _loggerFactory;
private IConsulClientFactory _clientFactory;
public ServiceProviderFactoryTests()
{
_loggerFactory = new Mock<IOcelotLoggerFactory>();
_factory = new ServiceDiscoveryProviderFactory(_loggerFactory.Object);
_clientFactory = new ConsulClientFactory();
_factory = new ServiceDiscoveryProviderFactory(_loggerFactory.Object, _clientFactory);
}
[Fact]
@ -87,7 +90,7 @@ namespace Ocelot.UnitTests.ServiceDiscovery
.Build();
var serviceConfig = new ServiceProviderConfigurationBuilder()
.WithServiceDiscoveryProviderType("ServiceFabric")
.WithType("ServiceFabric")
.Build();
this.Given(x => x.GivenTheReRoute(serviceConfig, reRoute))