mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-06-19 06:18:16 +08:00
Feature/websockets (#273)
* #212 - hacked websockets proxy together * faffing around * #212 hacking away :( * #212 websockets proxy middleware working * #212 map when for webockets working * #212 some test refactor * #212 temp commit * #212 websockets proxy working, tests passing...need to do some tidying and write docs * #212 more code coverage * #212 docs for websockets * #212 updated readme * #212 tidying up after websockets refactoring * #212 tidying up after websockets refactoring * #212 tidying up after websockets refactoring * stuck a warning in about logging levels into docs!
This commit is contained in:
@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using Consul;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
@ -28,7 +26,7 @@ namespace Ocelot.AcceptanceTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_use_service_discovery_and_load_balance_request()
|
||||
public void should_load_balance_request()
|
||||
{
|
||||
var downstreamServiceOneUrl = "http://localhost:50881";
|
||||
var downstreamServiceTwoUrl = "http://localhost:50892";
|
||||
@ -74,18 +72,6 @@ namespace Ocelot.AcceptanceTests
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void ThenOnlyOneServiceHasBeenCalled()
|
||||
{
|
||||
_counterOne.ShouldBe(10);
|
||||
_counterTwo.ShouldBe(0);
|
||||
}
|
||||
|
||||
private void GivenIResetCounters()
|
||||
{
|
||||
_counterOne = 0;
|
||||
_counterTwo = 0;
|
||||
}
|
||||
|
||||
private void ThenBothServicesCalledRealisticAmountOfTimes(int bottom, int top)
|
||||
{
|
||||
_counterOne.ShouldBeInRange(bottom, top);
|
||||
@ -121,7 +107,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);
|
||||
}
|
||||
|
@ -40,12 +40,49 @@ namespace Ocelot.AcceptanceTests
|
||||
public string RequestIdKey = "OcRequestId";
|
||||
private readonly Random _random;
|
||||
private IWebHostBuilder _webHostBuilder;
|
||||
private WebHostBuilder _ocelotBuilder;
|
||||
private IWebHost _ocelotHost;
|
||||
|
||||
public Steps()
|
||||
{
|
||||
_random = new Random();
|
||||
}
|
||||
|
||||
public async Task StartFakeOcelotWithWebSockets()
|
||||
{
|
||||
_ocelotBuilder = new WebHostBuilder();
|
||||
_ocelotBuilder.ConfigureServices(s =>
|
||||
{
|
||||
s.AddSingleton(_ocelotBuilder);
|
||||
s.AddOcelot();
|
||||
});
|
||||
_ocelotBuilder.UseKestrel()
|
||||
.UseUrls("http://localhost:5000")
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.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();
|
||||
})
|
||||
.ConfigureLogging((hostingContext, logging) =>
|
||||
{
|
||||
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
|
||||
logging.AddConsole();
|
||||
})
|
||||
.Configure(app =>
|
||||
{
|
||||
app.UseWebSockets();
|
||||
app.UseOcelot().Wait();
|
||||
})
|
||||
.UseIISIntegration();
|
||||
_ocelotHost = _ocelotBuilder.Build();
|
||||
await _ocelotHost.StartAsync();
|
||||
}
|
||||
|
||||
public void GivenThereIsAConfiguration(FileConfiguration fileConfiguration)
|
||||
{
|
||||
var configurationPath = TestConfiguration.ConfigurationPath;
|
||||
@ -698,6 +735,7 @@ namespace Ocelot.AcceptanceTests
|
||||
{
|
||||
_ocelotClient?.Dispose();
|
||||
_ocelotServer?.Dispose();
|
||||
_ocelotHost?.Dispose();
|
||||
}
|
||||
|
||||
public void ThenTheRequestIdIsReturned()
|
||||
|
487
test/Ocelot.AcceptanceTests/WebSocketTests.cs
Normal file
487
test/Ocelot.AcceptanceTests/WebSocketTests.cs
Normal file
@ -0,0 +1,487 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Consul;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ocelot.Configuration.File;
|
||||
using Shouldly;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
|
||||
namespace Ocelot.AcceptanceTests
|
||||
{
|
||||
public class WebSocketTests : IDisposable
|
||||
{
|
||||
private IWebHost _firstDownstreamHost;
|
||||
private IWebHost _secondDownstreamHost;
|
||||
private readonly List<string> _secondRecieved;
|
||||
private readonly List<string> _firstRecieved;
|
||||
private readonly List<ServiceEntry> _serviceEntries;
|
||||
private readonly Steps _steps;
|
||||
private IWebHost _fakeConsulBuilder;
|
||||
|
||||
public WebSocketTests()
|
||||
{
|
||||
_steps = new Steps();
|
||||
_firstRecieved = new List<string>();
|
||||
_secondRecieved = new List<string>();
|
||||
_serviceEntries = new List<ServiceEntry>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task should_proxy_websocket_input_to_downstream_service()
|
||||
{
|
||||
var downstreamPort = 5001;
|
||||
var downstreamHost = "localhost";
|
||||
|
||||
var config = new FileConfiguration
|
||||
{
|
||||
ReRoutes = new List<FileReRoute>
|
||||
{
|
||||
new FileReRoute
|
||||
{
|
||||
UpstreamPathTemplate = "/",
|
||||
DownstreamPathTemplate = "/ws",
|
||||
DownstreamScheme = "ws",
|
||||
DownstreamHostAndPorts = new List<FileHostAndPort>
|
||||
{
|
||||
new FileHostAndPort
|
||||
{
|
||||
Host = downstreamHost,
|
||||
Port = downstreamPort
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.Given(_ => _steps.GivenThereIsAConfiguration(config))
|
||||
.And(_ => _steps.StartFakeOcelotWithWebSockets())
|
||||
.And(_ => StartFakeDownstreamService($"http://{downstreamHost}:{downstreamPort}", "/ws"))
|
||||
.When(_ => StartClient("ws://localhost:5000/"))
|
||||
.Then(_ => _firstRecieved.Count.ShouldBe(10))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task should_proxy_websocket_input_to_downstream_service_and_use_load_balancer()
|
||||
{
|
||||
var downstreamPort = 5005;
|
||||
var downstreamHost = "localhost";
|
||||
var secondDownstreamPort = 5006;
|
||||
var secondDownstreamHost = "localhost";
|
||||
|
||||
var config = new FileConfiguration
|
||||
{
|
||||
ReRoutes = new List<FileReRoute>
|
||||
{
|
||||
new FileReRoute
|
||||
{
|
||||
UpstreamPathTemplate = "/",
|
||||
DownstreamPathTemplate = "/ws",
|
||||
DownstreamScheme = "ws",
|
||||
DownstreamHostAndPorts = new List<FileHostAndPort>
|
||||
{
|
||||
new FileHostAndPort
|
||||
{
|
||||
Host = downstreamHost,
|
||||
Port = downstreamPort
|
||||
},
|
||||
new FileHostAndPort
|
||||
{
|
||||
Host = secondDownstreamHost,
|
||||
Port = secondDownstreamPort
|
||||
}
|
||||
},
|
||||
LoadBalancer = "RoundRobin"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.Given(_ => _steps.GivenThereIsAConfiguration(config))
|
||||
.And(_ => _steps.StartFakeOcelotWithWebSockets())
|
||||
.And(_ => StartFakeDownstreamService($"http://{downstreamHost}:{downstreamPort}", "/ws"))
|
||||
.And(_ => StartSecondFakeDownstreamService($"http://{secondDownstreamHost}:{secondDownstreamPort}","/ws"))
|
||||
.When(_ => WhenIStartTheClients())
|
||||
.Then(_ => ThenBothDownstreamServicesAreCalled())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task should_proxy_websocket_input_to_downstream_service_and_use_service_discovery_and_load_balancer()
|
||||
{
|
||||
var downstreamPort = 5007;
|
||||
var downstreamHost = "localhost";
|
||||
|
||||
var secondDownstreamPort = 5008;
|
||||
var secondDownstreamHost = "localhost";
|
||||
|
||||
var serviceName = "websockets";
|
||||
var consulPort = 8509;
|
||||
var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}";
|
||||
var serviceEntryOne = new ServiceEntry()
|
||||
{
|
||||
Service = new AgentService()
|
||||
{
|
||||
Service = serviceName,
|
||||
Address = downstreamHost,
|
||||
Port = downstreamPort,
|
||||
ID = Guid.NewGuid().ToString(),
|
||||
Tags = new string[0]
|
||||
},
|
||||
};
|
||||
var serviceEntryTwo = new ServiceEntry()
|
||||
{
|
||||
Service = new AgentService()
|
||||
{
|
||||
Service = serviceName,
|
||||
Address = secondDownstreamHost,
|
||||
Port = secondDownstreamPort,
|
||||
ID = Guid.NewGuid().ToString(),
|
||||
Tags = new string[0]
|
||||
},
|
||||
};
|
||||
|
||||
var config = new FileConfiguration
|
||||
{
|
||||
ReRoutes = new List<FileReRoute>
|
||||
{
|
||||
new FileReRoute
|
||||
{
|
||||
UpstreamPathTemplate = "/",
|
||||
DownstreamPathTemplate = "/ws",
|
||||
DownstreamScheme = "ws",
|
||||
LoadBalancer = "RoundRobin",
|
||||
ServiceName = serviceName,
|
||||
UseServiceDiscovery = true
|
||||
}
|
||||
},
|
||||
GlobalConfiguration = new FileGlobalConfiguration
|
||||
{
|
||||
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
|
||||
{
|
||||
Host = "localhost",
|
||||
Port = consulPort,
|
||||
Type = "consul"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.Given(_ => _steps.GivenThereIsAConfiguration(config))
|
||||
.And(_ => _steps.StartFakeOcelotWithWebSockets())
|
||||
.And(_ => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, serviceName))
|
||||
.And(_ => GivenTheServicesAreRegisteredWithConsul(serviceEntryOne, serviceEntryTwo))
|
||||
.And(_ => StartFakeDownstreamService($"http://{downstreamHost}:{downstreamPort}", "/ws"))
|
||||
.And(_ => StartSecondFakeDownstreamService($"http://{secondDownstreamHost}:{secondDownstreamPort}", "/ws"))
|
||||
.When(_ => WhenIStartTheClients())
|
||||
.Then(_ => ThenBothDownstreamServicesAreCalled())
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
private void ThenBothDownstreamServicesAreCalled()
|
||||
{
|
||||
_firstRecieved.Count.ShouldBe(10);
|
||||
_firstRecieved.ForEach(x =>
|
||||
{
|
||||
x.ShouldBe("test");
|
||||
});
|
||||
|
||||
_secondRecieved.Count.ShouldBe(10);
|
||||
_secondRecieved.ForEach(x =>
|
||||
{
|
||||
x.ShouldBe("chocolate");
|
||||
});
|
||||
}
|
||||
|
||||
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}")
|
||||
{
|
||||
await context.Response.WriteJsonAsync(_serviceEntries);
|
||||
}
|
||||
});
|
||||
})
|
||||
.Build();
|
||||
|
||||
_fakeConsulBuilder.Start();
|
||||
}
|
||||
|
||||
private async Task WhenIStartTheClients()
|
||||
{
|
||||
var firstClient = StartClient("ws://localhost:5000/");
|
||||
|
||||
var secondClient = StartSecondClient("ws://localhost:5000/");
|
||||
|
||||
await Task.WhenAll(firstClient, secondClient);
|
||||
}
|
||||
|
||||
private async Task StartClient(string url)
|
||||
{
|
||||
var client = new ClientWebSocket();
|
||||
|
||||
await client.ConnectAsync(new Uri(url), CancellationToken.None);
|
||||
|
||||
var sending = Task.Run(async () =>
|
||||
{
|
||||
string line = "test";
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes(line);
|
||||
|
||||
await client.SendAsync(new ArraySegment<byte>(bytes), WebSocketMessageType.Text, true,
|
||||
CancellationToken.None);
|
||||
await Task.Delay(10);
|
||||
}
|
||||
|
||||
await client.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
|
||||
});
|
||||
|
||||
var receiving = Task.Run(async () =>
|
||||
{
|
||||
var buffer = new byte[1024 * 4];
|
||||
|
||||
while (true)
|
||||
{
|
||||
var result = await client.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||
|
||||
if (result.MessageType == WebSocketMessageType.Text)
|
||||
{
|
||||
_firstRecieved.Add(Encoding.UTF8.GetString(buffer, 0, result.Count));
|
||||
}
|
||||
|
||||
else if (result.MessageType == WebSocketMessageType.Close)
|
||||
{
|
||||
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await Task.WhenAll(sending, receiving);
|
||||
}
|
||||
|
||||
private async Task StartSecondClient(string url)
|
||||
{
|
||||
await Task.Delay(500);
|
||||
|
||||
var client = new ClientWebSocket();
|
||||
|
||||
await client.ConnectAsync(new Uri(url), CancellationToken.None);
|
||||
|
||||
var sending = Task.Run(async () =>
|
||||
{
|
||||
string line = "test";
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes(line);
|
||||
|
||||
await client.SendAsync(new ArraySegment<byte>(bytes), WebSocketMessageType.Text, true,
|
||||
CancellationToken.None);
|
||||
await Task.Delay(10);
|
||||
}
|
||||
|
||||
await client.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
|
||||
});
|
||||
|
||||
var receiving = Task.Run(async () =>
|
||||
{
|
||||
var buffer = new byte[1024 * 4];
|
||||
|
||||
while (true)
|
||||
{
|
||||
var result = await client.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||
|
||||
if (result.MessageType == WebSocketMessageType.Text)
|
||||
{
|
||||
_secondRecieved.Add(Encoding.UTF8.GetString(buffer, 0, result.Count));
|
||||
}
|
||||
|
||||
else if (result.MessageType == WebSocketMessageType.Close)
|
||||
{
|
||||
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await Task.WhenAll(sending, receiving);
|
||||
}
|
||||
|
||||
|
||||
private async Task StartFakeDownstreamService(string url, string path)
|
||||
{
|
||||
_firstDownstreamHost = new WebHostBuilder()
|
||||
.ConfigureServices(s => { }).UseKestrel()
|
||||
.UseUrls(url)
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.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.AddEnvironmentVariables();
|
||||
})
|
||||
.ConfigureLogging((hostingContext, logging) =>
|
||||
{
|
||||
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
|
||||
logging.AddConsole();
|
||||
})
|
||||
.Configure(app =>
|
||||
{
|
||||
app.UseWebSockets();
|
||||
app.Use(async (context, next) =>
|
||||
{
|
||||
if (context.Request.Path == path)
|
||||
{
|
||||
if (context.WebSockets.IsWebSocketRequest)
|
||||
{
|
||||
WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
|
||||
await Echo(webSocket);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Response.StatusCode = 400;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await next();
|
||||
}
|
||||
});
|
||||
})
|
||||
.UseIISIntegration().Build();
|
||||
await _firstDownstreamHost.StartAsync();
|
||||
}
|
||||
|
||||
|
||||
private async Task StartSecondFakeDownstreamService(string url, string path)
|
||||
{
|
||||
_secondDownstreamHost = new WebHostBuilder()
|
||||
.ConfigureServices(s => { }).UseKestrel()
|
||||
.UseUrls(url)
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.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.AddEnvironmentVariables();
|
||||
})
|
||||
.ConfigureLogging((hostingContext, logging) =>
|
||||
{
|
||||
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
|
||||
logging.AddConsole();
|
||||
})
|
||||
.Configure(app =>
|
||||
{
|
||||
app.UseWebSockets();
|
||||
app.Use(async (context, next) =>
|
||||
{
|
||||
if (context.Request.Path == path)
|
||||
{
|
||||
if (context.WebSockets.IsWebSocketRequest)
|
||||
{
|
||||
WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
|
||||
await Message(webSocket);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Response.StatusCode = 400;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await next();
|
||||
}
|
||||
});
|
||||
})
|
||||
.UseIISIntegration().Build();
|
||||
await _secondDownstreamHost.StartAsync();
|
||||
}
|
||||
|
||||
|
||||
private async Task Echo(WebSocket webSocket)
|
||||
{
|
||||
try
|
||||
{
|
||||
var buffer = new byte[1024 * 4];
|
||||
|
||||
var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||
|
||||
while (!result.CloseStatus.HasValue)
|
||||
{
|
||||
await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);
|
||||
|
||||
result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||
}
|
||||
|
||||
await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Message(WebSocket webSocket)
|
||||
{
|
||||
try
|
||||
{
|
||||
var buffer = new byte[1024 * 4];
|
||||
|
||||
var bytes = Encoding.UTF8.GetBytes("chocolate");
|
||||
|
||||
var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||
|
||||
while (!result.CloseStatus.HasValue)
|
||||
{
|
||||
await webSocket.SendAsync(new ArraySegment<byte>(bytes), result.MessageType, result.EndOfMessage, CancellationToken.None);
|
||||
|
||||
result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||
}
|
||||
|
||||
await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_steps.Dispose();
|
||||
_firstDownstreamHost?.Dispose();
|
||||
_secondDownstreamHost?.Dispose();
|
||||
_fakeConsulBuilder?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
@ -43,7 +43,7 @@ namespace Ocelot.UnitTests.Cache
|
||||
});
|
||||
_cacheManager = new OcelotCacheManagerCache<CachedResponse>(cacheManagerOutputCache);
|
||||
_downstreamContext = new DownstreamContext(new DefaultHttpContext());
|
||||
_downstreamContext.DownstreamRequest = new HttpRequestMessage(HttpMethod.Get, "https://some.url/blah?abcd=123");
|
||||
_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);
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ namespace Ocelot.UnitTests.Cache
|
||||
_logger = new Mock<IOcelotLogger>();
|
||||
_loggerFactory.Setup(x => x.CreateLogger<OutputCacheMiddleware>()).Returns(_logger.Object);
|
||||
_next = context => Task.CompletedTask;
|
||||
_downstreamContext.DownstreamRequest = new HttpRequestMessage(HttpMethod.Get, "https://some.url/blah?abcd=123");
|
||||
_downstreamContext.DownstreamRequest = new Ocelot.Request.Middleware.DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "https://some.url/blah?abcd=123"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -20,6 +20,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator
|
||||
using Xunit;
|
||||
using Shouldly;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Ocelot.Request.Middleware;
|
||||
|
||||
public class DownstreamUrlCreatorMiddlewareTests
|
||||
{
|
||||
@ -30,6 +31,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator
|
||||
private DownstreamUrlCreatorMiddleware _middleware;
|
||||
private DownstreamContext _downstreamContext;
|
||||
private OcelotRequestDelegate _next;
|
||||
private HttpRequestMessage _request;
|
||||
|
||||
public DownstreamUrlCreatorMiddlewareTests()
|
||||
{
|
||||
@ -38,7 +40,8 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator
|
||||
_logger = new Mock<IOcelotLogger>();
|
||||
_loggerFactory.Setup(x => x.CreateLogger<DownstreamUrlCreatorMiddleware>()).Returns(_logger.Object);
|
||||
_downstreamUrlTemplateVariableReplacer = new Mock<IDownstreamPathPlaceholderReplacer>();
|
||||
_downstreamContext.DownstreamRequest = new HttpRequestMessage(HttpMethod.Get, "https://my.url/abc/?q=123");
|
||||
_request = new HttpRequestMessage(HttpMethod.Get, "https://my.url/abc/?q=123");
|
||||
_downstreamContext.DownstreamRequest = new DownstreamRequest(_request);
|
||||
_next = context => Task.CompletedTask;
|
||||
}
|
||||
|
||||
@ -208,7 +211,9 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator
|
||||
|
||||
private void GivenTheDownstreamRequestUriIs(string uri)
|
||||
{
|
||||
_downstreamContext.DownstreamRequest.RequestUri = new Uri(uri);
|
||||
_request.RequestUri = new Uri(uri);
|
||||
//todo - not sure if needed
|
||||
_downstreamContext.DownstreamRequest = new DownstreamRequest(_request);
|
||||
}
|
||||
|
||||
private void GivenTheUrlReplacerWillReturn(string path)
|
||||
@ -221,7 +226,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator
|
||||
|
||||
private void ThenTheDownstreamRequestUriIs(string expectedUri)
|
||||
{
|
||||
_downstreamContext.DownstreamRequest.RequestUri.OriginalString.ShouldBe(expectedUri);
|
||||
_downstreamContext.DownstreamRequest.ToHttpRequestMessage().RequestUri.OriginalString.ShouldBe(expectedUri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ using Shouldly;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
using System.Net.Http;
|
||||
using Ocelot.Request.Middleware;
|
||||
|
||||
namespace Ocelot.UnitTests.Headers
|
||||
{
|
||||
@ -18,7 +19,7 @@ namespace Ocelot.UnitTests.Headers
|
||||
{
|
||||
private readonly AddHeadersToRequest _addHeadersToRequest;
|
||||
private readonly Mock<IClaimsParser> _parser;
|
||||
private readonly HttpRequestMessage _downstreamRequest;
|
||||
private readonly DownstreamRequest _downstreamRequest;
|
||||
private List<Claim> _claims;
|
||||
private List<ClaimToThing> _configuration;
|
||||
private Response _result;
|
||||
@ -28,7 +29,7 @@ namespace Ocelot.UnitTests.Headers
|
||||
{
|
||||
_parser = new Mock<IClaimsParser>();
|
||||
_addHeadersToRequest = new AddHeadersToRequest(_parser.Object);
|
||||
_downstreamRequest = new HttpRequestMessage();
|
||||
_downstreamRequest = new DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "http://test.com"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -16,6 +16,7 @@ using Ocelot.Middleware;
|
||||
namespace Ocelot.UnitTests.Headers
|
||||
{
|
||||
using System.Threading.Tasks;
|
||||
using Ocelot.Request.Middleware;
|
||||
|
||||
public class HttpHeadersTransformationMiddlewareTests
|
||||
{
|
||||
@ -68,7 +69,7 @@ namespace Ocelot.UnitTests.Headers
|
||||
|
||||
private void GivenTheDownstreamRequestIs()
|
||||
{
|
||||
_downstreamContext.DownstreamRequest = new HttpRequestMessage();
|
||||
_downstreamContext.DownstreamRequest = new DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "http://test.com"));
|
||||
}
|
||||
|
||||
private void GivenTheHttpResponseMessageIs()
|
||||
@ -97,7 +98,7 @@ namespace Ocelot.UnitTests.Headers
|
||||
|
||||
private void ThenTheIHttpResponseHeaderReplacerIsCalledCorrectly()
|
||||
{
|
||||
_postReplacer.Verify(x => x.Replace(It.IsAny<HttpResponseMessage>(), It.IsAny<List<HeaderFindAndReplace>>(), It.IsAny<HttpRequestMessage>()), Times.Once);
|
||||
_postReplacer.Verify(x => x.Replace(It.IsAny<HttpResponseMessage>(), It.IsAny<List<HeaderFindAndReplace>>(), It.IsAny<DownstreamRequest>()), Times.Once);
|
||||
}
|
||||
|
||||
private void GivenTheFollowingRequest()
|
||||
|
@ -14,6 +14,7 @@ namespace Ocelot.UnitTests.Headers
|
||||
using Ocelot.Headers;
|
||||
using Ocelot.Headers.Middleware;
|
||||
using Ocelot.Logging;
|
||||
using Ocelot.Request.Middleware;
|
||||
using Ocelot.Responses;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
@ -37,7 +38,7 @@ namespace Ocelot.UnitTests.Headers
|
||||
_loggerFactory.Setup(x => x.CreateLogger<HttpRequestHeadersBuilderMiddleware>()).Returns(_logger.Object);
|
||||
_next = context => Task.CompletedTask;
|
||||
_middleware = new HttpRequestHeadersBuilderMiddleware(_next, _loggerFactory.Object, _addHeaders.Object);
|
||||
_downstreamContext.DownstreamRequest = new HttpRequestMessage();
|
||||
_downstreamContext.DownstreamRequest = new DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "http://test.com"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -81,7 +82,7 @@ namespace Ocelot.UnitTests.Headers
|
||||
.Setup(x => x.SetHeadersOnDownstreamRequest(
|
||||
It.IsAny<List<ClaimToThing>>(),
|
||||
It.IsAny<IEnumerable<System.Security.Claims.Claim>>(),
|
||||
It.IsAny<HttpRequestMessage>()))
|
||||
It.IsAny<DownstreamRequest>()))
|
||||
.Returns(new OkResponse());
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ using Moq;
|
||||
using Ocelot.Infrastructure;
|
||||
using Ocelot.Middleware;
|
||||
using Ocelot.Infrastructure.RequestData;
|
||||
using Ocelot.Request.Middleware;
|
||||
|
||||
namespace Ocelot.UnitTests.Headers
|
||||
{
|
||||
@ -21,7 +22,7 @@ namespace Ocelot.UnitTests.Headers
|
||||
private HttpResponseHeaderReplacer _replacer;
|
||||
private List<HeaderFindAndReplace> _headerFindAndReplaces;
|
||||
private Response _result;
|
||||
private HttpRequestMessage _request;
|
||||
private DownstreamRequest _request;
|
||||
private Mock<IBaseUrlFinder> _finder;
|
||||
private Mock<IRequestScopedDataRepository> _repo;
|
||||
|
||||
@ -69,7 +70,7 @@ namespace Ocelot.UnitTests.Headers
|
||||
{
|
||||
var downstreamUrl = "http://downstream.com/";
|
||||
|
||||
var request = new HttpRequestMessage();
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, "http://test.com");
|
||||
request.RequestUri = new System.Uri(downstreamUrl);
|
||||
|
||||
var response = new HttpResponseMessage();
|
||||
@ -91,7 +92,7 @@ namespace Ocelot.UnitTests.Headers
|
||||
{
|
||||
var downstreamUrl = "http://downstream.com/";
|
||||
|
||||
var request = new HttpRequestMessage();
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, "http://test.com");
|
||||
request.RequestUri = new System.Uri(downstreamUrl);
|
||||
|
||||
var response = new HttpResponseMessage();
|
||||
@ -113,7 +114,7 @@ namespace Ocelot.UnitTests.Headers
|
||||
{
|
||||
var downstreamUrl = "http://downstream.com/test/product";
|
||||
|
||||
var request = new HttpRequestMessage();
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, "http://test.com");
|
||||
request.RequestUri = new System.Uri(downstreamUrl);
|
||||
|
||||
var response = new HttpResponseMessage();
|
||||
@ -135,7 +136,7 @@ namespace Ocelot.UnitTests.Headers
|
||||
{
|
||||
var downstreamUrl = "http://downstream.com/test/product";
|
||||
|
||||
var request = new HttpRequestMessage();
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, "http://test.com");
|
||||
request.RequestUri = new System.Uri(downstreamUrl);
|
||||
|
||||
var response = new HttpResponseMessage();
|
||||
@ -157,7 +158,7 @@ namespace Ocelot.UnitTests.Headers
|
||||
{
|
||||
var downstreamUrl = "http://downstream.com:123/test/product";
|
||||
|
||||
var request = new HttpRequestMessage();
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, "http://test.com");
|
||||
request.RequestUri = new System.Uri(downstreamUrl);
|
||||
|
||||
var response = new HttpResponseMessage();
|
||||
@ -179,7 +180,7 @@ namespace Ocelot.UnitTests.Headers
|
||||
{
|
||||
var downstreamUrl = "http://downstream.com:123/test/product";
|
||||
|
||||
var request = new HttpRequestMessage();
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, "http://test.com");
|
||||
request.RequestUri = new System.Uri(downstreamUrl);
|
||||
|
||||
var response = new HttpResponseMessage();
|
||||
@ -198,7 +199,7 @@ namespace Ocelot.UnitTests.Headers
|
||||
|
||||
private void GivenTheRequestIs(HttpRequestMessage request)
|
||||
{
|
||||
_request = request;
|
||||
_request = new DownstreamRequest(request);
|
||||
}
|
||||
|
||||
private void ThenTheHeadersAreNotReplaced()
|
||||
|
@ -4,6 +4,7 @@ using Moq;
|
||||
using Ocelot.Infrastructure;
|
||||
using Ocelot.Infrastructure.RequestData;
|
||||
using Ocelot.Middleware;
|
||||
using Ocelot.Request.Middleware;
|
||||
using Ocelot.Responses;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
@ -43,8 +44,9 @@ namespace Ocelot.UnitTests.Infrastructure
|
||||
[Fact]
|
||||
public void should_return_downstream_base_url_when_port_is_not_80_or_443()
|
||||
{
|
||||
var request = new HttpRequestMessage();
|
||||
request.RequestUri = new Uri("http://www.bbc.co.uk");
|
||||
var httpRequest = new HttpRequestMessage();
|
||||
httpRequest.RequestUri = new Uri("http://www.bbc.co.uk");
|
||||
var request = new DownstreamRequest(httpRequest);
|
||||
var result = _placeholders.Get("{DownstreamBaseUrl}", request);
|
||||
result.Data.ShouldBe("http://www.bbc.co.uk/");
|
||||
}
|
||||
@ -53,8 +55,9 @@ namespace Ocelot.UnitTests.Infrastructure
|
||||
[Fact]
|
||||
public void should_return_downstream_base_url_when_port_is_80_or_443()
|
||||
{
|
||||
var request = new HttpRequestMessage();
|
||||
request.RequestUri = new Uri("http://www.bbc.co.uk:123");
|
||||
var httpRequest = new HttpRequestMessage();
|
||||
httpRequest.RequestUri = new Uri("http://www.bbc.co.uk:123");
|
||||
var request = new DownstreamRequest(httpRequest);
|
||||
var result = _placeholders.Get("{DownstreamBaseUrl}", request);
|
||||
result.Data.ShouldBe("http://www.bbc.co.uk:123/");
|
||||
}
|
||||
@ -62,7 +65,8 @@ namespace Ocelot.UnitTests.Infrastructure
|
||||
[Fact]
|
||||
public void should_return_key_does_not_exist_for_http_request_message()
|
||||
{
|
||||
var result = _placeholders.Get("{Test}", new System.Net.Http.HttpRequestMessage());
|
||||
var request = new DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "http://west.com"));
|
||||
var result = _placeholders.Get("{Test}", request);
|
||||
result.IsError.ShouldBeTrue();
|
||||
result.Errors[0].Message.ShouldBe("Unable to find placeholder called {Test}");
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
using Xunit;
|
||||
using Ocelot.Infrastructure.Extensions;
|
||||
using Shouldly;
|
||||
|
||||
namespace Ocelot.UnitTests.Infrastructure
|
||||
{
|
||||
public class StringExtensionsTests
|
||||
{
|
||||
[Fact]
|
||||
public void should_trim_start()
|
||||
{
|
||||
var test = "/string";
|
||||
|
||||
test = test.TrimStart("/");
|
||||
|
||||
test.ShouldBe("string");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_return_source()
|
||||
{
|
||||
var test = "string";
|
||||
|
||||
test = test.LastCharAsForwardSlash();
|
||||
|
||||
test.ShouldBe("string/");
|
||||
}
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ using Ocelot.LoadBalancer.LoadBalancers;
|
||||
using Ocelot.ServiceDiscovery;
|
||||
using Shouldly;
|
||||
using System.Collections.Generic;
|
||||
using Ocelot.ServiceDiscovery.Providers;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
|
||||
|
@ -13,6 +13,7 @@ namespace Ocelot.UnitTests.LoadBalancer
|
||||
using Ocelot.LoadBalancer.LoadBalancers;
|
||||
using Ocelot.LoadBalancer.Middleware;
|
||||
using Ocelot.Logging;
|
||||
using Ocelot.Request.Middleware;
|
||||
using Ocelot.Responses;
|
||||
using Ocelot.Values;
|
||||
using Shouldly;
|
||||
@ -39,13 +40,13 @@ namespace Ocelot.UnitTests.LoadBalancer
|
||||
_loadBalancerHouse = new Mock<ILoadBalancerHouse>();
|
||||
_loadBalancer = new Mock<ILoadBalancer>();
|
||||
_loadBalancerHouse = new Mock<ILoadBalancerHouse>();
|
||||
_downstreamRequest = new HttpRequestMessage(HttpMethod.Get, "");
|
||||
_downstreamRequest = new HttpRequestMessage(HttpMethod.Get, "http://test.com/");
|
||||
_downstreamContext = new DownstreamContext(new DefaultHttpContext());
|
||||
_loggerFactory = new Mock<IOcelotLoggerFactory>();
|
||||
_logger = new Mock<IOcelotLogger>();
|
||||
_loggerFactory.Setup(x => x.CreateLogger<LoadBalancingMiddleware>()).Returns(_logger.Object);
|
||||
_next = context => Task.CompletedTask;
|
||||
_downstreamContext.DownstreamRequest = _downstreamRequest;
|
||||
_downstreamContext.DownstreamRequest = new DownstreamRequest(_downstreamRequest);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -122,6 +123,7 @@ namespace Ocelot.UnitTests.LoadBalancer
|
||||
private void GivenTheDownStreamUrlIs(string downstreamUrl)
|
||||
{
|
||||
_downstreamRequest.RequestUri = new System.Uri(downstreamUrl);
|
||||
_downstreamContext.DownstreamRequest = new DownstreamRequest(_downstreamRequest);
|
||||
}
|
||||
|
||||
private void GivenTheLoadBalancerReturnsAnError()
|
||||
@ -185,7 +187,7 @@ namespace Ocelot.UnitTests.LoadBalancer
|
||||
|
||||
private void ThenTheDownstreamUrlIsReplacedWith(string expectedUri)
|
||||
{
|
||||
_downstreamContext.DownstreamRequest.RequestUri.OriginalString.ShouldBe(expectedUri);
|
||||
_downstreamContext.DownstreamRequest.ToHttpRequestMessage().RequestUri.OriginalString.ShouldBe(expectedUri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ using Ocelot.Configuration.Builder;
|
||||
using Ocelot.Errors;
|
||||
using Ocelot.Middleware;
|
||||
using Ocelot.Middleware.Multiplexer;
|
||||
using Ocelot.Request.Middleware;
|
||||
using Ocelot.UnitTests.Responder;
|
||||
using Shouldly;
|
||||
using TestStack.BDDfy;
|
||||
@ -48,7 +49,7 @@ namespace Ocelot.UnitTests.Middleware
|
||||
new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent("Bill says hi") },
|
||||
DownstreamReRoute = billDownstreamReRoute,
|
||||
Errors = new List<Error> { new AnyError() },
|
||||
DownstreamRequest = new HttpRequestMessage(HttpMethod.Get, new Uri("http://www.bbc.co.uk")),
|
||||
DownstreamRequest = new DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, new Uri("http://www.bbc.co.uk"))),
|
||||
};
|
||||
|
||||
var downstreamContexts = new List<DownstreamContext> { billDownstreamContext };
|
||||
|
@ -12,24 +12,27 @@ using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
using System.Net.Http;
|
||||
using System;
|
||||
using Ocelot.Request.Middleware;
|
||||
|
||||
namespace Ocelot.UnitTests.QueryStrings
|
||||
{
|
||||
public class AddQueriesToRequestTests
|
||||
{
|
||||
private readonly AddQueriesToRequest _addQueriesToRequest;
|
||||
private HttpRequestMessage _downstreamRequest;
|
||||
private DownstreamRequest _downstreamRequest;
|
||||
private readonly Mock<IClaimsParser> _parser;
|
||||
private List<ClaimToThing> _configuration;
|
||||
private List<Claim> _claims;
|
||||
private Response _result;
|
||||
private Response<string> _claimValue;
|
||||
private HttpRequestMessage _request;
|
||||
|
||||
public AddQueriesToRequestTests()
|
||||
{
|
||||
_request = new HttpRequestMessage(HttpMethod.Post, "http://my.url/abc?q=123");
|
||||
_parser = new Mock<IClaimsParser>();
|
||||
_addQueriesToRequest = new AddQueriesToRequest(_parser.Object);
|
||||
_downstreamRequest = new HttpRequestMessage(HttpMethod.Post, "http://my.url/abc?q=123");
|
||||
_downstreamRequest = new DownstreamRequest(_request);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -78,7 +81,7 @@ namespace Ocelot.UnitTests.QueryStrings
|
||||
|
||||
private void TheTheQueryStringIs(string expected)
|
||||
{
|
||||
_downstreamRequest.RequestUri.Query.ShouldBe(expected);
|
||||
_downstreamRequest.Query.ShouldBe(expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -123,7 +126,7 @@ namespace Ocelot.UnitTests.QueryStrings
|
||||
|
||||
private void ThenTheQueryIsAdded()
|
||||
{
|
||||
var queries = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(_downstreamRequest.RequestUri.OriginalString);
|
||||
var queries = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(_downstreamRequest.ToHttpRequestMessage().RequestUri.OriginalString);
|
||||
var query = queries.First(x => x.Key == "query-key");
|
||||
query.Value.First().ShouldBe(_claimValue.Data);
|
||||
}
|
||||
@ -140,15 +143,18 @@ namespace Ocelot.UnitTests.QueryStrings
|
||||
|
||||
private void GivenTheDownstreamRequestHasQueryString(string queryString)
|
||||
{
|
||||
_downstreamRequest = new HttpRequestMessage(HttpMethod.Post, $"http://my.url/abc{queryString}");
|
||||
_request = new HttpRequestMessage(HttpMethod.Post, $"http://my.url/abc{queryString}");
|
||||
_downstreamRequest = new DownstreamRequest(_request);
|
||||
}
|
||||
|
||||
private void GivenTheDownstreamRequestHasQueryString(string key, string value)
|
||||
{
|
||||
var newUri = Microsoft.AspNetCore.WebUtilities.QueryHelpers
|
||||
.AddQueryString(_downstreamRequest.RequestUri.OriginalString, key, value);
|
||||
.AddQueryString(_downstreamRequest.ToHttpRequestMessage().RequestUri.OriginalString, key, value);
|
||||
|
||||
_downstreamRequest.RequestUri = new Uri(newUri);
|
||||
_request.RequestUri = new Uri(newUri);
|
||||
//todo - might not need to instanciate
|
||||
_downstreamRequest = new DownstreamRequest(_request);
|
||||
}
|
||||
|
||||
private void GivenTheClaimParserReturns(Response<string> claimValue)
|
||||
|
@ -18,6 +18,7 @@ namespace Ocelot.UnitTests.QueryStrings
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Ocelot.Request.Middleware;
|
||||
|
||||
public class QueryStringBuilderMiddlewareTests
|
||||
{
|
||||
@ -36,7 +37,7 @@ namespace Ocelot.UnitTests.QueryStrings
|
||||
_loggerFactory.Setup(x => x.CreateLogger<QueryStringBuilderMiddleware>()).Returns(_logger.Object);
|
||||
_next = context => Task.CompletedTask;
|
||||
_addQueries = new Mock<IAddQueriesToRequest>();
|
||||
_downstreamContext.DownstreamRequest = new HttpRequestMessage();
|
||||
_downstreamContext.DownstreamRequest = new DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "http://test.com"));
|
||||
_middleware = new QueryStringBuilderMiddleware(_next, _loggerFactory.Object, _addQueries.Object);
|
||||
}
|
||||
|
||||
@ -74,7 +75,7 @@ namespace Ocelot.UnitTests.QueryStrings
|
||||
.Setup(x => x.SetQueriesOnDownstreamRequest(
|
||||
It.IsAny<List<ClaimToThing>>(),
|
||||
It.IsAny<IEnumerable<Claim>>(),
|
||||
It.IsAny<HttpRequestMessage>()))
|
||||
It.IsAny<DownstreamRequest>()))
|
||||
.Returns(new OkResponse());
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ namespace Ocelot.UnitTests.RateLimit
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Ocelot.Request.Middleware;
|
||||
|
||||
public class ClientRateLimitMiddlewareTests
|
||||
{
|
||||
@ -100,7 +101,7 @@ namespace Ocelot.UnitTests.RateLimit
|
||||
{
|
||||
var request = new HttpRequestMessage(new HttpMethod("GET"), _url);
|
||||
request.Headers.Add("ClientId", clientId);
|
||||
_downstreamContext.DownstreamRequest = request;
|
||||
_downstreamContext.DownstreamRequest = new DownstreamRequest(request);
|
||||
|
||||
_middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
|
||||
_responseStatusCode = (int)_downstreamContext.HttpContext.Response.StatusCode;
|
||||
@ -115,7 +116,7 @@ namespace Ocelot.UnitTests.RateLimit
|
||||
{
|
||||
var request = new HttpRequestMessage(new HttpMethod("GET"), _url);
|
||||
request.Headers.Add("ClientId", clientId);
|
||||
_downstreamContext.DownstreamRequest = request;
|
||||
_downstreamContext.DownstreamRequest = new DownstreamRequest(request);
|
||||
_downstreamContext.HttpContext.Request.Headers.TryAdd("ClientId", clientId);
|
||||
|
||||
_middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
|
||||
|
@ -88,7 +88,7 @@ namespace Ocelot.UnitTests.Request
|
||||
|
||||
private void GivenTheMapperWillReturnAMappedRequest()
|
||||
{
|
||||
_mappedRequest = new OkResponse<HttpRequestMessage>(new HttpRequestMessage());
|
||||
_mappedRequest = new OkResponse<HttpRequestMessage>(new HttpRequestMessage(HttpMethod.Get, "http://www.bbc.co.uk"));
|
||||
|
||||
_requestMapper
|
||||
.Setup(rm => rm.Map(It.IsAny<HttpRequest>()))
|
||||
|
@ -20,6 +20,7 @@ namespace Ocelot.UnitTests.RequestId
|
||||
using Shouldly;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
using Ocelot.Request.Middleware;
|
||||
|
||||
public class ReRouteRequestIdMiddlewareTests
|
||||
{
|
||||
@ -35,7 +36,7 @@ namespace Ocelot.UnitTests.RequestId
|
||||
|
||||
public ReRouteRequestIdMiddlewareTests()
|
||||
{
|
||||
_downstreamRequest = new HttpRequestMessage();
|
||||
_downstreamRequest = new HttpRequestMessage(HttpMethod.Get, "http://test.com");
|
||||
_repo = new Mock<IRequestScopedDataRepository>();
|
||||
_downstreamContext = new DownstreamContext(new DefaultHttpContext());
|
||||
_loggerFactory = new Mock<IOcelotLoggerFactory>();
|
||||
@ -47,7 +48,7 @@ namespace Ocelot.UnitTests.RequestId
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
_middleware = new ReRouteRequestIdMiddleware(_next, _loggerFactory.Object, _repo.Object);
|
||||
_downstreamContext.DownstreamRequest = _downstreamRequest;
|
||||
_downstreamContext.DownstreamRequest = new DownstreamRequest(_downstreamRequest);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -14,6 +14,7 @@ using Ocelot.Configuration;
|
||||
using Ocelot.Configuration.Builder;
|
||||
using Ocelot.Logging;
|
||||
using Ocelot.Middleware;
|
||||
using Ocelot.Request.Middleware;
|
||||
using Ocelot.Requester;
|
||||
using Ocelot.Responses;
|
||||
using Shouldly;
|
||||
@ -170,7 +171,7 @@ namespace Ocelot.UnitTests.Requester
|
||||
var context = new DownstreamContext(new DefaultHttpContext())
|
||||
{
|
||||
DownstreamReRoute = downstream,
|
||||
DownstreamRequest = new HttpRequestMessage() { RequestUri = new Uri("http://localhost:5003") },
|
||||
DownstreamRequest = new DownstreamRequest(new HttpRequestMessage() { RequestUri = new Uri("http://localhost:5003") }),
|
||||
};
|
||||
|
||||
_context = context;
|
||||
|
@ -12,13 +12,16 @@ using Ocelot.Middleware;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
using Shouldly;
|
||||
using Ocelot.Request.Middleware;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ocelot.UnitTests.Requester
|
||||
{
|
||||
public class HttpClientHttpRequesterTest
|
||||
{
|
||||
private readonly Mock<IHttpClientCache> _cacheHandlers;
|
||||
private Mock<IDelegatingHandlerHandlerFactory> _house;
|
||||
private Mock<IDelegatingHandlerHandlerFactory> _factory;
|
||||
private Response<HttpResponseMessage> _response;
|
||||
private readonly HttpClientHttpRequester _httpClientRequester;
|
||||
private DownstreamContext _request;
|
||||
@ -27,8 +30,8 @@ namespace Ocelot.UnitTests.Requester
|
||||
|
||||
public HttpClientHttpRequesterTest()
|
||||
{
|
||||
_house = new Mock<IDelegatingHandlerHandlerFactory>();
|
||||
_house.Setup(x => x.Get(It.IsAny<DownstreamReRoute>())).Returns(new OkResponse<List<Func<DelegatingHandler>>>(new List<Func<DelegatingHandler>>()));
|
||||
_factory = new Mock<IDelegatingHandlerHandlerFactory>();
|
||||
_factory.Setup(x => x.Get(It.IsAny<DownstreamReRoute>())).Returns(new OkResponse<List<Func<DelegatingHandler>>>(new List<Func<DelegatingHandler>>()));
|
||||
_logger = new Mock<IOcelotLogger>();
|
||||
_loggerFactory = new Mock<IOcelotLoggerFactory>();
|
||||
_loggerFactory
|
||||
@ -38,7 +41,7 @@ namespace Ocelot.UnitTests.Requester
|
||||
_httpClientRequester = new HttpClientHttpRequester(
|
||||
_loggerFactory.Object,
|
||||
_cacheHandlers.Object,
|
||||
_house.Object);
|
||||
_factory.Object);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -50,10 +53,11 @@ namespace Ocelot.UnitTests.Requester
|
||||
var context = new DownstreamContext(new DefaultHttpContext())
|
||||
{
|
||||
DownstreamReRoute = reRoute,
|
||||
DownstreamRequest = new HttpRequestMessage() { RequestUri = new Uri("http://www.bbc.co.uk") },
|
||||
DownstreamRequest = new DownstreamRequest(new HttpRequestMessage() { RequestUri = new Uri("http://www.bbc.co.uk") }),
|
||||
};
|
||||
|
||||
this.Given(x=>x.GivenTheRequestIs(context))
|
||||
.And(x => GivenTheHouseReturnsOkHandler())
|
||||
.When(x=>x.WhenIGetResponse())
|
||||
.Then(x => x.ThenTheResponseIsCalledCorrectly())
|
||||
.BDDfy();
|
||||
@ -68,7 +72,7 @@ namespace Ocelot.UnitTests.Requester
|
||||
var context = new DownstreamContext(new DefaultHttpContext())
|
||||
{
|
||||
DownstreamReRoute = reRoute,
|
||||
DownstreamRequest = new HttpRequestMessage() { RequestUri = new Uri("http://localhost:60080") },
|
||||
DownstreamRequest = new DownstreamRequest(new HttpRequestMessage() { RequestUri = new Uri("http://localhost:60080") }),
|
||||
};
|
||||
|
||||
this.Given(x => x.GivenTheRequestIs(context))
|
||||
@ -96,5 +100,23 @@ namespace Ocelot.UnitTests.Requester
|
||||
{
|
||||
_response.IsError.ShouldBeTrue();
|
||||
}
|
||||
|
||||
private void GivenTheHouseReturnsOkHandler()
|
||||
{
|
||||
var handlers = new List<Func<DelegatingHandler>>
|
||||
{
|
||||
() => new OkDelegatingHandler()
|
||||
};
|
||||
|
||||
_factory.Setup(x => x.Get(It.IsAny<DownstreamReRoute>())).Returns(new OkResponse<List<Func<DelegatingHandler>>>(handlers));
|
||||
}
|
||||
|
||||
class OkDelegatingHandler : DelegatingHandler
|
||||
{
|
||||
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(new HttpResponseMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using Ocelot.ServiceDiscovery;
|
||||
using Ocelot.ServiceDiscovery.Providers;
|
||||
using Ocelot.Values;
|
||||
using Shouldly;
|
||||
using TestStack.BDDfy;
|
||||
|
@ -9,6 +9,8 @@ using Microsoft.AspNetCore.Http;
|
||||
using Moq;
|
||||
using Ocelot.Logging;
|
||||
using Ocelot.ServiceDiscovery;
|
||||
using Ocelot.ServiceDiscovery.Configuration;
|
||||
using Ocelot.ServiceDiscovery.Providers;
|
||||
using Ocelot.Values;
|
||||
using Xunit;
|
||||
using TestStack.BDDfy;
|
||||
|
@ -1,4 +1,7 @@
|
||||
namespace Ocelot.UnitTests.ServiceDiscovery
|
||||
using Ocelot.ServiceDiscovery.Configuration;
|
||||
using Ocelot.ServiceDiscovery.Providers;
|
||||
|
||||
namespace Ocelot.UnitTests.ServiceDiscovery
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -5,6 +5,7 @@ using Ocelot.Configuration;
|
||||
using Ocelot.Configuration.Builder;
|
||||
using Ocelot.Logging;
|
||||
using Ocelot.ServiceDiscovery;
|
||||
using Ocelot.ServiceDiscovery.Providers;
|
||||
using Shouldly;
|
||||
using TestStack.BDDfy;
|
||||
using Xunit;
|
||||
|
@ -0,0 +1,239 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Consul;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
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 TestStack.BDDfy;
|
||||
using Xunit;
|
||||
|
||||
namespace Ocelot.UnitTests.Websockets
|
||||
{
|
||||
public class WebSocketsProxyMiddlewareTests : IDisposable
|
||||
{
|
||||
private IWebHost _firstDownstreamHost;
|
||||
private readonly List<string> _firstRecieved;
|
||||
private WebHostBuilder _ocelotBuilder;
|
||||
private IWebHost _ocelotHost;
|
||||
|
||||
public WebSocketsProxyMiddlewareTests()
|
||||
{
|
||||
_firstRecieved = new List<string>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task should_proxy_websocket_input_to_downstream_service()
|
||||
{
|
||||
var downstreamPort = 5001;
|
||||
var downstreamHost = "localhost";
|
||||
|
||||
var config = new FileConfiguration
|
||||
{
|
||||
ReRoutes = new List<FileReRoute>
|
||||
{
|
||||
new FileReRoute
|
||||
{
|
||||
UpstreamPathTemplate = "/",
|
||||
DownstreamPathTemplate = "/ws",
|
||||
DownstreamScheme = "ws",
|
||||
DownstreamHostAndPorts = new List<FileHostAndPort>
|
||||
{
|
||||
new FileHostAndPort
|
||||
{
|
||||
Host = downstreamHost,
|
||||
Port = downstreamPort
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.Given(_ => GivenThereIsAConfiguration(config))
|
||||
.And(_ => StartFakeOcelotWithWebSockets())
|
||||
.And(_ => StartFakeDownstreamService($"http://{downstreamHost}:{downstreamPort}", "/ws"))
|
||||
.When(_ => StartClient("ws://localhost:5000/"))
|
||||
.Then(_ => _firstRecieved.Count.ShouldBe(10))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_firstDownstreamHost?.Dispose();
|
||||
}
|
||||
|
||||
public async Task StartFakeOcelotWithWebSockets()
|
||||
{
|
||||
_ocelotBuilder = new WebHostBuilder();
|
||||
_ocelotBuilder.ConfigureServices(s =>
|
||||
{
|
||||
s.AddSingleton(_ocelotBuilder);
|
||||
s.AddOcelot();
|
||||
});
|
||||
_ocelotBuilder.UseKestrel()
|
||||
.UseUrls("http://localhost:5000")
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.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();
|
||||
})
|
||||
.ConfigureLogging((hostingContext, logging) =>
|
||||
{
|
||||
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
|
||||
logging.AddConsole();
|
||||
})
|
||||
.Configure(app =>
|
||||
{
|
||||
app.UseWebSockets();
|
||||
app.UseOcelot().Wait();
|
||||
})
|
||||
.UseIISIntegration();
|
||||
_ocelotHost = _ocelotBuilder.Build();
|
||||
await _ocelotHost.StartAsync();
|
||||
}
|
||||
|
||||
public void GivenThereIsAConfiguration(FileConfiguration fileConfiguration)
|
||||
{
|
||||
var configurationPath = Path.Combine(AppContext.BaseDirectory, "configuration.json");
|
||||
|
||||
var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration);
|
||||
|
||||
if (File.Exists(configurationPath))
|
||||
{
|
||||
File.Delete(configurationPath);
|
||||
}
|
||||
|
||||
File.WriteAllText(configurationPath, jsonConfiguration);
|
||||
}
|
||||
|
||||
private async Task StartFakeDownstreamService(string url, string path)
|
||||
{
|
||||
_firstDownstreamHost = new WebHostBuilder()
|
||||
.ConfigureServices(s => { }).UseKestrel()
|
||||
.UseUrls(url)
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.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.AddEnvironmentVariables();
|
||||
})
|
||||
.ConfigureLogging((hostingContext, logging) =>
|
||||
{
|
||||
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
|
||||
logging.AddConsole();
|
||||
})
|
||||
.Configure(app =>
|
||||
{
|
||||
app.UseWebSockets();
|
||||
app.Use(async (context, next) =>
|
||||
{
|
||||
if (context.Request.Path == path)
|
||||
{
|
||||
if (context.WebSockets.IsWebSocketRequest)
|
||||
{
|
||||
WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
|
||||
await Echo(webSocket);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Response.StatusCode = 400;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await next();
|
||||
}
|
||||
});
|
||||
})
|
||||
.UseIISIntegration().Build();
|
||||
await _firstDownstreamHost.StartAsync();
|
||||
}
|
||||
|
||||
private async Task StartClient(string url)
|
||||
{
|
||||
var client = new ClientWebSocket();
|
||||
|
||||
await client.ConnectAsync(new Uri(url), CancellationToken.None);
|
||||
|
||||
var sending = Task.Run(async () =>
|
||||
{
|
||||
string line = "test";
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes(line);
|
||||
|
||||
await client.SendAsync(new ArraySegment<byte>(bytes), WebSocketMessageType.Text, true,
|
||||
CancellationToken.None);
|
||||
await Task.Delay(10);
|
||||
}
|
||||
|
||||
await client.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
|
||||
});
|
||||
|
||||
var receiving = Task.Run(async () =>
|
||||
{
|
||||
var buffer = new byte[1024 * 4];
|
||||
|
||||
while (true)
|
||||
{
|
||||
var result = await client.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||
|
||||
if (result.MessageType == WebSocketMessageType.Text)
|
||||
{
|
||||
_firstRecieved.Add(Encoding.UTF8.GetString(buffer, 0, result.Count));
|
||||
}
|
||||
|
||||
else if (result.MessageType == WebSocketMessageType.Close)
|
||||
{
|
||||
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await Task.WhenAll(sending, receiving);
|
||||
}
|
||||
|
||||
private async Task Echo(WebSocket webSocket)
|
||||
{
|
||||
try
|
||||
{
|
||||
var buffer = new byte[1024 * 4];
|
||||
|
||||
var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||
|
||||
while (!result.CloseStatus.HasValue)
|
||||
{
|
||||
await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);
|
||||
|
||||
result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||
}
|
||||
|
||||
await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user