mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-04-27 05:32:51 +08:00

* started messing around with this on the train last night * mega hacking away to change middleware into Ocelot iddleware * scoped data repo back in * broken commit getting tests working * another broken commit farting around with tests * all unit tests passing again * mw pipeline for ocelot...still loads of hacks but getting there now to get acceptance tests working, then fix config so you can have aggregate and then imlement multiplexer, then mapping to response...loads to do * all tests passing before aggregation feature implemented * removed all the request middleware stuff we dont need it * updated how errors work...tho i think there could be edge case here when aggregating because one downstream could error and this would effect another * removed multiplexer so you dont have to send route down, this isnt very thread safe...sigh * hacking around getting the config for aggregates in, this might change * refactored builder and unit tests passing now * Updated a bunch of ports for tests * plugged in code to create reroutes that are aggregates * made multiplexer a class * hacked test to death * simple aggregator done, initial validation done * removed request id from context, it is still specific for http request * now aggregates to json always * docs for aggregate reroutes * Updated docs
399 lines
15 KiB
C#
399 lines
15 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Net;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.AspNetCore.Builder;
|
|
using Microsoft.AspNetCore.Hosting;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Ocelot.Configuration.File;
|
|
using Ocelot.Middleware;
|
|
using Shouldly;
|
|
using TestStack.BDDfy;
|
|
using Xunit;
|
|
|
|
namespace Ocelot.AcceptanceTests
|
|
{
|
|
public class CustomMiddlewareTests : IDisposable
|
|
{
|
|
private readonly string _configurationPath;
|
|
private IWebHost _builder;
|
|
private readonly Steps _steps;
|
|
private int _counter;
|
|
|
|
public CustomMiddlewareTests()
|
|
{
|
|
_counter = 0;
|
|
_steps = new Steps();;
|
|
_configurationPath = "configuration.json";
|
|
}
|
|
|
|
[Fact]
|
|
public void should_call_pre_query_string_builder_middleware()
|
|
{
|
|
var configuration = new OcelotPipelineConfiguration
|
|
{
|
|
AuthorisationMiddleware = async (ctx, next) =>
|
|
{
|
|
_counter++;
|
|
await next.Invoke();
|
|
}
|
|
};
|
|
|
|
var fileConfiguration = new FileConfiguration
|
|
{
|
|
ReRoutes = new List<FileReRoute>
|
|
{
|
|
new FileReRoute
|
|
{
|
|
DownstreamPathTemplate = "/",
|
|
DownstreamHostAndPorts = new List<FileHostAndPort>
|
|
{
|
|
new FileHostAndPort
|
|
{
|
|
Host = "localhost",
|
|
Port = 41879,
|
|
}
|
|
},
|
|
DownstreamScheme = "http",
|
|
UpstreamPathTemplate = "/",
|
|
UpstreamHttpMethod = new List<string> { "Get" },
|
|
}
|
|
}
|
|
};
|
|
|
|
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:41879", 200, ""))
|
|
.And(x => _steps.GivenThereIsAConfiguration(fileConfiguration, _configurationPath))
|
|
.And(x => _steps.GivenOcelotIsRunning(configuration))
|
|
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
|
|
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
|
.And(x => x.ThenTheCounterIs(1))
|
|
.BDDfy();
|
|
}
|
|
|
|
[Fact]
|
|
public void should_call_authorisation_middleware()
|
|
{
|
|
var configuration = new OcelotPipelineConfiguration
|
|
{
|
|
AuthorisationMiddleware = async (ctx, next) =>
|
|
{
|
|
_counter++;
|
|
await next.Invoke();
|
|
}
|
|
};
|
|
|
|
var fileConfiguration = new FileConfiguration
|
|
{
|
|
ReRoutes = new List<FileReRoute>
|
|
{
|
|
new FileReRoute
|
|
{
|
|
DownstreamPathTemplate = "/",
|
|
DownstreamHostAndPorts = new List<FileHostAndPort>
|
|
{
|
|
new FileHostAndPort
|
|
{
|
|
Host = "localhost",
|
|
Port = 41879,
|
|
}
|
|
},
|
|
DownstreamScheme = "http",
|
|
UpstreamPathTemplate = "/",
|
|
UpstreamHttpMethod = new List<string> { "Get" },
|
|
}
|
|
}
|
|
};
|
|
|
|
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:41879", 200, ""))
|
|
.And(x => _steps.GivenThereIsAConfiguration(fileConfiguration, _configurationPath))
|
|
.And(x => _steps.GivenOcelotIsRunning(configuration))
|
|
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
|
|
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
|
.And(x => x.ThenTheCounterIs(1))
|
|
.BDDfy();
|
|
}
|
|
|
|
[Fact]
|
|
public void should_call_authentication_middleware()
|
|
{
|
|
var configuration = new OcelotPipelineConfiguration
|
|
{
|
|
AuthenticationMiddleware = async (ctx, next) =>
|
|
{
|
|
_counter++;
|
|
await next.Invoke();
|
|
}
|
|
};
|
|
|
|
var fileConfiguration = new FileConfiguration
|
|
{
|
|
ReRoutes = new List<FileReRoute>
|
|
{
|
|
new FileReRoute
|
|
{
|
|
DownstreamPathTemplate = "/41879/",
|
|
DownstreamHostAndPorts = new List<FileHostAndPort>
|
|
{
|
|
new FileHostAndPort
|
|
{
|
|
Host = "localhost",
|
|
Port = 41879,
|
|
}
|
|
},
|
|
DownstreamScheme = "http",
|
|
UpstreamPathTemplate = "/",
|
|
UpstreamHttpMethod = new List<string> { "Get" },
|
|
}
|
|
}
|
|
};
|
|
|
|
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:41879", 200, ""))
|
|
.And(x => _steps.GivenThereIsAConfiguration(fileConfiguration, _configurationPath))
|
|
.And(x => _steps.GivenOcelotIsRunning(configuration))
|
|
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
|
|
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
|
.And(x => x.ThenTheCounterIs(1))
|
|
.BDDfy();
|
|
}
|
|
|
|
[Fact]
|
|
public void should_call_pre_error_middleware()
|
|
{
|
|
var configuration = new OcelotPipelineConfiguration
|
|
{
|
|
PreErrorResponderMiddleware = async (ctx, next) =>
|
|
{
|
|
_counter++;
|
|
await next.Invoke();
|
|
}
|
|
};
|
|
|
|
var fileConfiguration = new FileConfiguration
|
|
{
|
|
ReRoutes = new List<FileReRoute>
|
|
{
|
|
new FileReRoute
|
|
{
|
|
DownstreamPathTemplate = "/",
|
|
DownstreamHostAndPorts = new List<FileHostAndPort>
|
|
{
|
|
new FileHostAndPort
|
|
{
|
|
Host = "localhost",
|
|
Port = 41879,
|
|
}
|
|
},
|
|
DownstreamScheme = "http",
|
|
UpstreamPathTemplate = "/",
|
|
UpstreamHttpMethod = new List<string> { "Get" },
|
|
}
|
|
}
|
|
};
|
|
|
|
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:41879", 200, ""))
|
|
.And(x => _steps.GivenThereIsAConfiguration(fileConfiguration, _configurationPath))
|
|
.And(x => _steps.GivenOcelotIsRunning(configuration))
|
|
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
|
|
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
|
.And(x => x.ThenTheCounterIs(1))
|
|
.BDDfy();
|
|
}
|
|
|
|
[Fact]
|
|
public void should_call_pre_authorisation_middleware()
|
|
{
|
|
var configuration = new OcelotPipelineConfiguration
|
|
{
|
|
PreAuthorisationMiddleware = async (ctx, next) =>
|
|
{
|
|
_counter++;
|
|
await next.Invoke();
|
|
}
|
|
};
|
|
|
|
var fileConfiguration = new FileConfiguration
|
|
{
|
|
ReRoutes = new List<FileReRoute>
|
|
{
|
|
new FileReRoute
|
|
{
|
|
DownstreamPathTemplate = "/",
|
|
DownstreamHostAndPorts = new List<FileHostAndPort>
|
|
{
|
|
new FileHostAndPort
|
|
{
|
|
Host = "localhost",
|
|
Port = 41879,
|
|
}
|
|
},
|
|
DownstreamScheme = "http",
|
|
UpstreamPathTemplate = "/",
|
|
UpstreamHttpMethod = new List<string> { "Get" },
|
|
}
|
|
}
|
|
};
|
|
|
|
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:41879", 200, ""))
|
|
.And(x => _steps.GivenThereIsAConfiguration(fileConfiguration, _configurationPath))
|
|
.And(x => _steps.GivenOcelotIsRunning(configuration))
|
|
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
|
|
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
|
.And(x => x.ThenTheCounterIs(1))
|
|
.BDDfy();
|
|
}
|
|
|
|
[Fact]
|
|
public void should_call_pre_http_authentication_middleware()
|
|
{
|
|
var configuration = new OcelotPipelineConfiguration
|
|
{
|
|
PreAuthenticationMiddleware = async (ctx, next) =>
|
|
{
|
|
_counter++;
|
|
await next.Invoke();
|
|
}
|
|
};
|
|
|
|
var fileConfiguration = new FileConfiguration
|
|
{
|
|
ReRoutes = new List<FileReRoute>
|
|
{
|
|
new FileReRoute
|
|
{
|
|
DownstreamPathTemplate = "/",
|
|
DownstreamHostAndPorts = new List<FileHostAndPort>
|
|
{
|
|
new FileHostAndPort
|
|
{
|
|
Host = "localhost",
|
|
Port = 41879,
|
|
}
|
|
},
|
|
DownstreamScheme = "http",
|
|
UpstreamPathTemplate = "/",
|
|
UpstreamHttpMethod = new List<string> { "Get" },
|
|
}
|
|
}
|
|
};
|
|
|
|
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:41879", 200, ""))
|
|
.And(x => _steps.GivenThereIsAConfiguration(fileConfiguration, _configurationPath))
|
|
.And(x => _steps.GivenOcelotIsRunning(configuration))
|
|
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
|
|
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
|
.And(x => x.ThenTheCounterIs(1))
|
|
.BDDfy();
|
|
}
|
|
|
|
|
|
[Fact(Skip = "This is just an example to show how you could hook into Ocelot pipeline with your own middleware. At the moment you must use Response.OnCompleted callback and cannot change the response :( I will see if this can be changed one day!")]
|
|
public void should_fix_issue_237()
|
|
{
|
|
Func<object, Task> callback = state =>
|
|
{
|
|
var httpContext = (HttpContext)state;
|
|
|
|
if (httpContext.Response.StatusCode > 400)
|
|
{
|
|
Debug.WriteLine("COUNT CALLED");
|
|
Console.WriteLine("COUNT CALLED");
|
|
}
|
|
|
|
return Task.CompletedTask;
|
|
};
|
|
|
|
var fileConfiguration = new FileConfiguration
|
|
{
|
|
ReRoutes = new List<FileReRoute>
|
|
{
|
|
new FileReRoute
|
|
{
|
|
DownstreamPathTemplate = "/west",
|
|
DownstreamHostAndPorts = new List<FileHostAndPort>
|
|
{
|
|
new FileHostAndPort
|
|
{
|
|
Host = "localhost",
|
|
Port = 41880,
|
|
}
|
|
},
|
|
DownstreamScheme = "http",
|
|
UpstreamPathTemplate = "/",
|
|
UpstreamHttpMethod = new List<string> { "Get" },
|
|
}
|
|
}
|
|
};
|
|
|
|
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:41880", 200, "/test"))
|
|
.And(x => _steps.GivenThereIsAConfiguration(fileConfiguration, _configurationPath))
|
|
.And(x => _steps.GivenOcelotIsRunningWithMiddleareBeforePipeline<FakeMiddleware>(callback))
|
|
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
|
|
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound))
|
|
.BDDfy();
|
|
}
|
|
|
|
private void ThenTheCounterIs(int expected)
|
|
{
|
|
_counter.ShouldBe(expected);
|
|
}
|
|
|
|
private void GivenThereIsAServiceRunningOn(string url, int statusCode, string basePath)
|
|
{
|
|
_builder = new WebHostBuilder()
|
|
.UseUrls(url)
|
|
.UseKestrel()
|
|
.UseContentRoot(Directory.GetCurrentDirectory())
|
|
.UseIISIntegration()
|
|
.UseUrls(url)
|
|
.Configure(app =>
|
|
{
|
|
app.UsePathBase(basePath);
|
|
app.Run(context =>
|
|
{
|
|
|
|
if(string.IsNullOrEmpty(basePath))
|
|
{
|
|
context.Response.StatusCode = statusCode;
|
|
}
|
|
else if(context.Request.Path.Value != basePath)
|
|
{
|
|
context.Response.StatusCode = 404;;
|
|
}
|
|
|
|
return Task.CompletedTask;
|
|
});
|
|
})
|
|
.Build();
|
|
|
|
_builder.Start();
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_builder?.Dispose();
|
|
_steps.Dispose();
|
|
}
|
|
|
|
public class FakeMiddleware
|
|
{
|
|
private readonly RequestDelegate _next;
|
|
private readonly Func<object, Task> _callback;
|
|
|
|
public FakeMiddleware(RequestDelegate next, Func<object, Task> callback)
|
|
{
|
|
_next = next;
|
|
_callback = callback;
|
|
}
|
|
|
|
public async Task Invoke(HttpContext context)
|
|
{
|
|
await _next(context);
|
|
|
|
context.Response.OnCompleted(_callback, context);
|
|
}
|
|
}
|
|
}
|
|
}
|