Rename all ReRoute to Route to move closer to YARP +semver: breaking

This commit is contained in:
Tom Pallister
2020-05-23 20:50:05 +01:00
committed by GitHub
parent fe3e8bd23a
commit 3439be8927
269 changed files with 23591 additions and 23605 deletions

View File

@ -33,9 +33,9 @@ namespace Ocelot.AcceptanceTests
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/api/values?MailId={userid}",
UpstreamPathTemplate = "/key1data/{userid}",
@ -51,7 +51,7 @@ namespace Ocelot.AcceptanceTests
},
Key = "key1",
},
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/api/values?MailId={userid}",
UpstreamPathTemplate = "/key2data/{userid}",
@ -67,7 +67,7 @@ namespace Ocelot.AcceptanceTests
},
Key = "key2",
},
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/api/values?MailId={userid}",
UpstreamPathTemplate = "/key3data/{userid}",
@ -83,7 +83,7 @@ namespace Ocelot.AcceptanceTests
},
Key = "key3",
},
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/api/values?MailId={userid}",
UpstreamPathTemplate = "/key4data/{userid}",
@ -100,11 +100,11 @@ namespace Ocelot.AcceptanceTests
Key = "key4",
},
},
Aggregates = new List<FileAggregateReRoute>
Aggregates = new List<FileAggregateRoute>
{
new FileAggregateReRoute
new FileAggregateRoute
{
ReRouteKeys = new List<string>{
RouteKeys = new List<string>{
"key1",
"key2",
"key3",
@ -112,9 +112,9 @@ namespace Ocelot.AcceptanceTests
},
UpstreamPathTemplate = "/EmpDetail/IN/{userid}",
},
new FileAggregateReRoute
new FileAggregateRoute
{
ReRouteKeys = new List<string>{
RouteKeys = new List<string>{
"key1",
"key2",
},
@ -146,9 +146,9 @@ namespace Ocelot.AcceptanceTests
var port3 = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
@ -164,7 +164,7 @@ namespace Ocelot.AcceptanceTests
UpstreamHttpMethod = new List<string> { "Get" },
Key = "Comments",
},
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/users/{userId}",
DownstreamScheme = "http",
@ -180,7 +180,7 @@ namespace Ocelot.AcceptanceTests
UpstreamHttpMethod = new List<string> { "Get" },
Key = "UserDetails",
},
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/posts/{postId}",
DownstreamScheme = "http",
@ -197,22 +197,22 @@ namespace Ocelot.AcceptanceTests
Key = "PostDetails",
},
},
Aggregates = new List<FileAggregateReRoute>
Aggregates = new List<FileAggregateRoute>
{
new FileAggregateReRoute
new FileAggregateRoute
{
UpstreamPathTemplate = "/",
UpstreamHost = "localhost",
ReRouteKeys = new List<string>
RouteKeys = new List<string>
{
"Comments",
"UserDetails",
"PostDetails",
},
ReRouteKeysConfig = new List<AggregateReRouteConfig>()
RouteKeysConfig = new List<AggregateRouteConfig>()
{
new AggregateReRouteConfig(){ReRouteKey = "UserDetails",JsonPath = "$[*].writerId",Parameter = "userId"},
new AggregateReRouteConfig(){ReRouteKey = "PostDetails",JsonPath = "$[*].postId",Parameter = "postId"},
new AggregateRouteConfig(){RouteKey = "UserDetails",JsonPath = "$[*].writerId",Parameter = "userId"},
new AggregateRouteConfig(){RouteKey = "PostDetails",JsonPath = "$[*].postId",Parameter = "postId"},
},
},
},
@ -242,9 +242,9 @@ namespace Ocelot.AcceptanceTests
var port2 = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
@ -260,7 +260,7 @@ namespace Ocelot.AcceptanceTests
UpstreamHttpMethod = new List<string> { "Get" },
Key = "Laura",
},
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
@ -277,13 +277,13 @@ namespace Ocelot.AcceptanceTests
Key = "Tom",
},
},
Aggregates = new List<FileAggregateReRoute>
Aggregates = new List<FileAggregateRoute>
{
new FileAggregateReRoute
new FileAggregateRoute
{
UpstreamPathTemplate = "/",
UpstreamHost = "localhost",
ReRouteKeys = new List<string>
RouteKeys = new List<string>
{
"Laura",
"Tom",
@ -313,9 +313,9 @@ namespace Ocelot.AcceptanceTests
var port2 = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
@ -331,7 +331,7 @@ namespace Ocelot.AcceptanceTests
UpstreamHttpMethod = new List<string> { "Get" },
Key = "Laura",
},
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
@ -348,13 +348,13 @@ namespace Ocelot.AcceptanceTests
Key = "Tom",
},
},
Aggregates = new List<FileAggregateReRoute>
Aggregates = new List<FileAggregateRoute>
{
new FileAggregateReRoute
new FileAggregateRoute
{
UpstreamPathTemplate = "/",
UpstreamHost = "localhost",
ReRouteKeys = new List<string>
RouteKeys = new List<string>
{
"Laura",
"Tom",
@ -383,9 +383,9 @@ namespace Ocelot.AcceptanceTests
var port2 = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
@ -401,7 +401,7 @@ namespace Ocelot.AcceptanceTests
UpstreamHttpMethod = new List<string> { "Get" },
Key = "Laura",
},
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
@ -418,13 +418,13 @@ namespace Ocelot.AcceptanceTests
Key = "Tom",
},
},
Aggregates = new List<FileAggregateReRoute>
Aggregates = new List<FileAggregateRoute>
{
new FileAggregateReRoute
new FileAggregateRoute
{
UpstreamPathTemplate = "/",
UpstreamHost = "localhost",
ReRouteKeys = new List<string>
RouteKeys = new List<string>
{
"Laura",
"Tom",
@ -453,9 +453,9 @@ namespace Ocelot.AcceptanceTests
var port2 = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
@ -471,7 +471,7 @@ namespace Ocelot.AcceptanceTests
UpstreamHttpMethod = new List<string> { "Get" },
Key = "Laura",
},
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
@ -488,13 +488,13 @@ namespace Ocelot.AcceptanceTests
Key = "Tom",
},
},
Aggregates = new List<FileAggregateReRoute>
Aggregates = new List<FileAggregateRoute>
{
new FileAggregateReRoute
new FileAggregateRoute
{
UpstreamPathTemplate = "/",
UpstreamHost = "localhost",
ReRouteKeys = new List<string>
RouteKeys = new List<string>
{
"Laura",
"Tom",
@ -523,9 +523,9 @@ namespace Ocelot.AcceptanceTests
var port2 = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
@ -541,7 +541,7 @@ namespace Ocelot.AcceptanceTests
UpstreamHttpMethod = new List<string> { "Get" },
Key = "Laura",
},
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
@ -558,13 +558,13 @@ namespace Ocelot.AcceptanceTests
Key = "Tom",
},
},
Aggregates = new List<FileAggregateReRoute>
Aggregates = new List<FileAggregateRoute>
{
new FileAggregateReRoute
new FileAggregateRoute
{
UpstreamPathTemplate = "/",
UpstreamHost = "localhost",
ReRouteKeys = new List<string>
RouteKeys = new List<string>
{
"Laura",
"Tom",

View File

@ -51,9 +51,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = _downstreamServicePath,
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -92,9 +92,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = _downstreamServicePath,
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -135,9 +135,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = _downstreamServicePath,
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -177,9 +177,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = _downstreamServicePath,
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -220,9 +220,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = _downstreamServicePath,
DownstreamHostAndPorts = new List<FileHostAndPort>

View File

@ -47,9 +47,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -107,9 +107,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -165,9 +165,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -208,9 +208,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -251,9 +251,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>

View File

@ -1,266 +1,266 @@
namespace Ocelot.AcceptanceTests
{
using Butterfly.Client.AspNetCore;
using Configuration.File;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Rafty.Infrastructure;
using Shouldly;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using TestStack.BDDfy;
using Xunit;
using Xunit.Abstractions;
public class ButterflyTracingTests : IDisposable
{
private IWebHost _serviceOneBuilder;
private IWebHost _serviceTwoBuilder;
private IWebHost _fakeButterfly;
private readonly Steps _steps;
private string _downstreamPathOne;
private string _downstreamPathTwo;
private int _butterflyCalled;
private readonly ITestOutputHelper _output;
public ButterflyTracingTests(ITestOutputHelper output)
{
_output = output;
_steps = new Steps();
}
[Fact]
public void should_forward_tracing_information_from_ocelot_and_downstream_services()
{
int port1 = RandomPortFinder.GetRandomPort();
int port2 = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/api/values",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port1,
}
},
UpstreamPathTemplate = "/api001/values",
UpstreamHttpMethod = new List<string> { "Get" },
HttpHandlerOptions = new FileHttpHandlerOptions
{
UseTracing = true
}
},
new FileReRoute
{
DownstreamPathTemplate = "/api/values",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port2,
}
},
UpstreamPathTemplate = "/api002/values",
UpstreamHttpMethod = new List<string> { "Get" },
HttpHandlerOptions = new FileHttpHandlerOptions
{
UseTracing = true
}
}
}
};
var butterflyPort = RandomPortFinder.GetRandomPort();
var butterflyUrl = $"http://localhost:{butterflyPort}";
this.Given(x => GivenFakeButterfly(butterflyUrl))
.And(x => GivenServiceOneIsRunning($"http://localhost:{port1}", "/api/values", 200, "Hello from Laura", butterflyUrl))
.And(x => GivenServiceTwoIsRunning($"http://localhost:{port2}", "/api/values", 200, "Hello from Tom", butterflyUrl))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningUsingButterfly(butterflyUrl))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/api001/values"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/api002/values"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Tom"))
.BDDfy();
var commandOnAllStateMachines = Wait.WaitFor(10000).Until(() => _butterflyCalled >= 4);
_output.WriteLine($"_butterflyCalled is {_butterflyCalled}");
commandOnAllStateMachines.ShouldBeTrue();
}
[Fact]
public void should_return_tracing_header()
{
int port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/api/values",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/api001/values",
UpstreamHttpMethod = new List<string> { "Get" },
HttpHandlerOptions = new FileHttpHandlerOptions
{
UseTracing = true
},
DownstreamHeaderTransform = new Dictionary<string, string>()
{
{"Trace-Id", "{TraceId}"},
{"Tom", "Laura"}
}
}
}
};
var butterflyPort = RandomPortFinder.GetRandomPort();
var butterflyUrl = $"http://localhost:{butterflyPort}";
this.Given(x => GivenFakeButterfly(butterflyUrl))
.And(x => GivenServiceOneIsRunning($"http://localhost:{port}", "/api/values", 200, "Hello from Laura", butterflyUrl))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningUsingButterfly(butterflyUrl))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/api001/values"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.And(x => _steps.ThenTheTraceHeaderIsSet("Trace-Id"))
.And(x => _steps.ThenTheResponseHeaderIs("Tom", "Laura"))
.BDDfy();
}
private void GivenServiceOneIsRunning(string baseUrl, string basePath, int statusCode, string responseBody, string butterflyUrl)
{
_serviceOneBuilder = new WebHostBuilder()
.UseUrls(baseUrl)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.ConfigureServices(services =>
{
services.AddButterfly(option =>
{
option.CollectorUrl = butterflyUrl;
option.Service = "Service One";
option.IgnoredRoutesRegexPatterns = new string[0];
});
})
.Configure(app =>
{
app.UsePathBase(basePath);
app.Run(async context =>
{
_downstreamPathOne = !string.IsNullOrEmpty(context.Request.PathBase.Value) ? context.Request.PathBase.Value : context.Request.Path.Value;
if (_downstreamPathOne != basePath)
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync("downstream path didnt match base path");
}
else
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
}
});
})
.Build();
_serviceOneBuilder.Start();
}
private void GivenFakeButterfly(string baseUrl)
{
_fakeButterfly = new WebHostBuilder()
.UseUrls(baseUrl)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.Configure(app =>
{
app.Run(async context =>
{
_butterflyCalled++;
await context.Response.WriteAsync("OK...");
});
})
.Build();
_fakeButterfly.Start();
}
private void GivenServiceTwoIsRunning(string baseUrl, string basePath, int statusCode, string responseBody, string butterflyUrl)
{
_serviceTwoBuilder = new WebHostBuilder()
.UseUrls(baseUrl)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.ConfigureServices(services =>
{
services.AddButterfly(option =>
{
option.CollectorUrl = butterflyUrl;
option.Service = "Service Two";
option.IgnoredRoutesRegexPatterns = new string[0];
});
})
.Configure(app =>
{
app.UsePathBase(basePath);
app.Run(async context =>
{
_downstreamPathTwo = !string.IsNullOrEmpty(context.Request.PathBase.Value) ? context.Request.PathBase.Value : context.Request.Path.Value;
if (_downstreamPathTwo != basePath)
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync("downstream path didnt match base path");
}
else
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
}
});
})
.Build();
_serviceTwoBuilder.Start();
}
public void Dispose()
{
_serviceOneBuilder?.Dispose();
_serviceTwoBuilder?.Dispose();
_fakeButterfly?.Dispose();
_steps.Dispose();
}
}
}
namespace Ocelot.AcceptanceTests
{
using Butterfly.Client.AspNetCore;
using Configuration.File;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Rafty.Infrastructure;
using Shouldly;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using TestStack.BDDfy;
using Xunit;
using Xunit.Abstractions;
public class ButterflyTracingTests : IDisposable
{
private IWebHost _serviceOneBuilder;
private IWebHost _serviceTwoBuilder;
private IWebHost _fakeButterfly;
private readonly Steps _steps;
private string _downstreamPathOne;
private string _downstreamPathTwo;
private int _butterflyCalled;
private readonly ITestOutputHelper _output;
public ButterflyTracingTests(ITestOutputHelper output)
{
_output = output;
_steps = new Steps();
}
[Fact]
public void should_forward_tracing_information_from_ocelot_and_downstream_services()
{
int port1 = RandomPortFinder.GetRandomPort();
int port2 = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/api/values",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port1,
}
},
UpstreamPathTemplate = "/api001/values",
UpstreamHttpMethod = new List<string> { "Get" },
HttpHandlerOptions = new FileHttpHandlerOptions
{
UseTracing = true
}
},
new FileRoute
{
DownstreamPathTemplate = "/api/values",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port2,
}
},
UpstreamPathTemplate = "/api002/values",
UpstreamHttpMethod = new List<string> { "Get" },
HttpHandlerOptions = new FileHttpHandlerOptions
{
UseTracing = true
}
}
}
};
var butterflyPort = RandomPortFinder.GetRandomPort();
var butterflyUrl = $"http://localhost:{butterflyPort}";
this.Given(x => GivenFakeButterfly(butterflyUrl))
.And(x => GivenServiceOneIsRunning($"http://localhost:{port1}", "/api/values", 200, "Hello from Laura", butterflyUrl))
.And(x => GivenServiceTwoIsRunning($"http://localhost:{port2}", "/api/values", 200, "Hello from Tom", butterflyUrl))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningUsingButterfly(butterflyUrl))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/api001/values"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/api002/values"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Tom"))
.BDDfy();
var commandOnAllStateMachines = Wait.WaitFor(10000).Until(() => _butterflyCalled >= 4);
_output.WriteLine($"_butterflyCalled is {_butterflyCalled}");
commandOnAllStateMachines.ShouldBeTrue();
}
[Fact]
public void should_return_tracing_header()
{
int port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/api/values",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/api001/values",
UpstreamHttpMethod = new List<string> { "Get" },
HttpHandlerOptions = new FileHttpHandlerOptions
{
UseTracing = true
},
DownstreamHeaderTransform = new Dictionary<string, string>()
{
{"Trace-Id", "{TraceId}"},
{"Tom", "Laura"}
}
}
}
};
var butterflyPort = RandomPortFinder.GetRandomPort();
var butterflyUrl = $"http://localhost:{butterflyPort}";
this.Given(x => GivenFakeButterfly(butterflyUrl))
.And(x => GivenServiceOneIsRunning($"http://localhost:{port}", "/api/values", 200, "Hello from Laura", butterflyUrl))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningUsingButterfly(butterflyUrl))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/api001/values"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.And(x => _steps.ThenTheTraceHeaderIsSet("Trace-Id"))
.And(x => _steps.ThenTheResponseHeaderIs("Tom", "Laura"))
.BDDfy();
}
private void GivenServiceOneIsRunning(string baseUrl, string basePath, int statusCode, string responseBody, string butterflyUrl)
{
_serviceOneBuilder = new WebHostBuilder()
.UseUrls(baseUrl)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.ConfigureServices(services =>
{
services.AddButterfly(option =>
{
option.CollectorUrl = butterflyUrl;
option.Service = "Service One";
option.IgnoredRoutesRegexPatterns = new string[0];
});
})
.Configure(app =>
{
app.UsePathBase(basePath);
app.Run(async context =>
{
_downstreamPathOne = !string.IsNullOrEmpty(context.Request.PathBase.Value) ? context.Request.PathBase.Value : context.Request.Path.Value;
if (_downstreamPathOne != basePath)
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync("downstream path didnt match base path");
}
else
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
}
});
})
.Build();
_serviceOneBuilder.Start();
}
private void GivenFakeButterfly(string baseUrl)
{
_fakeButterfly = new WebHostBuilder()
.UseUrls(baseUrl)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.Configure(app =>
{
app.Run(async context =>
{
_butterflyCalled++;
await context.Response.WriteAsync("OK...");
});
})
.Build();
_fakeButterfly.Start();
}
private void GivenServiceTwoIsRunning(string baseUrl, string basePath, int statusCode, string responseBody, string butterflyUrl)
{
_serviceTwoBuilder = new WebHostBuilder()
.UseUrls(baseUrl)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.ConfigureServices(services =>
{
services.AddButterfly(option =>
{
option.CollectorUrl = butterflyUrl;
option.Service = "Service Two";
option.IgnoredRoutesRegexPatterns = new string[0];
});
})
.Configure(app =>
{
app.UsePathBase(basePath);
app.Run(async context =>
{
_downstreamPathTwo = !string.IsNullOrEmpty(context.Request.PathBase.Value) ? context.Request.PathBase.Value : context.Request.Path.Value;
if (_downstreamPathTwo != basePath)
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync("downstream path didnt match base path");
}
else
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
}
});
})
.Build();
_serviceTwoBuilder.Start();
}
public void Dispose()
{
_serviceOneBuilder?.Dispose();
_serviceTwoBuilder?.Dispose();
_fakeButterfly?.Dispose();
_steps.Dispose();
}
}
}

View File

@ -27,9 +27,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -72,9 +72,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -118,9 +118,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -162,9 +162,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>

View File

@ -1,223 +1,223 @@
namespace Ocelot.AcceptanceTests
{
using Ocelot.Configuration.File;
using Shouldly;
using System;
using System.Collections.Generic;
using Xunit;
public class CannotStartOcelotTests : IDisposable
{
private readonly Steps _steps;
public CannotStartOcelotTests()
{
_steps = new Steps();
}
[Fact]
public void should_throw_exception_if_cannot_start_because_service_discovery_provider_specified_in_config_but_no_service_discovery_provider_registered_with_dynamic_re_routes()
{
var invalidConfig = new FileConfiguration
{
GlobalConfiguration = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{
Scheme = "https",
Host = "localhost",
Type = "consul",
Port = 8500
}
}
};
Exception exception = null;
_steps.GivenThereIsAConfiguration(invalidConfig);
try
{
_steps.GivenOcelotIsRunning();
}
catch (Exception ex)
{
exception = ex;
}
exception.ShouldNotBeNull();
exception.Message.ShouldBe("One or more errors occurred. (Unable to start Ocelot, errors are: Unable to start Ocelot, errors are: Unable to start Ocelot because either a ReRoute or GlobalConfiguration are using ServiceDiscoveryOptions but no ServiceDiscoveryFinderDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Consul and services.AddConsul() or Ocelot.Provider.Eureka and services.AddEureka()?)");
}
[Fact]
public void should_throw_exception_if_cannot_start_because_service_discovery_provider_specified_in_config_but_no_service_discovery_provider_registered()
{
var invalidConfig = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
UpstreamPathTemplate = "/laura",
UpstreamHttpMethod = new List<string> { "Get" },
ServiceName = "test"
}
},
GlobalConfiguration = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{
Scheme = "https",
Host = "localhost",
Type = "consul",
Port = 8500
}
}
};
Exception exception = null;
_steps.GivenThereIsAConfiguration(invalidConfig);
try
{
_steps.GivenOcelotIsRunning();
}
catch (Exception ex)
{
exception = ex;
}
exception.ShouldNotBeNull();
exception.Message.ShouldBe("One or more errors occurred. (Unable to start Ocelot, errors are: Unable to start Ocelot, errors are: Unable to start Ocelot because either a ReRoute or GlobalConfiguration are using ServiceDiscoveryOptions but no ServiceDiscoveryFinderDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Consul and services.AddConsul() or Ocelot.Provider.Eureka and services.AddEureka()?,Unable to start Ocelot, errors are: Unable to start Ocelot because either a ReRoute or GlobalConfiguration are using ServiceDiscoveryOptions but no ServiceDiscoveryFinderDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Consul and services.AddConsul() or Ocelot.Provider.Eureka and services.AddEureka()?)");
}
[Fact]
public void should_throw_exception_if_cannot_start_because_no_qos_delegate_registered_globally()
{
var invalidConfig = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51878,
}
},
UpstreamPathTemplate = "/laura",
UpstreamHttpMethod = new List<string> { "Get" },
Key = "Laura",
}
},
GlobalConfiguration = new FileGlobalConfiguration
{
QoSOptions = new FileQoSOptions
{
TimeoutValue = 1,
ExceptionsAllowedBeforeBreaking = 1
}
}
};
Exception exception = null;
_steps.GivenThereIsAConfiguration(invalidConfig);
try
{
_steps.GivenOcelotIsRunning();
}
catch (Exception ex)
{
exception = ex;
}
exception.ShouldNotBeNull();
exception.Message.ShouldBe("One or more errors occurred. (Unable to start Ocelot, errors are: Unable to start Ocelot because either a ReRoute or GlobalConfiguration are using QoSOptions but no QosDelegatingHandlerDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Polly and services.AddPolly()?)");
}
[Fact]
public void should_throw_exception_if_cannot_start_because_no_qos_delegate_registered_for_re_route()
{
var invalidConfig = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51878,
}
},
UpstreamPathTemplate = "/laura",
UpstreamHttpMethod = new List<string> { "Get" },
Key = "Laura",
QoSOptions = new FileQoSOptions
{
TimeoutValue = 1,
ExceptionsAllowedBeforeBreaking = 1
}
}
}
};
Exception exception = null;
_steps.GivenThereIsAConfiguration(invalidConfig);
try
{
_steps.GivenOcelotIsRunning();
}
catch (Exception ex)
{
exception = ex;
}
exception.ShouldNotBeNull();
exception.Message.ShouldBe("One or more errors occurred. (Unable to start Ocelot, errors are: Unable to start Ocelot because either a ReRoute or GlobalConfiguration are using QoSOptions but no QosDelegatingHandlerDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Polly and services.AddPolly()?)");
}
[Fact]
public void should_throw_exception_if_cannot_start()
{
var invalidConfig = new FileConfiguration()
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
UpstreamPathTemplate = "api",
DownstreamPathTemplate = "test"
}
}
};
Exception exception = null;
_steps.GivenThereIsAConfiguration(invalidConfig);
try
{
_steps.GivenOcelotIsRunning();
}
catch (Exception ex)
{
exception = ex;
}
exception.ShouldNotBeNull();
exception.Message.ShouldBe("One or more errors occurred. (Unable to start Ocelot, errors are: Downstream Path Template test doesnt start with forward slash,Upstream Path Template api doesnt start with forward slash,When not using service discovery DownstreamHostAndPorts must be set and not empty or Ocelot cannot find your service!)");
}
public void Dispose()
{
_steps.Dispose();
}
}
}
namespace Ocelot.AcceptanceTests
{
using Ocelot.Configuration.File;
using Shouldly;
using System;
using System.Collections.Generic;
using Xunit;
public class CannotStartOcelotTests : IDisposable
{
private readonly Steps _steps;
public CannotStartOcelotTests()
{
_steps = new Steps();
}
[Fact]
public void should_throw_exception_if_cannot_start_because_service_discovery_provider_specified_in_config_but_no_service_discovery_provider_registered_with_dynamic_re_routes()
{
var invalidConfig = new FileConfiguration
{
GlobalConfiguration = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{
Scheme = "https",
Host = "localhost",
Type = "consul",
Port = 8500
}
}
};
Exception exception = null;
_steps.GivenThereIsAConfiguration(invalidConfig);
try
{
_steps.GivenOcelotIsRunning();
}
catch (Exception ex)
{
exception = ex;
}
exception.ShouldNotBeNull();
exception.Message.ShouldBe("One or more errors occurred. (Unable to start Ocelot, errors are: Unable to start Ocelot, errors are: Unable to start Ocelot because either a Route or GlobalConfiguration are using ServiceDiscoveryOptions but no ServiceDiscoveryFinderDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Consul and services.AddConsul() or Ocelot.Provider.Eureka and services.AddEureka()?)");
}
[Fact]
public void should_throw_exception_if_cannot_start_because_service_discovery_provider_specified_in_config_but_no_service_discovery_provider_registered()
{
var invalidConfig = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
UpstreamPathTemplate = "/laura",
UpstreamHttpMethod = new List<string> { "Get" },
ServiceName = "test"
}
},
GlobalConfiguration = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{
Scheme = "https",
Host = "localhost",
Type = "consul",
Port = 8500
}
}
};
Exception exception = null;
_steps.GivenThereIsAConfiguration(invalidConfig);
try
{
_steps.GivenOcelotIsRunning();
}
catch (Exception ex)
{
exception = ex;
}
exception.ShouldNotBeNull();
exception.Message.ShouldBe("One or more errors occurred. (Unable to start Ocelot, errors are: Unable to start Ocelot, errors are: Unable to start Ocelot because either a Route or GlobalConfiguration are using ServiceDiscoveryOptions but no ServiceDiscoveryFinderDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Consul and services.AddConsul() or Ocelot.Provider.Eureka and services.AddEureka()?,Unable to start Ocelot, errors are: Unable to start Ocelot because either a Route or GlobalConfiguration are using ServiceDiscoveryOptions but no ServiceDiscoveryFinderDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Consul and services.AddConsul() or Ocelot.Provider.Eureka and services.AddEureka()?)");
}
[Fact]
public void should_throw_exception_if_cannot_start_because_no_qos_delegate_registered_globally()
{
var invalidConfig = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51878,
}
},
UpstreamPathTemplate = "/laura",
UpstreamHttpMethod = new List<string> { "Get" },
Key = "Laura",
}
},
GlobalConfiguration = new FileGlobalConfiguration
{
QoSOptions = new FileQoSOptions
{
TimeoutValue = 1,
ExceptionsAllowedBeforeBreaking = 1
}
}
};
Exception exception = null;
_steps.GivenThereIsAConfiguration(invalidConfig);
try
{
_steps.GivenOcelotIsRunning();
}
catch (Exception ex)
{
exception = ex;
}
exception.ShouldNotBeNull();
exception.Message.ShouldBe("One or more errors occurred. (Unable to start Ocelot, errors are: Unable to start Ocelot because either a Route or GlobalConfiguration are using QoSOptions but no QosDelegatingHandlerDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Polly and services.AddPolly()?)");
}
[Fact]
public void should_throw_exception_if_cannot_start_because_no_qos_delegate_registered_for_re_route()
{
var invalidConfig = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51878,
}
},
UpstreamPathTemplate = "/laura",
UpstreamHttpMethod = new List<string> { "Get" },
Key = "Laura",
QoSOptions = new FileQoSOptions
{
TimeoutValue = 1,
ExceptionsAllowedBeforeBreaking = 1
}
}
}
};
Exception exception = null;
_steps.GivenThereIsAConfiguration(invalidConfig);
try
{
_steps.GivenOcelotIsRunning();
}
catch (Exception ex)
{
exception = ex;
}
exception.ShouldNotBeNull();
exception.Message.ShouldBe("One or more errors occurred. (Unable to start Ocelot, errors are: Unable to start Ocelot because either a Route or GlobalConfiguration are using QoSOptions but no QosDelegatingHandlerDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Polly and services.AddPolly()?)");
}
[Fact]
public void should_throw_exception_if_cannot_start()
{
var invalidConfig = new FileConfiguration()
{
Routes = new List<FileRoute>
{
new FileRoute
{
UpstreamPathTemplate = "api",
DownstreamPathTemplate = "test"
}
}
};
Exception exception = null;
_steps.GivenThereIsAConfiguration(invalidConfig);
try
{
_steps.GivenOcelotIsRunning();
}
catch (Exception ex)
{
exception = ex;
}
exception.ShouldNotBeNull();
exception.Message.ShouldBe("One or more errors occurred. (Unable to start Ocelot, errors are: Downstream Path Template test doesnt start with forward slash,Upstream Path Template api doesnt start with forward slash,When not using service discovery DownstreamHostAndPorts must be set and not empty or Ocelot cannot find your service!)");
}
public void Dispose()
{
_steps.Dispose();
}
}
}

View File

@ -6,7 +6,7 @@ namespace Ocelot.AcceptanceTests
using System.Collections.Generic;
using System.Net;
using TestStack.BDDfy;
using Xunit;
using Xunit;
public class CaseSensitiveRoutingTests : IDisposable
{
@ -21,14 +21,14 @@ namespace Ocelot.AcceptanceTests
[Fact]
public void should_return_response_200_when_global_ignore_case_sensitivity_set()
{
int port = RandomPortFinder.GetRandomPort();
{
int port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/api/products/{productId}",
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -55,15 +55,15 @@ namespace Ocelot.AcceptanceTests
}
[Fact]
public void should_return_response_200_when_reroute_ignore_case_sensitivity_set()
{
int port = RandomPortFinder.GetRandomPort();
public void should_return_response_200_when_route_ignore_case_sensitivity_set()
{
int port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/api/products/{productId}",
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -77,7 +77,7 @@ namespace Ocelot.AcceptanceTests
DownstreamScheme = "http",
UpstreamPathTemplate = "/products/{productId}",
UpstreamHttpMethod = new List<string> { "Get" },
ReRouteIsCaseSensitive = false,
RouteIsCaseSensitive = false,
}
}
};
@ -91,15 +91,15 @@ namespace Ocelot.AcceptanceTests
}
[Fact]
public void should_return_response_404_when_reroute_respect_case_sensitivity_set()
{
int port = RandomPortFinder.GetRandomPort();
public void should_return_response_404_when_route_respect_case_sensitivity_set()
{
int port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/api/products/{productId}",
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -113,7 +113,7 @@ namespace Ocelot.AcceptanceTests
DownstreamScheme = "http",
UpstreamPathTemplate = "/products/{productId}",
UpstreamHttpMethod = new List<string> { "Get" },
ReRouteIsCaseSensitive = true,
RouteIsCaseSensitive = true,
}
}
};
@ -127,15 +127,15 @@ namespace Ocelot.AcceptanceTests
}
[Fact]
public void should_return_response_200_when_reroute_respect_case_sensitivity_set()
{
int port = RandomPortFinder.GetRandomPort();
public void should_return_response_200_when_route_respect_case_sensitivity_set()
{
int port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/api/products/{productId}",
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -149,7 +149,7 @@ namespace Ocelot.AcceptanceTests
DownstreamScheme = "http",
UpstreamPathTemplate = "/PRODUCTS/{productId}",
UpstreamHttpMethod = new List<string> { "Get" },
ReRouteIsCaseSensitive = true,
RouteIsCaseSensitive = true,
}
}
};
@ -164,14 +164,14 @@ namespace Ocelot.AcceptanceTests
[Fact]
public void should_return_response_404_when_global_respect_case_sensitivity_set()
{
int port = RandomPortFinder.GetRandomPort();
{
int port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/api/products/{productId}",
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -185,7 +185,7 @@ namespace Ocelot.AcceptanceTests
DownstreamScheme = "http",
UpstreamPathTemplate = "/products/{productId}",
UpstreamHttpMethod = new List<string> { "Get" },
ReRouteIsCaseSensitive = true,
RouteIsCaseSensitive = true,
}
}
};
@ -200,14 +200,14 @@ namespace Ocelot.AcceptanceTests
[Fact]
public void should_return_response_200_when_global_respect_case_sensitivity_set()
{
int port = RandomPortFinder.GetRandomPort();
{
int port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/api/products/{productId}",
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -221,7 +221,7 @@ namespace Ocelot.AcceptanceTests
DownstreamScheme = "http",
UpstreamPathTemplate = "/PRODUCTS/{productId}",
UpstreamHttpMethod = new List<string> { "Get" },
ReRouteIsCaseSensitive = true,
RouteIsCaseSensitive = true,
}
}
};
@ -249,4 +249,4 @@ namespace Ocelot.AcceptanceTests
_steps.Dispose();
}
}
}
}

View File

@ -1,205 +1,205 @@
using Xunit;
namespace Ocelot.AcceptanceTests
{
using IdentityServer4.AccessTokenValidation;
using IdentityServer4.Models;
using IdentityServer4.Test;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Ocelot.Configuration.File;
using Shouldly;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using TestStack.BDDfy;
public class ClaimsToDownstreamPathTests : IDisposable
{
private IWebHost _servicebuilder;
private IWebHost _identityServerBuilder;
private readonly Steps _steps;
private Action<IdentityServerAuthenticationOptions> _options;
private string _identityServerRootUrl;
private string _downstreamFinalPath;
public ClaimsToDownstreamPathTests()
{
var identityServerPort = RandomPortFinder.GetRandomPort();
_identityServerRootUrl = $"http://localhost:{identityServerPort}";
_steps = new Steps();
_options = o =>
{
o.Authority = _identityServerRootUrl;
o.ApiName = "api";
o.RequireHttpsMetadata = false;
o.SupportedTokens = SupportedTokens.Both;
o.ApiSecret = "secret";
};
}
[Fact]
public void should_return_200_and_change_downstream_path()
{
var user = new TestUser()
{
Username = "test",
Password = "test",
SubjectId = "registered|1231231",
};
int port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/users/{userId}",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
},
},
DownstreamScheme = "http",
UpstreamPathTemplate = "/users",
UpstreamHttpMethod = new List<string> { "Get" },
AuthenticationOptions = new FileAuthenticationOptions
{
AuthenticationProviderKey = "Test",
AllowedScopes = new List<string>
{
"openid", "offline_access", "api",
},
},
ChangeDownstreamPathTemplate =
{
{"userId", "Claims[sub] > value[1] > |"},
},
},
},
};
this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", AccessTokenType.Jwt, user))
.And(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", 200))
.And(x => _steps.GivenIHaveAToken(_identityServerRootUrl))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning(_options, "Test"))
.And(x => _steps.GivenIHaveAddedATokenToMyRequest())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/users"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("UserId: 1231231"))
.And(x => _downstreamFinalPath.ShouldBe("/users/1231231"))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string url, int statusCode)
{
_servicebuilder = new WebHostBuilder()
.UseUrls(url)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseUrls(url)
.Configure(app =>
{
app.Run(async context =>
{
_downstreamFinalPath = context.Request.Path.Value;
string userId = _downstreamFinalPath.Replace("/users/", string.Empty);
var responseBody = $"UserId: {userId}";
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
});
})
.Build();
_servicebuilder.Start();
}
private void GivenThereIsAnIdentityServerOn(string url, string apiName, AccessTokenType tokenType, TestUser user)
{
_identityServerBuilder = new WebHostBuilder()
.UseUrls(url)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseUrls(url)
.ConfigureServices(services =>
{
services.AddLogging();
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryApiResources(new List<ApiResource>
{
new ApiResource
{
Name = apiName,
Description = "My API",
Enabled = true,
DisplayName = "test",
Scopes = new List<Scope>()
{
new Scope("api"),
new Scope("openid"),
new Scope("offline_access")
},
ApiSecrets = new List<Secret>()
{
new Secret
{
Value = "secret".Sha256()
}
},
UserClaims = new List<string>()
{
"CustomerId", "LocationId", "UserType", "UserId"
}
}
})
.AddInMemoryClients(new List<Client>
{
new Client
{
ClientId = "client",
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
ClientSecrets = new List<Secret> {new Secret("secret".Sha256())},
AllowedScopes = new List<string> { apiName, "openid", "offline_access" },
AccessTokenType = tokenType,
Enabled = true,
RequireClientSecret = false
}
})
.AddTestUsers(new List<TestUser>
{
user
});
})
.Configure(app =>
{
app.UseIdentityServer();
})
.Build();
_identityServerBuilder.Start();
_steps.VerifyIdentiryServerStarted(url);
}
public void Dispose()
{
_servicebuilder?.Dispose();
_steps.Dispose();
_identityServerBuilder?.Dispose();
}
}
}
using Xunit;
namespace Ocelot.AcceptanceTests
{
using IdentityServer4.AccessTokenValidation;
using IdentityServer4.Models;
using IdentityServer4.Test;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Ocelot.Configuration.File;
using Shouldly;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using TestStack.BDDfy;
public class ClaimsToDownstreamPathTests : IDisposable
{
private IWebHost _servicebuilder;
private IWebHost _identityServerBuilder;
private readonly Steps _steps;
private Action<IdentityServerAuthenticationOptions> _options;
private string _identityServerRootUrl;
private string _downstreamFinalPath;
public ClaimsToDownstreamPathTests()
{
var identityServerPort = RandomPortFinder.GetRandomPort();
_identityServerRootUrl = $"http://localhost:{identityServerPort}";
_steps = new Steps();
_options = o =>
{
o.Authority = _identityServerRootUrl;
o.ApiName = "api";
o.RequireHttpsMetadata = false;
o.SupportedTokens = SupportedTokens.Both;
o.ApiSecret = "secret";
};
}
[Fact]
public void should_return_200_and_change_downstream_path()
{
var user = new TestUser()
{
Username = "test",
Password = "test",
SubjectId = "registered|1231231",
};
int port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/users/{userId}",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
},
},
DownstreamScheme = "http",
UpstreamPathTemplate = "/users",
UpstreamHttpMethod = new List<string> { "Get" },
AuthenticationOptions = new FileAuthenticationOptions
{
AuthenticationProviderKey = "Test",
AllowedScopes = new List<string>
{
"openid", "offline_access", "api",
},
},
ChangeDownstreamPathTemplate =
{
{"userId", "Claims[sub] > value[1] > |"},
},
},
},
};
this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", AccessTokenType.Jwt, user))
.And(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", 200))
.And(x => _steps.GivenIHaveAToken(_identityServerRootUrl))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning(_options, "Test"))
.And(x => _steps.GivenIHaveAddedATokenToMyRequest())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/users"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("UserId: 1231231"))
.And(x => _downstreamFinalPath.ShouldBe("/users/1231231"))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string url, int statusCode)
{
_servicebuilder = new WebHostBuilder()
.UseUrls(url)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseUrls(url)
.Configure(app =>
{
app.Run(async context =>
{
_downstreamFinalPath = context.Request.Path.Value;
string userId = _downstreamFinalPath.Replace("/users/", string.Empty);
var responseBody = $"UserId: {userId}";
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
});
})
.Build();
_servicebuilder.Start();
}
private void GivenThereIsAnIdentityServerOn(string url, string apiName, AccessTokenType tokenType, TestUser user)
{
_identityServerBuilder = new WebHostBuilder()
.UseUrls(url)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseUrls(url)
.ConfigureServices(services =>
{
services.AddLogging();
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryApiResources(new List<ApiResource>
{
new ApiResource
{
Name = apiName,
Description = "My API",
Enabled = true,
DisplayName = "test",
Scopes = new List<Scope>()
{
new Scope("api"),
new Scope("openid"),
new Scope("offline_access")
},
ApiSecrets = new List<Secret>()
{
new Secret
{
Value = "secret".Sha256()
}
},
UserClaims = new List<string>()
{
"CustomerId", "LocationId", "UserType", "UserId"
}
}
})
.AddInMemoryClients(new List<Client>
{
new Client
{
ClientId = "client",
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
ClientSecrets = new List<Secret> {new Secret("secret".Sha256())},
AllowedScopes = new List<string> { apiName, "openid", "offline_access" },
AccessTokenType = tokenType,
Enabled = true,
RequireClientSecret = false
}
})
.AddTestUsers(new List<TestUser>
{
user
});
})
.Configure(app =>
{
app.UseIdentityServer();
})
.Build();
_identityServerBuilder.Start();
_steps.VerifyIdentiryServerStarted(url);
}
public void Dispose()
{
_servicebuilder?.Dispose();
_steps.Dispose();
_identityServerBuilder?.Dispose();
}
}
}

View File

@ -63,9 +63,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>

View File

@ -62,9 +62,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -128,9 +128,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>

View File

@ -1,222 +1,222 @@
namespace Ocelot.AcceptanceTests
{
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using TestStack.BDDfy;
using Xunit;
public class ClientRateLimitTests : IDisposable
{
private readonly Steps _steps;
private int _counterOne;
private readonly ServiceHandler _serviceHandler;
public ClientRateLimitTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
}
[Fact]
public void should_call_withratelimiting()
{
int port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/api/ClientRateLimit",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
DownstreamScheme = "http",
UpstreamPathTemplate = "/api/ClientRateLimit",
UpstreamHttpMethod = new List<string> { "Get" },
RequestIdKey = _steps.RequestIdKey,
RateLimitOptions = new FileRateLimitRule()
{
EnableRateLimiting = true,
ClientWhitelist = new List<string>(),
Limit = 3,
Period = "1s",
PeriodTimespan = 1000
}
}
},
GlobalConfiguration = new FileGlobalConfiguration()
{
RateLimitOptions = new FileRateLimitOptions()
{
ClientIdHeader = "ClientId",
DisableRateLimitHeaders = false,
QuotaExceededMessage = "",
RateLimitCounterPrefix = "",
HttpStatusCode = 428
},
RequestIdKey = "oceclientrequest"
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/api/ClientRateLimit"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/api/ClientRateLimit", 1))
.Then(x => _steps.ThenTheStatusCodeShouldBe(200))
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/api/ClientRateLimit", 2))
.Then(x => _steps.ThenTheStatusCodeShouldBe(200))
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/api/ClientRateLimit", 1))
.Then(x => _steps.ThenTheStatusCodeShouldBe(428))
.BDDfy();
}
[Fact]
public void should_wait_for_period_timespan_to_elapse_before_making_next_request()
{
int port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/api/ClientRateLimit",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
DownstreamScheme = "http",
UpstreamPathTemplate = "/api/ClientRateLimit",
UpstreamHttpMethod = new List<string> { "Get" },
RequestIdKey = _steps.RequestIdKey,
RateLimitOptions = new FileRateLimitRule()
{
EnableRateLimiting = true,
ClientWhitelist = new List<string>(),
Limit = 3,
Period = "1s",
PeriodTimespan = 2
}
}
},
GlobalConfiguration = new FileGlobalConfiguration()
{
RateLimitOptions = new FileRateLimitOptions()
{
ClientIdHeader = "ClientId",
DisableRateLimitHeaders = false,
QuotaExceededMessage = "",
RateLimitCounterPrefix = "",
HttpStatusCode = 428
},
RequestIdKey = "oceclientrequest"
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/api/ClientRateLimit"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/api/ClientRateLimit", 1))
.Then(x => _steps.ThenTheStatusCodeShouldBe(200))
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/api/ClientRateLimit", 2))
.Then(x => _steps.ThenTheStatusCodeShouldBe(200))
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/api/ClientRateLimit", 1))
.Then(x => _steps.ThenTheStatusCodeShouldBe(428))
.And(x => _steps.GivenIWait(1000))
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/api/ClientRateLimit", 1))
.Then(x => _steps.ThenTheStatusCodeShouldBe(428))
.And(x => _steps.GivenIWait(1000))
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/api/ClientRateLimit", 1))
.Then(x => _steps.ThenTheStatusCodeShouldBe(200))
.BDDfy();
}
[Fact]
public void should_call_middleware_withWhitelistClient()
{
int port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/api/ClientRateLimit",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
DownstreamScheme = "http",
UpstreamPathTemplate = "/api/ClientRateLimit",
UpstreamHttpMethod = new List<string> { "Get" },
RequestIdKey = _steps.RequestIdKey,
RateLimitOptions = new FileRateLimitRule()
{
EnableRateLimiting = true,
ClientWhitelist = new List<string>() { "ocelotclient1"},
Limit = 3,
Period = "1s",
PeriodTimespan = 100
}
}
},
GlobalConfiguration = new FileGlobalConfiguration()
{
RateLimitOptions = new FileRateLimitOptions()
{
ClientIdHeader = "ClientId",
DisableRateLimitHeaders = false,
QuotaExceededMessage = "",
RateLimitCounterPrefix = ""
},
RequestIdKey = "oceclientrequest"
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/api/ClientRateLimit"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/api/ClientRateLimit", 4))
.Then(x => _steps.ThenTheStatusCodeShouldBe(200))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath)
{
_serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, context =>
{
_counterOne++;
context.Response.StatusCode = 200;
context.Response.WriteAsync(_counterOne.ToString());
return Task.CompletedTask;
});
}
public void Dispose()
{
_steps.Dispose();
}
}
}
namespace Ocelot.AcceptanceTests
{
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using TestStack.BDDfy;
using Xunit;
public class ClientRateLimitTests : IDisposable
{
private readonly Steps _steps;
private int _counterOne;
private readonly ServiceHandler _serviceHandler;
public ClientRateLimitTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
}
[Fact]
public void should_call_withratelimiting()
{
int port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/api/ClientRateLimit",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
DownstreamScheme = "http",
UpstreamPathTemplate = "/api/ClientRateLimit",
UpstreamHttpMethod = new List<string> { "Get" },
RequestIdKey = _steps.RequestIdKey,
RateLimitOptions = new FileRateLimitRule()
{
EnableRateLimiting = true,
ClientWhitelist = new List<string>(),
Limit = 3,
Period = "1s",
PeriodTimespan = 1000
}
}
},
GlobalConfiguration = new FileGlobalConfiguration()
{
RateLimitOptions = new FileRateLimitOptions()
{
ClientIdHeader = "ClientId",
DisableRateLimitHeaders = false,
QuotaExceededMessage = "",
RateLimitCounterPrefix = "",
HttpStatusCode = 428
},
RequestIdKey = "oceclientrequest"
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/api/ClientRateLimit"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/api/ClientRateLimit", 1))
.Then(x => _steps.ThenTheStatusCodeShouldBe(200))
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/api/ClientRateLimit", 2))
.Then(x => _steps.ThenTheStatusCodeShouldBe(200))
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/api/ClientRateLimit", 1))
.Then(x => _steps.ThenTheStatusCodeShouldBe(428))
.BDDfy();
}
[Fact]
public void should_wait_for_period_timespan_to_elapse_before_making_next_request()
{
int port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/api/ClientRateLimit",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
DownstreamScheme = "http",
UpstreamPathTemplate = "/api/ClientRateLimit",
UpstreamHttpMethod = new List<string> { "Get" },
RequestIdKey = _steps.RequestIdKey,
RateLimitOptions = new FileRateLimitRule()
{
EnableRateLimiting = true,
ClientWhitelist = new List<string>(),
Limit = 3,
Period = "1s",
PeriodTimespan = 2
}
}
},
GlobalConfiguration = new FileGlobalConfiguration()
{
RateLimitOptions = new FileRateLimitOptions()
{
ClientIdHeader = "ClientId",
DisableRateLimitHeaders = false,
QuotaExceededMessage = "",
RateLimitCounterPrefix = "",
HttpStatusCode = 428
},
RequestIdKey = "oceclientrequest"
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/api/ClientRateLimit"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/api/ClientRateLimit", 1))
.Then(x => _steps.ThenTheStatusCodeShouldBe(200))
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/api/ClientRateLimit", 2))
.Then(x => _steps.ThenTheStatusCodeShouldBe(200))
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/api/ClientRateLimit", 1))
.Then(x => _steps.ThenTheStatusCodeShouldBe(428))
.And(x => _steps.GivenIWait(1000))
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/api/ClientRateLimit", 1))
.Then(x => _steps.ThenTheStatusCodeShouldBe(428))
.And(x => _steps.GivenIWait(1000))
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/api/ClientRateLimit", 1))
.Then(x => _steps.ThenTheStatusCodeShouldBe(200))
.BDDfy();
}
[Fact]
public void should_call_middleware_withWhitelistClient()
{
int port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/api/ClientRateLimit",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
DownstreamScheme = "http",
UpstreamPathTemplate = "/api/ClientRateLimit",
UpstreamHttpMethod = new List<string> { "Get" },
RequestIdKey = _steps.RequestIdKey,
RateLimitOptions = new FileRateLimitRule()
{
EnableRateLimiting = true,
ClientWhitelist = new List<string>() { "ocelotclient1"},
Limit = 3,
Period = "1s",
PeriodTimespan = 100
}
}
},
GlobalConfiguration = new FileGlobalConfiguration()
{
RateLimitOptions = new FileRateLimitOptions()
{
ClientIdHeader = "ClientId",
DisableRateLimitHeaders = false,
QuotaExceededMessage = "",
RateLimitCounterPrefix = ""
},
RequestIdKey = "oceclientrequest"
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/api/ClientRateLimit"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/api/ClientRateLimit", 4))
.Then(x => _steps.ThenTheStatusCodeShouldBe(200))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath)
{
_serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, context =>
{
_counterOne++;
context.Response.StatusCode = 200;
context.Response.WriteAsync(_counterOne.ToString());
return Task.CompletedTask;
});
}
public void Dispose()
{
_steps.Dispose();
}
}
}

View File

@ -1,188 +1,188 @@
namespace Ocelot.AcceptanceTests
{
using Configuration.File;
using Consul;
using IdentityServer4.Extensions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using TestStack.BDDfy;
using Xunit;
public class ConfigurationInConsulTests : IDisposable
{
private IHost _builder;
private readonly Steps _steps;
private IHost _fakeConsulBuilder;
private FileConfiguration _config;
private readonly List<ServiceEntry> _consulServices;
public ConfigurationInConsulTests()
{
_consulServices = new List<ServiceEntry>();
_steps = new Steps();
}
[Fact]
public void should_return_response_200_with_simple_url_when_using_jsonserialized_cache()
{
int consulPort = RandomPortFinder.GetRandomPort();
int servicePort = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = servicePort,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
},
GlobalConfiguration = new FileGlobalConfiguration()
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Scheme = "http",
Host = "localhost",
Port = consulPort
}
}
};
var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}";
this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, ""))
.And(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{servicePort}", "", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfigAndJsonSerializedCache())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url, string serviceName)
{
_fakeConsulBuilder = Host.CreateDefaultBuilder()
.ConfigureWebHost(webBuilder =>
{
webBuilder.UseUrls(url)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseUrls(url)
.Configure(app =>
{
app.Run(async context =>
{
if (context.Request.Method.ToLower() == "get" && context.Request.Path.Value == "/v1/kv/InternalConfiguration")
{
var json = JsonConvert.SerializeObject(_config);
var bytes = Encoding.UTF8.GetBytes(json);
var base64 = Convert.ToBase64String(bytes);
var kvp = new FakeConsulGetResponse(base64);
await context.Response.WriteJsonAsync(new FakeConsulGetResponse[] { kvp });
}
else if (context.Request.Method.ToLower() == "put" && context.Request.Path.Value == "/v1/kv/InternalConfiguration")
{
try
{
var reader = new StreamReader(context.Request.Body);
// Synchronous operations are disallowed. Call ReadAsync or set AllowSynchronousIO to true instead.
// var json = reader.ReadToEnd();
var json = await reader.ReadToEndAsync();
_config = JsonConvert.DeserializeObject<FileConfiguration>(json);
var response = JsonConvert.SerializeObject(true);
await context.Response.WriteAsync(response);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
else if (context.Request.Path.Value == $"/v1/health/service/{serviceName}")
{
await context.Response.WriteJsonAsync(_consulServices);
}
});
});
}).Build();
_fakeConsulBuilder.Start();
}
public class FakeConsulGetResponse
{
public FakeConsulGetResponse(string value)
{
Value = value;
}
public int CreateIndex => 100;
public int ModifyIndex => 200;
public int LockIndex => 200;
public string Key => "InternalConfiguration";
public int Flags => 0;
public string Value { get; private set; }
public string Session => "adf4238a-882b-9ddc-4a9d-5b6758e4159e";
}
private void GivenThereIsAServiceRunningOn(string url, string basePath, int statusCode, string responseBody)
{
_builder = Host.CreateDefaultBuilder()
.ConfigureWebHost(webBuilder =>
{
webBuilder.UseUrls(url)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseUrls(url)
.Configure(app =>
{
app.UsePathBase(basePath);
app.Run(async context =>
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
});
});
})
.Build();
_builder.Start();
}
public void Dispose()
{
_builder?.Dispose();
_steps.Dispose();
}
}
}
namespace Ocelot.AcceptanceTests
{
using Configuration.File;
using Consul;
using IdentityServer4.Extensions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using TestStack.BDDfy;
using Xunit;
public class ConfigurationInConsulTests : IDisposable
{
private IHost _builder;
private readonly Steps _steps;
private IHost _fakeConsulBuilder;
private FileConfiguration _config;
private readonly List<ServiceEntry> _consulServices;
public ConfigurationInConsulTests()
{
_consulServices = new List<ServiceEntry>();
_steps = new Steps();
}
[Fact]
public void should_return_response_200_with_simple_url_when_using_jsonserialized_cache()
{
int consulPort = RandomPortFinder.GetRandomPort();
int servicePort = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = servicePort,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
},
GlobalConfiguration = new FileGlobalConfiguration()
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Scheme = "http",
Host = "localhost",
Port = consulPort
}
}
};
var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}";
this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, ""))
.And(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{servicePort}", "", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfigAndJsonSerializedCache())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url, string serviceName)
{
_fakeConsulBuilder = Host.CreateDefaultBuilder()
.ConfigureWebHost(webBuilder =>
{
webBuilder.UseUrls(url)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseUrls(url)
.Configure(app =>
{
app.Run(async context =>
{
if (context.Request.Method.ToLower() == "get" && context.Request.Path.Value == "/v1/kv/InternalConfiguration")
{
var json = JsonConvert.SerializeObject(_config);
var bytes = Encoding.UTF8.GetBytes(json);
var base64 = Convert.ToBase64String(bytes);
var kvp = new FakeConsulGetResponse(base64);
await context.Response.WriteJsonAsync(new FakeConsulGetResponse[] { kvp });
}
else if (context.Request.Method.ToLower() == "put" && context.Request.Path.Value == "/v1/kv/InternalConfiguration")
{
try
{
var reader = new StreamReader(context.Request.Body);
// Synchronous operations are disallowed. Call ReadAsync or set AllowSynchronousIO to true instead.
// var json = reader.ReadToEnd();
var json = await reader.ReadToEndAsync();
_config = JsonConvert.DeserializeObject<FileConfiguration>(json);
var response = JsonConvert.SerializeObject(true);
await context.Response.WriteAsync(response);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
else if (context.Request.Path.Value == $"/v1/health/service/{serviceName}")
{
await context.Response.WriteJsonAsync(_consulServices);
}
});
});
}).Build();
_fakeConsulBuilder.Start();
}
public class FakeConsulGetResponse
{
public FakeConsulGetResponse(string value)
{
Value = value;
}
public int CreateIndex => 100;
public int ModifyIndex => 200;
public int LockIndex => 200;
public string Key => "InternalConfiguration";
public int Flags => 0;
public string Value { get; private set; }
public string Session => "adf4238a-882b-9ddc-4a9d-5b6758e4159e";
}
private void GivenThereIsAServiceRunningOn(string url, string basePath, int statusCode, string responseBody)
{
_builder = Host.CreateDefaultBuilder()
.ConfigureWebHost(webBuilder =>
{
webBuilder.UseUrls(url)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseUrls(url)
.Configure(app =>
{
app.UsePathBase(basePath);
app.Run(async context =>
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
});
});
})
.Build();
_builder.Start();
}
public void Dispose()
{
_builder?.Dispose();
_steps.Dispose();
}
}
}

View File

@ -1,487 +1,487 @@
namespace Ocelot.AcceptanceTests
{
using Cache;
using Configuration.File;
using Consul;
using Infrastructure;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using Shouldly;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using TestStack.BDDfy;
using Xunit;
public class ConsulConfigurationInConsulTests : IDisposable
{
private IWebHost _builder;
private readonly Steps _steps;
private IWebHost _fakeConsulBuilder;
private FileConfiguration _config;
private readonly List<ServiceEntry> _consulServices;
public ConsulConfigurationInConsulTests()
{
_consulServices = new List<ServiceEntry>();
_steps = new Steps();
}
[Fact]
public void should_return_response_200_with_simple_url()
{
int consulPort = RandomPortFinder.GetRandomPort();
int servicePort = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = servicePort,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
},
GlobalConfiguration = new FileGlobalConfiguration()
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Scheme = "http",
Host = "localhost",
Port = consulPort
}
}
};
var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}";
this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, ""))
.And(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{servicePort}", "", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfig())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_load_configuration_out_of_consul()
{
var consulPort = RandomPortFinder.GetRandomPort();
int servicePort = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
GlobalConfiguration = new FileGlobalConfiguration()
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Scheme = "http",
Host = "localhost",
Port = consulPort
}
}
};
var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}";
var consulConfig = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/status",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = servicePort,
}
},
UpstreamPathTemplate = "/cs/status",
UpstreamHttpMethod = new List<string> {"Get"}
}
},
GlobalConfiguration = new FileGlobalConfiguration()
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Scheme = "http",
Host = "localhost",
Port = consulPort
}
}
};
this.Given(x => GivenTheConsulConfigurationIs(consulConfig))
.And(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, ""))
.And(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{servicePort}", "/status", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfig())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/cs/status"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_load_configuration_out_of_consul_if_it_is_changed()
{
var consulPort = RandomPortFinder.GetRandomPort();
int servicePort = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
GlobalConfiguration = new FileGlobalConfiguration()
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Scheme = "http",
Host = "localhost",
Port = consulPort
}
}
};
var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}";
var consulConfig = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/status",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = servicePort,
}
},
UpstreamPathTemplate = "/cs/status",
UpstreamHttpMethod = new List<string> {"Get"}
}
},
GlobalConfiguration = new FileGlobalConfiguration()
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Scheme = "http",
Host = "localhost",
Port = consulPort
}
}
};
var secondConsulConfig = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/status",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = servicePort,
}
},
UpstreamPathTemplate = "/cs/status/awesome",
UpstreamHttpMethod = new List<string> {"Get"}
}
},
GlobalConfiguration = new FileGlobalConfiguration()
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Scheme = "http",
Host = "localhost",
Port = consulPort
}
}
};
this.Given(x => GivenTheConsulConfigurationIs(consulConfig))
.And(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, ""))
.And(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{servicePort}", "/status", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfig())
.And(x => _steps.WhenIGetUrlOnTheApiGateway("/cs/status"))
.And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.When(x => GivenTheConsulConfigurationIs(secondConsulConfig))
.Then(x => ThenTheConfigIsUpdatedInOcelot())
.BDDfy();
}
[Fact]
public void should_handle_request_to_consul_for_downstream_service_and_make_request_no_re_routes_and_rate_limit()
{
int consulPort = RandomPortFinder.GetRandomPort();
const string serviceName = "web";
int downstreamServicePort = RandomPortFinder.GetRandomPort();
var downstreamServiceOneUrl = $"http://localhost:{downstreamServicePort}";
var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}";
var serviceEntryOne = new ServiceEntry()
{
Service = new AgentService()
{
Service = serviceName,
Address = "localhost",
Port = downstreamServicePort,
ID = "web_90_0_2_224_8080",
Tags = new[] { "version-v1" }
},
};
var consulConfig = new FileConfiguration
{
DynamicReRoutes = new List<FileDynamicReRoute>
{
new FileDynamicReRoute
{
ServiceName = serviceName,
RateLimitRule = new FileRateLimitRule()
{
EnableRateLimiting = true,
ClientWhitelist = new List<string>(),
Limit = 3,
Period = "1s",
PeriodTimespan = 1000
}
}
},
GlobalConfiguration = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{
Scheme = "http",
Host = "localhost",
Port = consulPort
},
RateLimitOptions = new FileRateLimitOptions()
{
ClientIdHeader = "ClientId",
DisableRateLimitHeaders = false,
QuotaExceededMessage = "",
RateLimitCounterPrefix = "",
HttpStatusCode = 428
},
DownstreamScheme = "http",
}
};
var configuration = new FileConfiguration
{
GlobalConfiguration = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{
Scheme = "http",
Host = "localhost",
Port = consulPort
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn(downstreamServiceOneUrl, "/something", 200, "Hello from Laura"))
.And(x => GivenTheConsulConfigurationIs(consulConfig))
.And(x => x.GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, serviceName))
.And(x => x.GivenTheServicesAreRegisteredWithConsul(serviceEntryOne))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfig())
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/web/something", 1))
.Then(x => _steps.ThenTheStatusCodeShouldBe(200))
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/web/something", 2))
.Then(x => _steps.ThenTheStatusCodeShouldBe(200))
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/web/something", 1))
.Then(x => _steps.ThenTheStatusCodeShouldBe(428))
.BDDfy();
}
private void ThenTheConfigIsUpdatedInOcelot()
{
var result = Wait.WaitFor(20000).Until(() =>
{
try
{
_steps.WhenIGetUrlOnTheApiGateway("/cs/status/awesome");
_steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK);
_steps.ThenTheResponseBodyShouldBe("Hello from Laura");
return true;
}
catch (Exception)
{
return false;
}
});
result.ShouldBeTrue();
}
private void GivenTheConsulConfigurationIs(FileConfiguration config)
{
_config = config;
}
private void GivenTheServicesAreRegisteredWithConsul(params ServiceEntry[] serviceEntries)
{
foreach (var serviceEntry in serviceEntries)
{
_consulServices.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.Method.ToLower() == "get" && context.Request.Path.Value == "/v1/kv/InternalConfiguration")
{
var json = JsonConvert.SerializeObject(_config);
var bytes = Encoding.UTF8.GetBytes(json);
var base64 = Convert.ToBase64String(bytes);
var kvp = new FakeConsulGetResponse(base64);
json = JsonConvert.SerializeObject(new FakeConsulGetResponse[] { kvp });
context.Response.Headers.Add("Content-Type", "application/json");
await context.Response.WriteAsync(json);
}
else if (context.Request.Method.ToLower() == "put" && context.Request.Path.Value == "/v1/kv/InternalConfiguration")
{
try
{
var reader = new StreamReader(context.Request.Body);
// Synchronous operations are disallowed. Call ReadAsync or set AllowSynchronousIO to true instead.
// var json = reader.ReadToEnd();
var json = await reader.ReadToEndAsync();
_config = JsonConvert.DeserializeObject<FileConfiguration>(json);
var response = JsonConvert.SerializeObject(true);
await context.Response.WriteAsync(response);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
else if (context.Request.Path.Value == $"/v1/health/service/{serviceName}")
{
var json = JsonConvert.SerializeObject(_consulServices);
context.Response.Headers.Add("Content-Type", "application/json");
await context.Response.WriteAsync(json);
}
});
})
.Build();
_fakeConsulBuilder.Start();
}
public class FakeConsulGetResponse
{
public FakeConsulGetResponse(string value)
{
Value = value;
}
public int CreateIndex => 100;
public int ModifyIndex => 200;
public int LockIndex => 200;
public string Key => "InternalConfiguration";
public int Flags => 0;
public string Value { get; private set; }
public string Session => "adf4238a-882b-9ddc-4a9d-5b6758e4159e";
}
private void GivenThereIsAServiceRunningOn(string url, string basePath, int statusCode, string responseBody)
{
_builder = new WebHostBuilder()
.UseUrls(url)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseUrls(url)
.Configure(app =>
{
app.UsePathBase(basePath);
app.Run(async context =>
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
});
})
.Build();
_builder.Start();
}
public void Dispose()
{
_builder?.Dispose();
_steps.Dispose();
}
private class FakeCache : IOcelotCache<FileConfiguration>
{
public void Add(string key, FileConfiguration value, TimeSpan ttl, string region)
{
throw new NotImplementedException();
}
public FileConfiguration Get(string key, string region)
{
throw new NotImplementedException();
}
public void ClearRegion(string region)
{
throw new NotImplementedException();
}
public void AddAndDelete(string key, FileConfiguration value, TimeSpan ttl, string region)
{
throw new NotImplementedException();
}
}
}
}
namespace Ocelot.AcceptanceTests
{
using Cache;
using Configuration.File;
using Consul;
using Infrastructure;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using Shouldly;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using TestStack.BDDfy;
using Xunit;
public class ConsulConfigurationInConsulTests : IDisposable
{
private IWebHost _builder;
private readonly Steps _steps;
private IWebHost _fakeConsulBuilder;
private FileConfiguration _config;
private readonly List<ServiceEntry> _consulServices;
public ConsulConfigurationInConsulTests()
{
_consulServices = new List<ServiceEntry>();
_steps = new Steps();
}
[Fact]
public void should_return_response_200_with_simple_url()
{
int consulPort = RandomPortFinder.GetRandomPort();
int servicePort = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = servicePort,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
},
GlobalConfiguration = new FileGlobalConfiguration()
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Scheme = "http",
Host = "localhost",
Port = consulPort
}
}
};
var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}";
this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, ""))
.And(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{servicePort}", "", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfig())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_load_configuration_out_of_consul()
{
var consulPort = RandomPortFinder.GetRandomPort();
int servicePort = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
GlobalConfiguration = new FileGlobalConfiguration()
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Scheme = "http",
Host = "localhost",
Port = consulPort
}
}
};
var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}";
var consulConfig = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/status",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = servicePort,
}
},
UpstreamPathTemplate = "/cs/status",
UpstreamHttpMethod = new List<string> {"Get"}
}
},
GlobalConfiguration = new FileGlobalConfiguration()
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Scheme = "http",
Host = "localhost",
Port = consulPort
}
}
};
this.Given(x => GivenTheConsulConfigurationIs(consulConfig))
.And(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, ""))
.And(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{servicePort}", "/status", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfig())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/cs/status"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_load_configuration_out_of_consul_if_it_is_changed()
{
var consulPort = RandomPortFinder.GetRandomPort();
int servicePort = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
GlobalConfiguration = new FileGlobalConfiguration()
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Scheme = "http",
Host = "localhost",
Port = consulPort
}
}
};
var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}";
var consulConfig = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/status",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = servicePort,
}
},
UpstreamPathTemplate = "/cs/status",
UpstreamHttpMethod = new List<string> {"Get"}
}
},
GlobalConfiguration = new FileGlobalConfiguration()
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Scheme = "http",
Host = "localhost",
Port = consulPort
}
}
};
var secondConsulConfig = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/status",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = servicePort,
}
},
UpstreamPathTemplate = "/cs/status/awesome",
UpstreamHttpMethod = new List<string> {"Get"}
}
},
GlobalConfiguration = new FileGlobalConfiguration()
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Scheme = "http",
Host = "localhost",
Port = consulPort
}
}
};
this.Given(x => GivenTheConsulConfigurationIs(consulConfig))
.And(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, ""))
.And(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{servicePort}", "/status", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfig())
.And(x => _steps.WhenIGetUrlOnTheApiGateway("/cs/status"))
.And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.When(x => GivenTheConsulConfigurationIs(secondConsulConfig))
.Then(x => ThenTheConfigIsUpdatedInOcelot())
.BDDfy();
}
[Fact]
public void should_handle_request_to_consul_for_downstream_service_and_make_request_no_re_routes_and_rate_limit()
{
int consulPort = RandomPortFinder.GetRandomPort();
const string serviceName = "web";
int downstreamServicePort = RandomPortFinder.GetRandomPort();
var downstreamServiceOneUrl = $"http://localhost:{downstreamServicePort}";
var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}";
var serviceEntryOne = new ServiceEntry()
{
Service = new AgentService()
{
Service = serviceName,
Address = "localhost",
Port = downstreamServicePort,
ID = "web_90_0_2_224_8080",
Tags = new[] { "version-v1" }
},
};
var consulConfig = new FileConfiguration
{
DynamicRoutes = new List<FileDynamicRoute>
{
new FileDynamicRoute
{
ServiceName = serviceName,
RateLimitRule = new FileRateLimitRule()
{
EnableRateLimiting = true,
ClientWhitelist = new List<string>(),
Limit = 3,
Period = "1s",
PeriodTimespan = 1000
}
}
},
GlobalConfiguration = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{
Scheme = "http",
Host = "localhost",
Port = consulPort
},
RateLimitOptions = new FileRateLimitOptions()
{
ClientIdHeader = "ClientId",
DisableRateLimitHeaders = false,
QuotaExceededMessage = "",
RateLimitCounterPrefix = "",
HttpStatusCode = 428
},
DownstreamScheme = "http",
}
};
var configuration = new FileConfiguration
{
GlobalConfiguration = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{
Scheme = "http",
Host = "localhost",
Port = consulPort
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn(downstreamServiceOneUrl, "/something", 200, "Hello from Laura"))
.And(x => GivenTheConsulConfigurationIs(consulConfig))
.And(x => x.GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, serviceName))
.And(x => x.GivenTheServicesAreRegisteredWithConsul(serviceEntryOne))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfig())
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/web/something", 1))
.Then(x => _steps.ThenTheStatusCodeShouldBe(200))
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/web/something", 2))
.Then(x => _steps.ThenTheStatusCodeShouldBe(200))
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimesForRateLimit("/web/something", 1))
.Then(x => _steps.ThenTheStatusCodeShouldBe(428))
.BDDfy();
}
private void ThenTheConfigIsUpdatedInOcelot()
{
var result = Wait.WaitFor(20000).Until(() =>
{
try
{
_steps.WhenIGetUrlOnTheApiGateway("/cs/status/awesome");
_steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK);
_steps.ThenTheResponseBodyShouldBe("Hello from Laura");
return true;
}
catch (Exception)
{
return false;
}
});
result.ShouldBeTrue();
}
private void GivenTheConsulConfigurationIs(FileConfiguration config)
{
_config = config;
}
private void GivenTheServicesAreRegisteredWithConsul(params ServiceEntry[] serviceEntries)
{
foreach (var serviceEntry in serviceEntries)
{
_consulServices.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.Method.ToLower() == "get" && context.Request.Path.Value == "/v1/kv/InternalConfiguration")
{
var json = JsonConvert.SerializeObject(_config);
var bytes = Encoding.UTF8.GetBytes(json);
var base64 = Convert.ToBase64String(bytes);
var kvp = new FakeConsulGetResponse(base64);
json = JsonConvert.SerializeObject(new FakeConsulGetResponse[] { kvp });
context.Response.Headers.Add("Content-Type", "application/json");
await context.Response.WriteAsync(json);
}
else if (context.Request.Method.ToLower() == "put" && context.Request.Path.Value == "/v1/kv/InternalConfiguration")
{
try
{
var reader = new StreamReader(context.Request.Body);
// Synchronous operations are disallowed. Call ReadAsync or set AllowSynchronousIO to true instead.
// var json = reader.ReadToEnd();
var json = await reader.ReadToEndAsync();
_config = JsonConvert.DeserializeObject<FileConfiguration>(json);
var response = JsonConvert.SerializeObject(true);
await context.Response.WriteAsync(response);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
else if (context.Request.Path.Value == $"/v1/health/service/{serviceName}")
{
var json = JsonConvert.SerializeObject(_consulServices);
context.Response.Headers.Add("Content-Type", "application/json");
await context.Response.WriteAsync(json);
}
});
})
.Build();
_fakeConsulBuilder.Start();
}
public class FakeConsulGetResponse
{
public FakeConsulGetResponse(string value)
{
Value = value;
}
public int CreateIndex => 100;
public int ModifyIndex => 200;
public int LockIndex => 200;
public string Key => "InternalConfiguration";
public int Flags => 0;
public string Value { get; private set; }
public string Session => "adf4238a-882b-9ddc-4a9d-5b6758e4159e";
}
private void GivenThereIsAServiceRunningOn(string url, string basePath, int statusCode, string responseBody)
{
_builder = new WebHostBuilder()
.UseUrls(url)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseUrls(url)
.Configure(app =>
{
app.UsePathBase(basePath);
app.Run(async context =>
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
});
})
.Build();
_builder.Start();
}
public void Dispose()
{
_builder?.Dispose();
_steps.Dispose();
}
private class FakeCache : IOcelotCache<FileConfiguration>
{
public void Add(string key, FileConfiguration value, TimeSpan ttl, string region)
{
throw new NotImplementedException();
}
public FileConfiguration Get(string key, string region)
{
throw new NotImplementedException();
}
public void ClearRegion(string region)
{
throw new NotImplementedException();
}
public void AddAndDelete(string key, FileConfiguration value, TimeSpan ttl, string region)
{
throw new NotImplementedException();
}
}
}
}

View File

@ -1,352 +1,352 @@
namespace Ocelot.AcceptanceTests
{
using Configuration.File;
using Consul;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using Shouldly;
using System;
using System.Collections.Generic;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using TestStack.BDDfy;
using Xunit;
public class ConsulWebSocketTests : IDisposable
{
private readonly List<string> _secondRecieved;
private readonly List<string> _firstRecieved;
private readonly List<ServiceEntry> _serviceEntries;
private readonly Steps _steps;
private readonly ServiceHandler _serviceHandler;
public ConsulWebSocketTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
_firstRecieved = new List<string>();
_secondRecieved = new List<string>();
_serviceEntries = new List<ServiceEntry>();
}
[Fact]
public void should_proxy_websocket_input_to_downstream_service_and_use_service_discovery_and_load_balancer()
{
var downstreamPort = RandomPortFinder.GetRandomPort();
var downstreamHost = "localhost";
var secondDownstreamPort = RandomPortFinder.GetRandomPort();
var secondDownstreamHost = "localhost";
var serviceName = "websockets";
var consulPort = RandomPortFinder.GetRandomPort();
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",
LoadBalancerOptions = new FileLoadBalancerOptions { Type = "RoundRobin" },
ServiceName = serviceName,
}
},
GlobalConfiguration = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{
Scheme = "http",
Host = "localhost",
Port = consulPort,
Type = "consul"
}
}
};
this.Given(_ => _steps.GivenThereIsAConfiguration(config))
.And(_ => _steps.StartFakeOcelotWithWebSocketsWithConsul())
.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)
{
_serviceHandler.GivenThereIsAServiceRunningOn(url, async context =>
{
if (context.Request.Path.Value == $"/v1/health/service/{serviceName}")
{
var json = JsonConvert.SerializeObject(_serviceEntries);
context.Response.Headers.Add("Content-Type", "application/json");
await context.Response.WriteAsync(json);
}
});
}
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)
{
if (client.State != WebSocketState.Closed)
{
// Last version, the client state is CloseReceived
// Valid states are: Open, CloseReceived, CloseSent
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)
{
if (client.State != WebSocketState.Closed)
{
// Last version, the client state is CloseReceived
// Valid states are: Open, CloseReceived, CloseSent
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
}
break;
}
}
});
await Task.WhenAll(sending, receiving);
}
private async Task StartFakeDownstreamService(string url, string path)
{
await _serviceHandler.StartFakeDownstreamService(url, path, async (context, next) =>
{
if (context.Request.Path == path)
{
if (context.WebSockets.IsWebSocketRequest)
{
var webSocket = await context.WebSockets.AcceptWebSocketAsync();
await Echo(webSocket);
}
else
{
context.Response.StatusCode = 400;
}
}
else
{
await next();
}
});
}
private async Task StartSecondFakeDownstreamService(string url, string path)
{
await _serviceHandler.StartFakeDownstreamService(url, path, 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();
}
});
}
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()
{
_serviceHandler?.Dispose();
_steps.Dispose();
}
}
}
namespace Ocelot.AcceptanceTests
{
using Configuration.File;
using Consul;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using Shouldly;
using System;
using System.Collections.Generic;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using TestStack.BDDfy;
using Xunit;
public class ConsulWebSocketTests : IDisposable
{
private readonly List<string> _secondRecieved;
private readonly List<string> _firstRecieved;
private readonly List<ServiceEntry> _serviceEntries;
private readonly Steps _steps;
private readonly ServiceHandler _serviceHandler;
public ConsulWebSocketTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
_firstRecieved = new List<string>();
_secondRecieved = new List<string>();
_serviceEntries = new List<ServiceEntry>();
}
[Fact]
public void should_proxy_websocket_input_to_downstream_service_and_use_service_discovery_and_load_balancer()
{
var downstreamPort = RandomPortFinder.GetRandomPort();
var downstreamHost = "localhost";
var secondDownstreamPort = RandomPortFinder.GetRandomPort();
var secondDownstreamHost = "localhost";
var serviceName = "websockets";
var consulPort = RandomPortFinder.GetRandomPort();
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
{
Routes = new List<FileRoute>
{
new FileRoute
{
UpstreamPathTemplate = "/",
DownstreamPathTemplate = "/ws",
DownstreamScheme = "ws",
LoadBalancerOptions = new FileLoadBalancerOptions { Type = "RoundRobin" },
ServiceName = serviceName,
}
},
GlobalConfiguration = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{
Scheme = "http",
Host = "localhost",
Port = consulPort,
Type = "consul"
}
}
};
this.Given(_ => _steps.GivenThereIsAConfiguration(config))
.And(_ => _steps.StartFakeOcelotWithWebSocketsWithConsul())
.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)
{
_serviceHandler.GivenThereIsAServiceRunningOn(url, async context =>
{
if (context.Request.Path.Value == $"/v1/health/service/{serviceName}")
{
var json = JsonConvert.SerializeObject(_serviceEntries);
context.Response.Headers.Add("Content-Type", "application/json");
await context.Response.WriteAsync(json);
}
});
}
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)
{
if (client.State != WebSocketState.Closed)
{
// Last version, the client state is CloseReceived
// Valid states are: Open, CloseReceived, CloseSent
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)
{
if (client.State != WebSocketState.Closed)
{
// Last version, the client state is CloseReceived
// Valid states are: Open, CloseReceived, CloseSent
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
}
break;
}
}
});
await Task.WhenAll(sending, receiving);
}
private async Task StartFakeDownstreamService(string url, string path)
{
await _serviceHandler.StartFakeDownstreamService(url, path, async (context, next) =>
{
if (context.Request.Path == path)
{
if (context.WebSockets.IsWebSocketRequest)
{
var webSocket = await context.WebSockets.AcceptWebSocketAsync();
await Echo(webSocket);
}
else
{
context.Response.StatusCode = 400;
}
}
else
{
await next();
}
});
}
private async Task StartSecondFakeDownstreamService(string url, string path)
{
await _serviceHandler.StartFakeDownstreamService(url, path, 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();
}
});
}
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()
{
_serviceHandler?.Dispose();
_steps.Dispose();
}
}
}

View File

@ -1,182 +1,182 @@
namespace Ocelot.AcceptanceTests
{
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using Shouldly;
using System;
using System.Collections.Generic;
using System.Net;
using TestStack.BDDfy;
using Xunit;
public class ContentTests : IDisposable
{
private readonly Steps _steps;
private string _contentType;
private long? _contentLength;
private bool _contentTypeHeaderExists;
private readonly ServiceHandler _serviceHandler;
public ContentTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
}
[Fact]
public void should_not_add_content_type_or_content_length_headers()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.And(x => ThenTheContentTypeShouldBeEmpty())
.And(x => ThenTheContentLengthShouldBeZero())
.BDDfy();
}
[Fact]
public void should_add_content_type_and_content_length_headers()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
DownstreamScheme = "http",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Post" },
}
}
};
var contentType = "application/json";
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", 201, string.Empty))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.And(x => _steps.GivenThePostHasContent("postContent"))
.And(x => _steps.GivenThePostHasContentType(contentType))
.When(x => _steps.WhenIPostUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Created))
.And(x => ThenTheContentLengthIs(11))
.And(x => ThenTheContentTypeIsIs(contentType))
.BDDfy();
}
[Fact]
public void should_add_default_content_type_header()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
DownstreamScheme = "http",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Post" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", 201, string.Empty))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.And(x => _steps.GivenThePostHasContent("postContent"))
.When(x => _steps.WhenIPostUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Created))
.And(x => ThenTheContentLengthIs(11))
.And(x => ThenTheContentTypeIsIs("text/plain; charset=utf-8"))
.BDDfy();
}
private void ThenTheContentTypeIsIs(string expected)
{
_contentType.ShouldBe(expected);
}
private void ThenTheContentLengthShouldBeZero()
{
_contentLength.ShouldBeEquivalentTo(0L);
}
private void ThenTheContentLengthIs(int expected)
{
_contentLength.ShouldBe(expected);
}
private void ThenTheContentTypeShouldBeEmpty()
{
_contentType.ShouldBeNullOrEmpty();
_contentTypeHeaderExists.ShouldBe(false);
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody)
{
_serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
{
_contentType = context.Request.ContentType;
_contentLength = context.Request.ContentLength;
_contentTypeHeaderExists = context.Request.Headers.TryGetValue("Content-Type", out var value);
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
});
}
public void Dispose()
{
_serviceHandler?.Dispose();
_steps.Dispose();
}
}
}
namespace Ocelot.AcceptanceTests
{
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using Shouldly;
using System;
using System.Collections.Generic;
using System.Net;
using TestStack.BDDfy;
using Xunit;
public class ContentTests : IDisposable
{
private readonly Steps _steps;
private string _contentType;
private long? _contentLength;
private bool _contentTypeHeaderExists;
private readonly ServiceHandler _serviceHandler;
public ContentTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
}
[Fact]
public void should_not_add_content_type_or_content_length_headers()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.And(x => ThenTheContentTypeShouldBeEmpty())
.And(x => ThenTheContentLengthShouldBeZero())
.BDDfy();
}
[Fact]
public void should_add_content_type_and_content_length_headers()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
DownstreamScheme = "http",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Post" },
}
}
};
var contentType = "application/json";
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", 201, string.Empty))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.And(x => _steps.GivenThePostHasContent("postContent"))
.And(x => _steps.GivenThePostHasContentType(contentType))
.When(x => _steps.WhenIPostUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Created))
.And(x => ThenTheContentLengthIs(11))
.And(x => ThenTheContentTypeIsIs(contentType))
.BDDfy();
}
[Fact]
public void should_add_default_content_type_header()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
DownstreamScheme = "http",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Post" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", 201, string.Empty))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.And(x => _steps.GivenThePostHasContent("postContent"))
.When(x => _steps.WhenIPostUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Created))
.And(x => ThenTheContentLengthIs(11))
.And(x => ThenTheContentTypeIsIs("text/plain; charset=utf-8"))
.BDDfy();
}
private void ThenTheContentTypeIsIs(string expected)
{
_contentType.ShouldBe(expected);
}
private void ThenTheContentLengthShouldBeZero()
{
_contentLength.ShouldBeEquivalentTo(0L);
}
private void ThenTheContentLengthIs(int expected)
{
_contentLength.ShouldBe(expected);
}
private void ThenTheContentTypeShouldBeEmpty()
{
_contentType.ShouldBeNullOrEmpty();
_contentTypeHeaderExists.ShouldBe(false);
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody)
{
_serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
{
_contentType = context.Request.ContentType;
_contentLength = context.Request.ContentLength;
_contentTypeHeaderExists = context.Request.Headers.TryGetValue("Content-Type", out var value);
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
});
}
public void Dispose()
{
_serviceHandler?.Dispose();
_steps.Dispose();
}
}
}

View File

@ -43,9 +43,9 @@
var fileConfiguration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -88,9 +88,9 @@
var fileConfiguration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -133,9 +133,9 @@
var fileConfiguration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/41879/",
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -178,9 +178,9 @@
var fileConfiguration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -223,9 +223,9 @@
var fileConfiguration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -268,9 +268,9 @@
var fileConfiguration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -317,9 +317,9 @@
var fileConfiguration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/west",
DownstreamHostAndPorts = new List<FileHostAndPort>

View File

@ -1,283 +1,283 @@
namespace Ocelot.AcceptanceTests
{
using Configuration.File;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using Steeltoe.Common.Discovery;
using System;
using System.Collections.Generic;
using System.Net;
using TestStack.BDDfy;
using Xunit;
public class EurekaServiceDiscoveryTests : IDisposable
{
private readonly Steps _steps;
private readonly List<IServiceInstance> _eurekaInstances;
private readonly ServiceHandler _serviceHandler;
public EurekaServiceDiscoveryTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
_eurekaInstances = new List<IServiceInstance>();
}
[Fact]
public void should_use_eureka_service_discovery_and_make_request()
{
var eurekaPort = 8761;
var serviceName = "product";
var downstreamServicePort = RandomPortFinder.GetRandomPort();
var downstreamServiceOneUrl = $"http://localhost:{downstreamServicePort}";
var fakeEurekaServiceDiscoveryUrl = $"http://localhost:{eurekaPort}";
var instanceOne = new FakeEurekaService(serviceName, "localhost", downstreamServicePort, false,
new Uri($"http://localhost:{downstreamServicePort}"), new Dictionary<string, string>());
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
ServiceName = serviceName,
LoadBalancerOptions = new FileLoadBalancerOptions { Type = "LeastConnection" },
}
},
GlobalConfiguration = new FileGlobalConfiguration()
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Type = "Eureka"
}
}
};
this.Given(x => x.GivenEurekaProductServiceOneIsRunning(downstreamServiceOneUrl))
.And(x => x.GivenThereIsAFakeEurekaServiceDiscoveryProvider(fakeEurekaServiceDiscoveryUrl, serviceName))
.And(x => x.GivenTheServicesAreRegisteredWithEureka(instanceOne))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningWithEureka())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(_ => _steps.ThenTheResponseBodyShouldBe(nameof(EurekaServiceDiscoveryTests)))
.BDDfy();
}
private void GivenTheServicesAreRegisteredWithEureka(params IServiceInstance[] serviceInstances)
{
foreach (var instance in serviceInstances)
{
_eurekaInstances.Add(instance);
}
}
private void GivenThereIsAFakeEurekaServiceDiscoveryProvider(string url, string serviceName)
{
_serviceHandler.GivenThereIsAServiceRunningOn(url, async context =>
{
if (context.Request.Path.Value == "/eureka/apps/")
{
var apps = new List<Application>();
foreach (var serviceInstance in _eurekaInstances)
{
var a = new Application
{
name = serviceName,
instance = new List<Instance>
{
new Instance
{
instanceId = $"{serviceInstance.Host}:{serviceInstance}",
hostName = serviceInstance.Host,
app = serviceName,
ipAddr = "127.0.0.1",
status = "UP",
overriddenstatus = "UNKNOWN",
port = new Port {value = serviceInstance.Port, enabled = "true"},
securePort = new SecurePort {value = serviceInstance.Port, enabled = "true"},
countryId = 1,
dataCenterInfo = new DataCenterInfo {value = "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo", name = "MyOwn"},
leaseInfo = new LeaseInfo
{
renewalIntervalInSecs = 30,
durationInSecs = 90,
registrationTimestamp = 1457714988223,
lastRenewalTimestamp= 1457716158319,
evictionTimestamp = 0,
serviceUpTimestamp = 1457714988223
},
metadata = new Metadata
{
value = "java.util.Collections$EmptyMap"
},
homePageUrl = $"{serviceInstance.Host}:{serviceInstance.Port}",
statusPageUrl = $"{serviceInstance.Host}:{serviceInstance.Port}",
healthCheckUrl = $"{serviceInstance.Host}:{serviceInstance.Port}",
vipAddress = serviceName,
isCoordinatingDiscoveryServer = "false",
lastUpdatedTimestamp = "1457714988223",
lastDirtyTimestamp = "1457714988172",
actionType = "ADDED"
}
}
};
apps.Add(a);
}
var applications = new EurekaApplications
{
applications = new Applications
{
application = apps,
apps__hashcode = "UP_1_",
versions__delta = "1"
}
};
var json = JsonConvert.SerializeObject(applications);
context.Response.Headers.Add("Content-Type", "application/json");
await context.Response.WriteAsync(json);
}
});
}
private void GivenEurekaProductServiceOneIsRunning(string url)
{
_serviceHandler.GivenThereIsAServiceRunningOn(url, async context =>
{
try
{
context.Response.StatusCode = 200;
await context.Response.WriteAsync(nameof(EurekaServiceDiscoveryTests));
}
catch (Exception exception)
{
await context.Response.WriteAsync(exception.StackTrace);
}
});
}
public void Dispose()
{
_serviceHandler?.Dispose();
_steps.Dispose();
}
}
public class FakeEurekaService : IServiceInstance
{
public FakeEurekaService(string serviceId, string host, int port, bool isSecure, Uri uri, IDictionary<string, string> metadata)
{
ServiceId = serviceId;
Host = host;
Port = port;
IsSecure = isSecure;
Uri = uri;
Metadata = metadata;
}
public string ServiceId { get; }
public string Host { get; }
public int Port { get; }
public bool IsSecure { get; }
public Uri Uri { get; }
public IDictionary<string, string> Metadata { get; }
}
public class Port
{
[JsonProperty("$")]
public int value { get; set; }
[JsonProperty("@enabled")]
public string enabled { get; set; }
}
public class SecurePort
{
[JsonProperty("$")]
public int value { get; set; }
[JsonProperty("@enabled")]
public string enabled { get; set; }
}
public class DataCenterInfo
{
[JsonProperty("@class")]
public string value { get; set; }
public string name { get; set; }
}
public class LeaseInfo
{
public int renewalIntervalInSecs { get; set; }
public int durationInSecs { get; set; }
public long registrationTimestamp { get; set; }
public long lastRenewalTimestamp { get; set; }
public int evictionTimestamp { get; set; }
public long serviceUpTimestamp { get; set; }
}
public class Metadata
{
[JsonProperty("@class")]
public string value { get; set; }
}
public class Instance
{
public string instanceId { get; set; }
public string hostName { get; set; }
public string app { get; set; }
public string ipAddr { get; set; }
public string status { get; set; }
public string overriddenstatus { get; set; }
public Port port { get; set; }
public SecurePort securePort { get; set; }
public int countryId { get; set; }
public DataCenterInfo dataCenterInfo { get; set; }
public LeaseInfo leaseInfo { get; set; }
public Metadata metadata { get; set; }
public string homePageUrl { get; set; }
public string statusPageUrl { get; set; }
public string healthCheckUrl { get; set; }
public string vipAddress { get; set; }
public string isCoordinatingDiscoveryServer { get; set; }
public string lastUpdatedTimestamp { get; set; }
public string lastDirtyTimestamp { get; set; }
public string actionType { get; set; }
}
public class Application
{
public string name { get; set; }
public List<Instance> instance { get; set; }
}
public class Applications
{
public string versions__delta { get; set; }
public string apps__hashcode { get; set; }
public List<Application> application { get; set; }
}
public class EurekaApplications
{
public Applications applications { get; set; }
}
}
namespace Ocelot.AcceptanceTests
{
using Configuration.File;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using Steeltoe.Common.Discovery;
using System;
using System.Collections.Generic;
using System.Net;
using TestStack.BDDfy;
using Xunit;
public class EurekaServiceDiscoveryTests : IDisposable
{
private readonly Steps _steps;
private readonly List<IServiceInstance> _eurekaInstances;
private readonly ServiceHandler _serviceHandler;
public EurekaServiceDiscoveryTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
_eurekaInstances = new List<IServiceInstance>();
}
[Fact]
public void should_use_eureka_service_discovery_and_make_request()
{
var eurekaPort = 8761;
var serviceName = "product";
var downstreamServicePort = RandomPortFinder.GetRandomPort();
var downstreamServiceOneUrl = $"http://localhost:{downstreamServicePort}";
var fakeEurekaServiceDiscoveryUrl = $"http://localhost:{eurekaPort}";
var instanceOne = new FakeEurekaService(serviceName, "localhost", downstreamServicePort, false,
new Uri($"http://localhost:{downstreamServicePort}"), new Dictionary<string, string>());
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
ServiceName = serviceName,
LoadBalancerOptions = new FileLoadBalancerOptions { Type = "LeastConnection" },
}
},
GlobalConfiguration = new FileGlobalConfiguration()
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Type = "Eureka"
}
}
};
this.Given(x => x.GivenEurekaProductServiceOneIsRunning(downstreamServiceOneUrl))
.And(x => x.GivenThereIsAFakeEurekaServiceDiscoveryProvider(fakeEurekaServiceDiscoveryUrl, serviceName))
.And(x => x.GivenTheServicesAreRegisteredWithEureka(instanceOne))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningWithEureka())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(_ => _steps.ThenTheResponseBodyShouldBe(nameof(EurekaServiceDiscoveryTests)))
.BDDfy();
}
private void GivenTheServicesAreRegisteredWithEureka(params IServiceInstance[] serviceInstances)
{
foreach (var instance in serviceInstances)
{
_eurekaInstances.Add(instance);
}
}
private void GivenThereIsAFakeEurekaServiceDiscoveryProvider(string url, string serviceName)
{
_serviceHandler.GivenThereIsAServiceRunningOn(url, async context =>
{
if (context.Request.Path.Value == "/eureka/apps/")
{
var apps = new List<Application>();
foreach (var serviceInstance in _eurekaInstances)
{
var a = new Application
{
name = serviceName,
instance = new List<Instance>
{
new Instance
{
instanceId = $"{serviceInstance.Host}:{serviceInstance}",
hostName = serviceInstance.Host,
app = serviceName,
ipAddr = "127.0.0.1",
status = "UP",
overriddenstatus = "UNKNOWN",
port = new Port {value = serviceInstance.Port, enabled = "true"},
securePort = new SecurePort {value = serviceInstance.Port, enabled = "true"},
countryId = 1,
dataCenterInfo = new DataCenterInfo {value = "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo", name = "MyOwn"},
leaseInfo = new LeaseInfo
{
renewalIntervalInSecs = 30,
durationInSecs = 90,
registrationTimestamp = 1457714988223,
lastRenewalTimestamp= 1457716158319,
evictionTimestamp = 0,
serviceUpTimestamp = 1457714988223
},
metadata = new Metadata
{
value = "java.util.Collections$EmptyMap"
},
homePageUrl = $"{serviceInstance.Host}:{serviceInstance.Port}",
statusPageUrl = $"{serviceInstance.Host}:{serviceInstance.Port}",
healthCheckUrl = $"{serviceInstance.Host}:{serviceInstance.Port}",
vipAddress = serviceName,
isCoordinatingDiscoveryServer = "false",
lastUpdatedTimestamp = "1457714988223",
lastDirtyTimestamp = "1457714988172",
actionType = "ADDED"
}
}
};
apps.Add(a);
}
var applications = new EurekaApplications
{
applications = new Applications
{
application = apps,
apps__hashcode = "UP_1_",
versions__delta = "1"
}
};
var json = JsonConvert.SerializeObject(applications);
context.Response.Headers.Add("Content-Type", "application/json");
await context.Response.WriteAsync(json);
}
});
}
private void GivenEurekaProductServiceOneIsRunning(string url)
{
_serviceHandler.GivenThereIsAServiceRunningOn(url, async context =>
{
try
{
context.Response.StatusCode = 200;
await context.Response.WriteAsync(nameof(EurekaServiceDiscoveryTests));
}
catch (Exception exception)
{
await context.Response.WriteAsync(exception.StackTrace);
}
});
}
public void Dispose()
{
_serviceHandler?.Dispose();
_steps.Dispose();
}
}
public class FakeEurekaService : IServiceInstance
{
public FakeEurekaService(string serviceId, string host, int port, bool isSecure, Uri uri, IDictionary<string, string> metadata)
{
ServiceId = serviceId;
Host = host;
Port = port;
IsSecure = isSecure;
Uri = uri;
Metadata = metadata;
}
public string ServiceId { get; }
public string Host { get; }
public int Port { get; }
public bool IsSecure { get; }
public Uri Uri { get; }
public IDictionary<string, string> Metadata { get; }
}
public class Port
{
[JsonProperty("$")]
public int value { get; set; }
[JsonProperty("@enabled")]
public string enabled { get; set; }
}
public class SecurePort
{
[JsonProperty("$")]
public int value { get; set; }
[JsonProperty("@enabled")]
public string enabled { get; set; }
}
public class DataCenterInfo
{
[JsonProperty("@class")]
public string value { get; set; }
public string name { get; set; }
}
public class LeaseInfo
{
public int renewalIntervalInSecs { get; set; }
public int durationInSecs { get; set; }
public long registrationTimestamp { get; set; }
public long lastRenewalTimestamp { get; set; }
public int evictionTimestamp { get; set; }
public long serviceUpTimestamp { get; set; }
}
public class Metadata
{
[JsonProperty("@class")]
public string value { get; set; }
}
public class Instance
{
public string instanceId { get; set; }
public string hostName { get; set; }
public string app { get; set; }
public string ipAddr { get; set; }
public string status { get; set; }
public string overriddenstatus { get; set; }
public Port port { get; set; }
public SecurePort securePort { get; set; }
public int countryId { get; set; }
public DataCenterInfo dataCenterInfo { get; set; }
public LeaseInfo leaseInfo { get; set; }
public Metadata metadata { get; set; }
public string homePageUrl { get; set; }
public string statusPageUrl { get; set; }
public string healthCheckUrl { get; set; }
public string vipAddress { get; set; }
public string isCoordinatingDiscoveryServer { get; set; }
public string lastUpdatedTimestamp { get; set; }
public string lastDirtyTimestamp { get; set; }
public string actionType { get; set; }
}
public class Application
{
public string name { get; set; }
public List<Instance> instance { get; set; }
}
public class Applications
{
public string versions__delta { get; set; }
public string apps__hashcode { get; set; }
public List<Application> application { get; set; }
}
public class EurekaApplications
{
public Applications applications { get; set; }
}
}

View File

@ -30,9 +30,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",

View File

@ -29,9 +29,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
@ -70,9 +70,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
@ -110,9 +110,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
@ -154,9 +154,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
@ -198,9 +198,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
@ -246,9 +246,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/sso/{everything}",
DownstreamScheme = "http",
@ -289,9 +289,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/sso/{everything}",
DownstreamScheme = "http",
@ -332,9 +332,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
@ -369,9 +369,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",

View File

@ -1,167 +1,167 @@
namespace Ocelot.AcceptanceTests
{
using Configuration;
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using Requester;
using Shouldly;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Net;
using TestStack.BDDfy;
using Xunit;
public class HttpClientCachingTests : IDisposable
{
private readonly Steps _steps;
private string _downstreamPath;
private readonly ServiceHandler _serviceHandler;
public HttpClientCachingTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
}
[Fact]
public void should_cache_one_http_client_same_re_route()
namespace Ocelot.AcceptanceTests
{
using Configuration;
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using Requester;
using Shouldly;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Net;
using TestStack.BDDfy;
using Xunit;
public class HttpClientCachingTests : IDisposable
{
private readonly Steps _steps;
private string _downstreamPath;
private readonly ServiceHandler _serviceHandler;
public HttpClientCachingTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
}
[Fact]
public void should_cache_one_http_client_same_re_route()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
var cache = new FakeHttpClientCache();
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningWithFakeHttpClientCache(cache))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.And(x => cache.Count.ShouldBe(1))
.BDDfy();
}
[Fact]
public void should_cache_two_http_client_different_re_route()
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
var cache = new FakeHttpClientCache();
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningWithFakeHttpClientCache(cache))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.And(x => cache.Count.ShouldBe(1))
.BDDfy();
}
[Fact]
public void should_cache_two_http_client_different_re_route()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
},
new FileReRoute
{
DownstreamPathTemplate = "/two",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/two",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
var cache = new FakeHttpClientCache();
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningWithFakeHttpClientCache(cache))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/two"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/two"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/two"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.And(x => cache.Count.ShouldBe(2))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string baseUrl, int statusCode, string responseBody)
{
_serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, async context =>
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
});
}
public void Dispose()
{
_serviceHandler.Dispose();
_steps.Dispose();
}
public class FakeHttpClientCache : IHttpClientCache
{
private readonly ConcurrentDictionary<DownstreamReRoute, IHttpClient> _httpClientsCache;
public FakeHttpClientCache()
{
_httpClientsCache = new ConcurrentDictionary<DownstreamReRoute, IHttpClient>();
}
public void Set(DownstreamReRoute key, IHttpClient client, TimeSpan expirationTime)
{
_httpClientsCache.AddOrUpdate(key, client, (k, oldValue) => client);
}
public IHttpClient Get(DownstreamReRoute key)
{
//todo handle error?
return _httpClientsCache.TryGetValue(key, out var client) ? client : null;
}
public int Count => _httpClientsCache.Count;
}
}
}
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
},
new FileRoute
{
DownstreamPathTemplate = "/two",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/two",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
var cache = new FakeHttpClientCache();
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningWithFakeHttpClientCache(cache))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/two"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/two"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/two"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.And(x => cache.Count.ShouldBe(2))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string baseUrl, int statusCode, string responseBody)
{
_serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, async context =>
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
});
}
public void Dispose()
{
_serviceHandler.Dispose();
_steps.Dispose();
}
public class FakeHttpClientCache : IHttpClientCache
{
private readonly ConcurrentDictionary<DownstreamRoute, IHttpClient> _httpClientsCache;
public FakeHttpClientCache()
{
_httpClientsCache = new ConcurrentDictionary<DownstreamRoute, IHttpClient>();
}
public void Set(DownstreamRoute key, IHttpClient client, TimeSpan expirationTime)
{
_httpClientsCache.AddOrUpdate(key, client, (k, oldValue) => client);
}
public IHttpClient Get(DownstreamRoute key)
{
//todo handle error?
return _httpClientsCache.TryGetValue(key, out var client) ? client : null;
}
public int Count => _httpClientsCache.Count;
}
}
}

View File

@ -1,296 +1,296 @@
namespace Ocelot.AcceptanceTests
{
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using Shouldly;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using TestStack.BDDfy;
using Xunit;
public class HttpDelegatingHandlersTests : IDisposable
{
private readonly Steps _steps;
private string _downstreamPath;
private readonly ServiceHandler _serviceHandler;
public HttpDelegatingHandlersTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
}
[Fact]
public void should_call_re_route_ordered_specific_handlers()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
DelegatingHandlers = new List<string>
{
"FakeHandlerTwo",
"FakeHandler"
}
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningWithSpecficHandlersRegisteredInDi<FakeHandler, FakeHandlerTwo>())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.And(x => ThenTheOrderedHandlersAreCalledCorrectly())
.BDDfy();
}
[Fact]
public void should_call_global_di_handlers()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningWithGlobalHandlersRegisteredInDi<FakeHandler, FakeHandlerTwo>())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.And(x => ThenTheHandlersAreCalledCorrectly())
.BDDfy();
}
[Fact]
public void should_call_global_di_handlers_multiple_times()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningWithGlobalHandlerRegisteredInDi<FakeHandlerAgain>())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_call_global_di_handlers_with_dependency()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
var dependency = new FakeDependency();
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningWithGlobalHandlersRegisteredInDi<FakeHandlerWithDependency>(dependency))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.And(x => ThenTheDependencyIsCalled(dependency))
.BDDfy();
}
private void ThenTheDependencyIsCalled(FakeDependency dependency)
{
dependency.Called.ShouldBeTrue();
}
private void ThenTheHandlersAreCalledCorrectly()
{
FakeHandler.TimeCalled.ShouldBeLessThan(FakeHandlerTwo.TimeCalled);
}
private void ThenTheOrderedHandlersAreCalledCorrectly()
{
FakeHandlerTwo.TimeCalled.ShouldBeLessThan(FakeHandler.TimeCalled);
}
public class FakeDependency
{
public bool Called;
}
// ReSharper disable once ClassNeverInstantiated.Local
private class FakeHandlerWithDependency : DelegatingHandler
{
private readonly FakeDependency _dependency;
public FakeHandlerWithDependency(FakeDependency dependency)
{
_dependency = dependency;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
_dependency.Called = true;
return base.SendAsync(request, cancellationToken);
}
}
// ReSharper disable once ClassNeverInstantiated.Local
private class FakeHandler : DelegatingHandler
{
public static DateTime TimeCalled { get; private set; }
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
TimeCalled = DateTime.Now;
return base.SendAsync(request, cancellationToken);
}
}
// ReSharper disable once ClassNeverInstantiated.Local
private class FakeHandlerTwo : DelegatingHandler
{
public static DateTime TimeCalled { get; private set; }
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
TimeCalled = DateTime.Now;
return base.SendAsync(request, cancellationToken);
}
}
// ReSharper disable once ClassNeverInstantiated.Local
private class FakeHandlerAgain : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
Console.WriteLine(request.RequestUri);
//do stuff and optionally call the base handler..
return await base.SendAsync(request, cancellationToken);
}
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody)
{
_serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
{
_downstreamPath = !string.IsNullOrEmpty(context.Request.PathBase.Value) ? context.Request.PathBase.Value : context.Request.Path.Value;
if (_downstreamPath != basePath)
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync("downstream path didnt match base path");
}
else
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
}
});
}
public void Dispose()
{
_steps?.Dispose();
_serviceHandler?.Dispose();
}
}
}
namespace Ocelot.AcceptanceTests
{
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using Shouldly;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using TestStack.BDDfy;
using Xunit;
public class HttpDelegatingHandlersTests : IDisposable
{
private readonly Steps _steps;
private string _downstreamPath;
private readonly ServiceHandler _serviceHandler;
public HttpDelegatingHandlersTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
}
[Fact]
public void should_call_re_route_ordered_specific_handlers()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
DelegatingHandlers = new List<string>
{
"FakeHandlerTwo",
"FakeHandler"
}
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningWithSpecficHandlersRegisteredInDi<FakeHandler, FakeHandlerTwo>())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.And(x => ThenTheOrderedHandlersAreCalledCorrectly())
.BDDfy();
}
[Fact]
public void should_call_global_di_handlers()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningWithGlobalHandlersRegisteredInDi<FakeHandler, FakeHandlerTwo>())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.And(x => ThenTheHandlersAreCalledCorrectly())
.BDDfy();
}
[Fact]
public void should_call_global_di_handlers_multiple_times()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningWithGlobalHandlerRegisteredInDi<FakeHandlerAgain>())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_call_global_di_handlers_with_dependency()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
var dependency = new FakeDependency();
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningWithGlobalHandlersRegisteredInDi<FakeHandlerWithDependency>(dependency))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.And(x => ThenTheDependencyIsCalled(dependency))
.BDDfy();
}
private void ThenTheDependencyIsCalled(FakeDependency dependency)
{
dependency.Called.ShouldBeTrue();
}
private void ThenTheHandlersAreCalledCorrectly()
{
FakeHandler.TimeCalled.ShouldBeLessThan(FakeHandlerTwo.TimeCalled);
}
private void ThenTheOrderedHandlersAreCalledCorrectly()
{
FakeHandlerTwo.TimeCalled.ShouldBeLessThan(FakeHandler.TimeCalled);
}
public class FakeDependency
{
public bool Called;
}
// ReSharper disable once ClassNeverInstantiated.Local
private class FakeHandlerWithDependency : DelegatingHandler
{
private readonly FakeDependency _dependency;
public FakeHandlerWithDependency(FakeDependency dependency)
{
_dependency = dependency;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
_dependency.Called = true;
return base.SendAsync(request, cancellationToken);
}
}
// ReSharper disable once ClassNeverInstantiated.Local
private class FakeHandler : DelegatingHandler
{
public static DateTime TimeCalled { get; private set; }
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
TimeCalled = DateTime.Now;
return base.SendAsync(request, cancellationToken);
}
}
// ReSharper disable once ClassNeverInstantiated.Local
private class FakeHandlerTwo : DelegatingHandler
{
public static DateTime TimeCalled { get; private set; }
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
TimeCalled = DateTime.Now;
return base.SendAsync(request, cancellationToken);
}
}
// ReSharper disable once ClassNeverInstantiated.Local
private class FakeHandlerAgain : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
Console.WriteLine(request.RequestUri);
//do stuff and optionally call the base handler..
return await base.SendAsync(request, cancellationToken);
}
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody)
{
_serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
{
_downstreamPath = !string.IsNullOrEmpty(context.Request.PathBase.Value) ? context.Request.PathBase.Value : context.Request.Path.Value;
if (_downstreamPath != basePath)
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync("downstream path didnt match base path");
}
else
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
}
});
}
public void Dispose()
{
_steps?.Dispose();
_serviceHandler?.Dispose();
}
}
}

View File

@ -1,243 +1,243 @@
namespace Ocelot.AcceptanceTests
{
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using TestStack.BDDfy;
using Xunit;
public class HttpTests : IDisposable
{
private readonly Steps _steps;
private readonly ServiceHandler _serviceHandler;
public HttpTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
}
[Fact]
public void should_return_response_200_when_using_http_one()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/{url}",
DownstreamScheme = "https",
UpstreamPathTemplate = "/{url}",
UpstreamHttpMethod = new List<string> { "Get" },
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
},
},
DownstreamHttpMethod = "POST",
DownstreamHttpVersion = "1.0",
DangerousAcceptAnyServerCertificateValidator = true
},
},
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}/", "/", port, HttpProtocols.Http1))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.BDDfy();
}
[Fact]
public void should_return_response_200_when_using_http_one_point_one()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/{url}",
DownstreamScheme = "https",
UpstreamPathTemplate = "/{url}",
UpstreamHttpMethod = new List<string> { "Get" },
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
},
},
DownstreamHttpMethod = "POST",
DownstreamHttpVersion = "1.1",
DangerousAcceptAnyServerCertificateValidator = true
},
},
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}/", "/", port, HttpProtocols.Http1))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.BDDfy();
}
[Fact]
public void should_return_response_200_when_using_http_two_point_zero()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/{url}",
DownstreamScheme = "https",
UpstreamPathTemplate = "/{url}",
UpstreamHttpMethod = new List<string> { "Get" },
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
},
},
DownstreamHttpMethod = "POST",
DownstreamHttpVersion = "2.0",
DangerousAcceptAnyServerCertificateValidator = true
},
},
};
const string expected = "here is some content";
var httpContent = new StringContent(expected);
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}/", "/", port, HttpProtocols.Http2))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/", httpContent))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(_ => _steps.ThenTheResponseBodyShouldBe(expected))
.BDDfy();
}
[Fact]
public void should_return_response_502_when_using_http_one_to_talk_to_server_running_http_two()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/{url}",
DownstreamScheme = "https",
UpstreamPathTemplate = "/{url}",
UpstreamHttpMethod = new List<string> { "Get" },
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
},
},
DownstreamHttpMethod = "POST",
DownstreamHttpVersion = "1.1",
DangerousAcceptAnyServerCertificateValidator = true
},
},
};
const string expected = "here is some content";
var httpContent = new StringContent(expected);
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}/", "/", port, HttpProtocols.Http2))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/", httpContent))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.BadGateway))
.BDDfy();
}
[Fact]
public void should_return_response_200_when_using_http_two_to_talk_to_server_running_http_one_point_one()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/{url}",
DownstreamScheme = "https",
UpstreamPathTemplate = "/{url}",
UpstreamHttpMethod = new List<string> { "Get" },
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
},
},
DownstreamHttpMethod = "POST",
DownstreamHttpVersion = "2.0",
DangerousAcceptAnyServerCertificateValidator = true
},
},
};
const string expected = "here is some content";
var httpContent = new StringContent(expected);
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}/", "/", port, HttpProtocols.Http1))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/", httpContent))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(_ => _steps.ThenTheResponseBodyShouldBe(expected))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int port, HttpProtocols protocols)
{
_serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
{
context.Response.StatusCode = 200;
var reader = new StreamReader(context.Request.Body);
var body = await reader.ReadToEndAsync();
await context.Response.WriteAsync(body);
}, port, protocols);
}
public void Dispose()
{
_serviceHandler.Dispose();
_steps.Dispose();
}
}
}
namespace Ocelot.AcceptanceTests
{
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using TestStack.BDDfy;
using Xunit;
public class HttpTests : IDisposable
{
private readonly Steps _steps;
private readonly ServiceHandler _serviceHandler;
public HttpTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
}
[Fact]
public void should_return_response_200_when_using_http_one()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/{url}",
DownstreamScheme = "https",
UpstreamPathTemplate = "/{url}",
UpstreamHttpMethod = new List<string> { "Get" },
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
},
},
DownstreamHttpMethod = "POST",
DownstreamHttpVersion = "1.0",
DangerousAcceptAnyServerCertificateValidator = true
},
},
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}/", "/", port, HttpProtocols.Http1))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.BDDfy();
}
[Fact]
public void should_return_response_200_when_using_http_one_point_one()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/{url}",
DownstreamScheme = "https",
UpstreamPathTemplate = "/{url}",
UpstreamHttpMethod = new List<string> { "Get" },
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
},
},
DownstreamHttpMethod = "POST",
DownstreamHttpVersion = "1.1",
DangerousAcceptAnyServerCertificateValidator = true
},
},
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}/", "/", port, HttpProtocols.Http1))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.BDDfy();
}
[Fact]
public void should_return_response_200_when_using_http_two_point_zero()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/{url}",
DownstreamScheme = "https",
UpstreamPathTemplate = "/{url}",
UpstreamHttpMethod = new List<string> { "Get" },
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
},
},
DownstreamHttpMethod = "POST",
DownstreamHttpVersion = "2.0",
DangerousAcceptAnyServerCertificateValidator = true
},
},
};
const string expected = "here is some content";
var httpContent = new StringContent(expected);
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}/", "/", port, HttpProtocols.Http2))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/", httpContent))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(_ => _steps.ThenTheResponseBodyShouldBe(expected))
.BDDfy();
}
[Fact]
public void should_return_response_502_when_using_http_one_to_talk_to_server_running_http_two()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/{url}",
DownstreamScheme = "https",
UpstreamPathTemplate = "/{url}",
UpstreamHttpMethod = new List<string> { "Get" },
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
},
},
DownstreamHttpMethod = "POST",
DownstreamHttpVersion = "1.1",
DangerousAcceptAnyServerCertificateValidator = true
},
},
};
const string expected = "here is some content";
var httpContent = new StringContent(expected);
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}/", "/", port, HttpProtocols.Http2))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/", httpContent))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.BadGateway))
.BDDfy();
}
[Fact]
public void should_return_response_200_when_using_http_two_to_talk_to_server_running_http_one_point_one()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/{url}",
DownstreamScheme = "https",
UpstreamPathTemplate = "/{url}",
UpstreamHttpMethod = new List<string> { "Get" },
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
},
},
DownstreamHttpMethod = "POST",
DownstreamHttpVersion = "2.0",
DangerousAcceptAnyServerCertificateValidator = true
},
},
};
const string expected = "here is some content";
var httpContent = new StringContent(expected);
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}/", "/", port, HttpProtocols.Http1))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/", httpContent))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(_ => _steps.ThenTheResponseBodyShouldBe(expected))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int port, HttpProtocols protocols)
{
_serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
{
context.Response.StatusCode = 200;
var reader = new StreamReader(context.Request.Body);
var body = await reader.ReadToEndAsync();
await context.Response.WriteAsync(body);
}, port, protocols);
}
public void Dispose()
{
_serviceHandler.Dispose();
_steps.Dispose();
}
}
}

View File

@ -40,9 +40,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
@ -89,9 +89,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
@ -138,9 +138,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
@ -165,7 +165,7 @@ namespace Ocelot.AcceptanceTests
GlobalConfiguration = new FileGlobalConfiguration(),
};
Func<IServiceProvider, DownstreamReRoute, IServiceDiscoveryProvider, CustomLoadBalancer> loadBalancerFactoryFunc = (serviceProvider, reRoute, serviceDiscoveryProvider) => new CustomLoadBalancer(serviceDiscoveryProvider.Get);
Func<IServiceProvider, DownstreamRoute, IServiceDiscoveryProvider, CustomLoadBalancer> loadBalancerFactoryFunc = (serviceProvider, route, serviceDiscoveryProvider) => new CustomLoadBalancer(serviceDiscoveryProvider.Get);
this.Given(x => x.GivenProductServiceOneIsRunning(downstreamServiceOneUrl, 200))
.And(x => x.GivenProductServiceTwoIsRunning(downstreamServiceTwoUrl, 200))

View File

@ -1,164 +1,164 @@
namespace Ocelot.AcceptanceTests
{
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using TestStack.BDDfy;
using Xunit;
public class MethodTests : IDisposable
{
private readonly Steps _steps;
private readonly ServiceHandler _serviceHandler;
public MethodTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
}
[Fact]
public void should_return_response_200_when_get_converted_to_post()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/{url}",
DownstreamScheme = "http",
UpstreamPathTemplate = "/{url}",
UpstreamHttpMethod = new List<string> { "Get" },
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
},
},
DownstreamHttpMethod = "POST",
},
},
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}/", "/", "POST"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.BDDfy();
}
[Fact]
public void should_return_response_200_when_get_converted_to_post_with_content()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/{url}",
DownstreamScheme = "http",
UpstreamPathTemplate = "/{url}",
UpstreamHttpMethod = new List<string> { "Get" },
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
},
},
DownstreamHttpMethod = "POST",
},
},
};
const string expected = "here is some content";
var httpContent = new StringContent(expected);
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}/", "/", "POST"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/", httpContent))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(_ => _steps.ThenTheResponseBodyShouldBe(expected))
.BDDfy();
}
[Fact]
public void should_return_response_200_when_get_converted_to_get_with_content()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/{url}",
DownstreamScheme = "http",
UpstreamPathTemplate = "/{url}",
UpstreamHttpMethod = new List<string> { "Post" },
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
},
},
DownstreamHttpMethod = "GET",
},
},
};
const string expected = "here is some content";
var httpContent = new StringContent(expected);
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}/", "/", "GET"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIPostUrlOnTheApiGateway("/", httpContent))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(_ => _steps.ThenTheResponseBodyShouldBe(expected))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, string expected)
{
_serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
{
if (context.Request.Method == expected)
{
context.Response.StatusCode = 200;
var reader = new StreamReader(context.Request.Body);
var body = await reader.ReadToEndAsync();
await context.Response.WriteAsync(body);
}
else
{
context.Response.StatusCode = 500;
}
});
}
public void Dispose()
{
_serviceHandler.Dispose();
_steps.Dispose();
}
}
}
namespace Ocelot.AcceptanceTests
{
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using TestStack.BDDfy;
using Xunit;
public class MethodTests : IDisposable
{
private readonly Steps _steps;
private readonly ServiceHandler _serviceHandler;
public MethodTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
}
[Fact]
public void should_return_response_200_when_get_converted_to_post()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/{url}",
DownstreamScheme = "http",
UpstreamPathTemplate = "/{url}",
UpstreamHttpMethod = new List<string> { "Get" },
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
},
},
DownstreamHttpMethod = "POST",
},
},
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}/", "/", "POST"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.BDDfy();
}
[Fact]
public void should_return_response_200_when_get_converted_to_post_with_content()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/{url}",
DownstreamScheme = "http",
UpstreamPathTemplate = "/{url}",
UpstreamHttpMethod = new List<string> { "Get" },
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
},
},
DownstreamHttpMethod = "POST",
},
},
};
const string expected = "here is some content";
var httpContent = new StringContent(expected);
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}/", "/", "POST"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/", httpContent))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(_ => _steps.ThenTheResponseBodyShouldBe(expected))
.BDDfy();
}
[Fact]
public void should_return_response_200_when_get_converted_to_get_with_content()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/{url}",
DownstreamScheme = "http",
UpstreamPathTemplate = "/{url}",
UpstreamHttpMethod = new List<string> { "Post" },
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
},
},
DownstreamHttpMethod = "GET",
},
},
};
const string expected = "here is some content";
var httpContent = new StringContent(expected);
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}/", "/", "GET"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIPostUrlOnTheApiGateway("/", httpContent))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(_ => _steps.ThenTheResponseBodyShouldBe(expected))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, string expected)
{
_serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
{
if (context.Request.Method == expected)
{
context.Response.StatusCode = 200;
var reader = new StreamReader(context.Request.Body);
var body = await reader.ReadToEndAsync();
await context.Response.WriteAsync(body);
}
else
{
context.Response.StatusCode = 500;
}
});
}
public void Dispose()
{
_serviceHandler.Dispose();
_steps.Dispose();
}
}
}

View File

@ -24,14 +24,14 @@
[Fact]
public void should_not_timeout()
{
var port = RandomPortFinder.GetRandomPort();
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -65,14 +65,14 @@
[Fact]
public void should_timeout()
{
var port = RandomPortFinder.GetRandomPort();
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -106,14 +106,14 @@
[Fact]
public void should_open_circuit_breaker_then_close()
{
var port = RandomPortFinder.GetRandomPort();
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
@ -157,16 +157,16 @@
}
[Fact]
public void open_circuit_should_not_effect_different_reRoute()
{
var port1 = RandomPortFinder.GetRandomPort();
var port2 = RandomPortFinder.GetRandomPort();
public void open_circuit_should_not_effect_different_route()
{
var port1 = RandomPortFinder.GetRandomPort();
var port2 = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
@ -187,7 +187,7 @@
DurationOfBreak = 1000
}
},
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",

View File

@ -1,76 +1,76 @@
namespace Ocelot.AcceptanceTests
{
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Ocelot.Configuration.File;
using System;
using System.Collections.Generic;
using TestStack.BDDfy;
using Xunit;
public class ReasonPhraseTests : IDisposable
{
private readonly Steps _steps;
private string _contentType;
private long? _contentLength;
private bool _contentTypeHeaderExists;
private readonly ServiceHandler _serviceHandler;
public ReasonPhraseTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
}
[Fact]
public void should_return_reason_phrase()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", "some reason"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.And(_ => _steps.ThenTheReasonPhraseIs("some reason"))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, string reasonPhrase)
{
_serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
{
context.Response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = reasonPhrase;
await context.Response.WriteAsync("YOYO!");
});
}
public void Dispose()
{
_serviceHandler?.Dispose();
_steps.Dispose();
}
}
}
namespace Ocelot.AcceptanceTests
{
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Ocelot.Configuration.File;
using System;
using System.Collections.Generic;
using TestStack.BDDfy;
using Xunit;
public class ReasonPhraseTests : IDisposable
{
private readonly Steps _steps;
private string _contentType;
private long? _contentLength;
private bool _contentTypeHeaderExists;
private readonly ServiceHandler _serviceHandler;
public ReasonPhraseTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
}
[Fact]
public void should_return_reason_phrase()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", "some reason"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.And(_ => _steps.ThenTheReasonPhraseIs("some reason"))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, string reasonPhrase)
{
_serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
{
context.Response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = reasonPhrase;
await context.Response.WriteAsync("YOYO!");
});
}
public void Dispose()
{
_serviceHandler?.Dispose();
_steps.Dispose();
}
}
}

View File

@ -26,9 +26,9 @@
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -62,9 +62,9 @@
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -99,9 +99,9 @@
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
@ -140,9 +140,9 @@
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>

View File

@ -25,9 +25,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/{everything}",
DownstreamScheme = "http",

View File

@ -23,9 +23,9 @@
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
UpstreamPathTemplate = "/",
@ -57,9 +57,9 @@
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
UpstreamPathTemplate = "/",
@ -92,9 +92,9 @@
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
UpstreamPathTemplate = "/",

File diff suppressed because it is too large Load Diff

View File

@ -1,271 +1,271 @@
namespace Ocelot.AcceptanceTests
{
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using System;
using System.Collections.Generic;
using System.Net;
using TestStack.BDDfy;
using Xunit;
public class RoutingWithQueryStringTests : IDisposable
{
private readonly Steps _steps;
private readonly ServiceHandler _serviceHandler;
public RoutingWithQueryStringTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
}
[Fact]
public void should_return_response_200_with_query_string_template()
{
var subscriptionId = Guid.NewGuid().ToString();
var unitId = Guid.NewGuid().ToString();
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/api/units/{subscriptionId}/{unitId}/updates",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", $"/api/subscriptions/{subscriptionId}/updates", $"?unitId={unitId}", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway($"/api/units/{subscriptionId}/{unitId}/updates"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_return_response_200_with_odata_query_string()
{
var subscriptionId = Guid.NewGuid().ToString();
var unitId = Guid.NewGuid().ToString();
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/{everything}",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/{everything}",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", $"/odata/customers", "?$filter=Name%20eq%20'Sam'", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway($"/odata/customers?$filter=Name eq 'Sam' "))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_return_response_200_with_query_string_upstream_template()
{
var subscriptionId = Guid.NewGuid().ToString();
var unitId = Guid.NewGuid().ToString();
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/api/units/{subscriptionId}/{unitId}/updates",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", $"/api/units/{subscriptionId}/{unitId}/updates", "", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway($"/api/subscriptions/{subscriptionId}/updates?unitId={unitId}"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_return_response_404_with_query_string_upstream_template_no_query_string()
{
var subscriptionId = Guid.NewGuid().ToString();
var unitId = Guid.NewGuid().ToString();
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/api/units/{subscriptionId}/{unitId}/updates",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", $"/api/units/{subscriptionId}/{unitId}/updates", "", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway($"/api/subscriptions/{subscriptionId}/updates"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound))
.BDDfy();
}
[Fact]
public void should_return_response_404_with_query_string_upstream_template_different_query_string()
{
var subscriptionId = Guid.NewGuid().ToString();
var unitId = Guid.NewGuid().ToString();
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/api/units/{subscriptionId}/{unitId}/updates",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", $"/api/units/{subscriptionId}/{unitId}/updates", "", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway($"/api/subscriptions/{subscriptionId}/updates?test=1"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound))
.BDDfy();
}
[Fact]
public void should_return_response_200_with_query_string_upstream_template_multiple_params()
{
var subscriptionId = Guid.NewGuid().ToString();
var unitId = Guid.NewGuid().ToString();
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/api/units/{subscriptionId}/{unitId}/updates",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", $"/api/units/{subscriptionId}/{unitId}/updates", "?productId=1", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway($"/api/subscriptions/{subscriptionId}/updates?unitId={unitId}&productId=1"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, string queryString, int statusCode, string responseBody)
{
_serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
{
if ((context.Request.PathBase.Value != basePath) || context.Request.QueryString.Value != queryString)
{
context.Response.StatusCode = 500;
await context.Response.WriteAsync("downstream path didnt match base path");
}
else
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
}
});
}
public void Dispose()
{
_serviceHandler?.Dispose();
_steps.Dispose();
}
}
}
namespace Ocelot.AcceptanceTests
{
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using System;
using System.Collections.Generic;
using System.Net;
using TestStack.BDDfy;
using Xunit;
public class RoutingWithQueryStringTests : IDisposable
{
private readonly Steps _steps;
private readonly ServiceHandler _serviceHandler;
public RoutingWithQueryStringTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
}
[Fact]
public void should_return_response_200_with_query_string_template()
{
var subscriptionId = Guid.NewGuid().ToString();
var unitId = Guid.NewGuid().ToString();
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/api/units/{subscriptionId}/{unitId}/updates",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", $"/api/subscriptions/{subscriptionId}/updates", $"?unitId={unitId}", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway($"/api/units/{subscriptionId}/{unitId}/updates"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_return_response_200_with_odata_query_string()
{
var subscriptionId = Guid.NewGuid().ToString();
var unitId = Guid.NewGuid().ToString();
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/{everything}",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/{everything}",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", $"/odata/customers", "?$filter=Name%20eq%20'Sam'", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway($"/odata/customers?$filter=Name eq 'Sam' "))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_return_response_200_with_query_string_upstream_template()
{
var subscriptionId = Guid.NewGuid().ToString();
var unitId = Guid.NewGuid().ToString();
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/api/units/{subscriptionId}/{unitId}/updates",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", $"/api/units/{subscriptionId}/{unitId}/updates", "", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway($"/api/subscriptions/{subscriptionId}/updates?unitId={unitId}"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_return_response_404_with_query_string_upstream_template_no_query_string()
{
var subscriptionId = Guid.NewGuid().ToString();
var unitId = Guid.NewGuid().ToString();
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/api/units/{subscriptionId}/{unitId}/updates",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", $"/api/units/{subscriptionId}/{unitId}/updates", "", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway($"/api/subscriptions/{subscriptionId}/updates"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound))
.BDDfy();
}
[Fact]
public void should_return_response_404_with_query_string_upstream_template_different_query_string()
{
var subscriptionId = Guid.NewGuid().ToString();
var unitId = Guid.NewGuid().ToString();
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/api/units/{subscriptionId}/{unitId}/updates",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", $"/api/units/{subscriptionId}/{unitId}/updates", "", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway($"/api/subscriptions/{subscriptionId}/updates?test=1"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound))
.BDDfy();
}
[Fact]
public void should_return_response_200_with_query_string_upstream_template_multiple_params()
{
var subscriptionId = Guid.NewGuid().ToString();
var unitId = Guid.NewGuid().ToString();
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/api/units/{subscriptionId}/{unitId}/updates",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", $"/api/units/{subscriptionId}/{unitId}/updates", "?productId=1", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway($"/api/subscriptions/{subscriptionId}/updates?unitId={unitId}&productId=1"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, string queryString, int statusCode, string responseBody)
{
_serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
{
if ((context.Request.PathBase.Value != basePath) || context.Request.QueryString.Value != queryString)
{
context.Response.StatusCode = 500;
await context.Response.WriteAsync("downstream path didnt match base path");
}
else
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
}
});
}
public void Dispose()
{
_serviceHandler?.Dispose();
_steps.Dispose();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,208 +1,208 @@
namespace Ocelot.AcceptanceTests
{
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using System;
using System.Collections.Generic;
using System.Net;
using TestStack.BDDfy;
using Xunit;
public class ServiceFabricTests : IDisposable
{
private readonly Steps _steps;
private string _downstreamPath;
private readonly ServiceHandler _serviceHandler;
public ServiceFabricTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
}
[Fact]
public void should_fix_issue_555()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/{everything}",
DownstreamScheme = "http",
UpstreamPathTemplate = "/{everything}",
UpstreamHttpMethod = new List<string> { "Get" },
ServiceName = "OcelotServiceApplication/OcelotApplicationService"
}
},
GlobalConfiguration = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Host = "localhost",
Port = port,
Type = "ServiceFabric"
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/OcelotServiceApplication/OcelotApplicationService/a", 200, "Hello from Laura", "b=c"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/a?b=c"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_support_service_fabric_naming_and_dns_service_stateless_and_guest()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/api/values",
DownstreamScheme = "http",
UpstreamPathTemplate = "/EquipmentInterfaces",
UpstreamHttpMethod = new List<string> { "Get" },
ServiceName = "OcelotServiceApplication/OcelotApplicationService"
}
},
GlobalConfiguration = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Host = "localhost",
Port = port,
Type = "ServiceFabric"
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/OcelotServiceApplication/OcelotApplicationService/api/values", 200, "Hello from Laura", "test=best"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/EquipmentInterfaces?test=best"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_support_service_fabric_naming_and_dns_service_statefull_and_actors()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/api/values",
DownstreamScheme = "http",
UpstreamPathTemplate = "/EquipmentInterfaces",
UpstreamHttpMethod = new List<string> { "Get" },
ServiceName = "OcelotServiceApplication/OcelotApplicationService"
}
},
GlobalConfiguration = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Host = "localhost",
Port = port,
Type = "ServiceFabric"
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/OcelotServiceApplication/OcelotApplicationService/api/values", 200, "Hello from Laura", "PartitionKind=test&PartitionKey=1"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/EquipmentInterfaces?PartitionKind=test&PartitionKey=1"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_support_placeholder_in_service_fabric_service_name()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/values",
DownstreamScheme = "http",
UpstreamPathTemplate = "/api/{version}/values",
UpstreamHttpMethod = new List<string> { "Get" },
ServiceName = "Service_{version}/Api"
}
},
GlobalConfiguration = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Host = "localhost",
Port = port,
Type = "ServiceFabric"
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/Service_1.0/Api/values", 200, "Hello from Laura", "test=best"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/api/1.0/values?test=best"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody, string expectedQueryString)
{
_serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
{
_downstreamPath = !string.IsNullOrEmpty(context.Request.PathBase.Value) ? context.Request.PathBase.Value : context.Request.Path.Value;
if (_downstreamPath != basePath)
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync("downstream path didnt match base path");
}
else
{
if (context.Request.QueryString.Value.Contains(expectedQueryString))
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
}
else
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync("downstream path didnt match base path");
}
}
});
}
public void Dispose()
{
_serviceHandler?.Dispose();
_steps.Dispose();
}
}
}
namespace Ocelot.AcceptanceTests
{
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using System;
using System.Collections.Generic;
using System.Net;
using TestStack.BDDfy;
using Xunit;
public class ServiceFabricTests : IDisposable
{
private readonly Steps _steps;
private string _downstreamPath;
private readonly ServiceHandler _serviceHandler;
public ServiceFabricTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
}
[Fact]
public void should_fix_issue_555()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/{everything}",
DownstreamScheme = "http",
UpstreamPathTemplate = "/{everything}",
UpstreamHttpMethod = new List<string> { "Get" },
ServiceName = "OcelotServiceApplication/OcelotApplicationService"
}
},
GlobalConfiguration = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Host = "localhost",
Port = port,
Type = "ServiceFabric"
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/OcelotServiceApplication/OcelotApplicationService/a", 200, "Hello from Laura", "b=c"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/a?b=c"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_support_service_fabric_naming_and_dns_service_stateless_and_guest()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/api/values",
DownstreamScheme = "http",
UpstreamPathTemplate = "/EquipmentInterfaces",
UpstreamHttpMethod = new List<string> { "Get" },
ServiceName = "OcelotServiceApplication/OcelotApplicationService"
}
},
GlobalConfiguration = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Host = "localhost",
Port = port,
Type = "ServiceFabric"
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/OcelotServiceApplication/OcelotApplicationService/api/values", 200, "Hello from Laura", "test=best"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/EquipmentInterfaces?test=best"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_support_service_fabric_naming_and_dns_service_statefull_and_actors()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/api/values",
DownstreamScheme = "http",
UpstreamPathTemplate = "/EquipmentInterfaces",
UpstreamHttpMethod = new List<string> { "Get" },
ServiceName = "OcelotServiceApplication/OcelotApplicationService"
}
},
GlobalConfiguration = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Host = "localhost",
Port = port,
Type = "ServiceFabric"
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/OcelotServiceApplication/OcelotApplicationService/api/values", 200, "Hello from Laura", "PartitionKind=test&PartitionKey=1"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/EquipmentInterfaces?PartitionKind=test&PartitionKey=1"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_support_placeholder_in_service_fabric_service_name()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/values",
DownstreamScheme = "http",
UpstreamPathTemplate = "/api/{version}/values",
UpstreamHttpMethod = new List<string> { "Get" },
ServiceName = "Service_{version}/Api"
}
},
GlobalConfiguration = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Host = "localhost",
Port = port,
Type = "ServiceFabric"
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/Service_1.0/Api/values", 200, "Hello from Laura", "test=best"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/api/1.0/values?test=best"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody, string expectedQueryString)
{
_serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
{
_downstreamPath = !string.IsNullOrEmpty(context.Request.PathBase.Value) ? context.Request.PathBase.Value : context.Request.Path.Value;
if (_downstreamPath != basePath)
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync("downstream path didnt match base path");
}
else
{
if (context.Request.QueryString.Value.Contains(expectedQueryString))
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
}
else
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync("downstream path didnt match base path");
}
}
});
}
public void Dispose()
{
_serviceHandler?.Dispose();
_steps.Dispose();
}
}
}

View File

@ -27,9 +27,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "https",
@ -64,9 +64,9 @@ namespace Ocelot.AcceptanceTests
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "https",

View File

@ -1,102 +1,102 @@
namespace Ocelot.AcceptanceTests
{
using Configuration.Repository;
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using Responses;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Threading.Tasks;
using TestStack.BDDfy;
using Xunit;
public class StartupTests : IDisposable
{
private readonly Steps _steps;
private readonly ServiceHandler _serviceHandler;
private string _downstreamPath;
public StartupTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
}
[Fact]
public void should_not_try_and_write_to_disk_on_startup_when_not_using_admin_api()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
var fakeRepo = new FakeFileConfigurationRepository();
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningWithBlowingUpDiskRepo(fakeRepo))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody)
{
_serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
{
_downstreamPath = !string.IsNullOrEmpty(context.Request.PathBase.Value) ? context.Request.PathBase.Value : context.Request.Path.Value;
if (_downstreamPath != basePath)
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync("downstream path didnt match base path");
}
else
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
}
});
}
public void Dispose()
{
_serviceHandler?.Dispose();
_steps.Dispose();
}
private class FakeFileConfigurationRepository : IFileConfigurationRepository
{
public Task<Response<FileConfiguration>> Get()
{
throw new NotImplementedException();
}
public Task<Response> Set(FileConfiguration fileConfiguration)
{
throw new NotImplementedException();
}
}
}
}
namespace Ocelot.AcceptanceTests
{
using Configuration.Repository;
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using Responses;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Threading.Tasks;
using TestStack.BDDfy;
using Xunit;
public class StartupTests : IDisposable
{
private readonly Steps _steps;
private readonly ServiceHandler _serviceHandler;
private string _downstreamPath;
public StartupTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
}
[Fact]
public void should_not_try_and_write_to_disk_on_startup_when_not_using_admin_api()
{
var port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
var fakeRepo = new FakeFileConfigurationRepository();
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningWithBlowingUpDiskRepo(fakeRepo))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody)
{
_serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
{
_downstreamPath = !string.IsNullOrEmpty(context.Request.PathBase.Value) ? context.Request.PathBase.Value : context.Request.Path.Value;
if (_downstreamPath != basePath)
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync("downstream path didnt match base path");
}
else
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
}
});
}
public void Dispose()
{
_serviceHandler?.Dispose();
_steps.Dispose();
}
private class FakeFileConfigurationRepository : IFileConfigurationRepository
{
public Task<Response<FileConfiguration>> Get()
{
throw new NotImplementedException();
}
public Task<Response> Set(FileConfiguration fileConfiguration)
{
throw new NotImplementedException();
}
}
}
}

View File

@ -261,7 +261,7 @@ namespace Ocelot.AcceptanceTests
/// <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 GivenOcelotIsRunningWithCustomLoadBalancer<T>(Func<IServiceProvider, DownstreamReRoute, IServiceDiscoveryProvider, T> loadBalancerFactoryFunc)
public void GivenOcelotIsRunningWithCustomLoadBalancer<T>(Func<IServiceProvider, DownstreamRoute, IServiceDiscoveryProvider, T> loadBalancerFactoryFunc)
where T : ILoadBalancer
{
_webHostBuilder = new WebHostBuilder();

View File

@ -1,293 +1,293 @@
namespace Ocelot.AcceptanceTests
{
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using Shouldly;
using System;
using System.Collections.Generic;
using TestStack.BDDfy;
using Xunit;
public class StickySessionsTests : IDisposable
{
private readonly Steps _steps;
private int _counterOne;
private int _counterTwo;
private static readonly object SyncLock = new object();
private readonly ServiceHandler _serviceHandler;
public StickySessionsTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
}
[Fact]
public void should_use_same_downstream_host()
{
var downstreamPortOne = RandomPortFinder.GetRandomPort();
var downstreamPortTwo = RandomPortFinder.GetRandomPort();
var downstreamServiceOneUrl = $"http://localhost:{downstreamPortOne}";
var downstreamServiceTwoUrl = $"http://localhost:{downstreamPortTwo}";
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
LoadBalancerOptions = new FileLoadBalancerOptions
{
Type = "CookieStickySessions",
Key = "sessionid",
Expiry = 300000
},
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = downstreamPortOne
},
new FileHostAndPort
{
Host = "localhost",
Port = downstreamPortTwo
}
}
}
}
};
this.Given(x => x.GivenProductServiceOneIsRunning(downstreamServiceOneUrl, 200))
.And(x => x.GivenProductServiceTwoIsRunning(downstreamServiceTwoUrl, 200))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimes("/", 10, "sessionid", "123"))
.Then(x => x.ThenTheFirstServiceIsCalled(10))
.Then(x => x.ThenTheSecondServiceIsCalled(0))
.BDDfy();
}
[Fact]
public void should_use_different_downstream_host_for_different_re_route()
{
var downstreamPortOne = RandomPortFinder.GetRandomPort();
var downstreamPortTwo = RandomPortFinder.GetRandomPort();
var downstreamServiceOneUrl = $"http://localhost:{downstreamPortOne}";
var downstreamServiceTwoUrl = $"http://localhost:{downstreamPortTwo}";
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
LoadBalancerOptions = new FileLoadBalancerOptions
{
Type = "CookieStickySessions",
Key = "sessionid",
Expiry = 300000
},
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = downstreamPortOne
},
new FileHostAndPort
{
Host = "localhost",
Port = downstreamPortTwo
}
}
},
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
UpstreamPathTemplate = "/test",
UpstreamHttpMethod = new List<string> { "Get" },
LoadBalancerOptions = new FileLoadBalancerOptions
{
Type = "CookieStickySessions",
Key = "bestid",
Expiry = 300000
},
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = downstreamPortTwo
},
new FileHostAndPort
{
Host = "localhost",
Port = downstreamPortOne
}
}
}
}
};
this.Given(x => x.GivenProductServiceOneIsRunning(downstreamServiceOneUrl, 200))
.And(x => x.GivenProductServiceTwoIsRunning(downstreamServiceTwoUrl, 200))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/", "sessionid", "123"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/test", "bestid", "123"))
.Then(x => x.ThenTheFirstServiceIsCalled(1))
.Then(x => x.ThenTheSecondServiceIsCalled(1))
.BDDfy();
}
[Fact]
public void should_use_same_downstream_host_for_different_re_route()
{
var downstreamPortOne = RandomPortFinder.GetRandomPort();
var downstreamPortTwo = RandomPortFinder.GetRandomPort();
var downstreamServiceOneUrl = $"http://localhost:{downstreamPortOne}";
var downstreamServiceTwoUrl = $"http://localhost:{downstreamPortTwo}";
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
LoadBalancerOptions = new FileLoadBalancerOptions
{
Type = "CookieStickySessions",
Key = "sessionid",
Expiry = 300000
},
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = downstreamPortOne
},
new FileHostAndPort
{
Host = "localhost",
Port = downstreamPortTwo
}
}
},
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
UpstreamPathTemplate = "/test",
UpstreamHttpMethod = new List<string> { "Get" },
LoadBalancerOptions = new FileLoadBalancerOptions
{
Type = "CookieStickySessions",
Key = "sessionid",
Expiry = 300000
},
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = downstreamPortTwo
},
new FileHostAndPort
{
Host = "localhost",
Port = downstreamPortOne
}
}
}
}
};
this.Given(x => x.GivenProductServiceOneIsRunning(downstreamServiceOneUrl, 200))
.And(x => x.GivenProductServiceTwoIsRunning(downstreamServiceTwoUrl, 200))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/", "sessionid", "123"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/test", "sessionid", "123"))
.Then(x => x.ThenTheFirstServiceIsCalled(2))
.Then(x => x.ThenTheSecondServiceIsCalled(0))
.BDDfy();
}
private void ThenTheFirstServiceIsCalled(int expected)
{
_counterOne.ShouldBe(expected);
}
private void ThenTheSecondServiceIsCalled(int expected)
{
_counterTwo.ShouldBe(expected);
}
private void GivenProductServiceOneIsRunning(string url, int statusCode)
{
_serviceHandler.GivenThereIsAServiceRunningOn(url, async context =>
{
try
{
var response = string.Empty;
lock (SyncLock)
{
_counterOne++;
response = _counterOne.ToString();
}
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(response);
}
catch (Exception exception)
{
await context.Response.WriteAsync(exception.StackTrace);
}
});
}
private void GivenProductServiceTwoIsRunning(string url, int statusCode)
{
_serviceHandler.GivenThereIsAServiceRunningOn(url, async context =>
{
try
{
var response = string.Empty;
lock (SyncLock)
{
_counterTwo++;
response = _counterTwo.ToString();
}
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(response);
}
catch (Exception exception)
{
await context.Response.WriteAsync(exception.StackTrace);
}
});
}
public void Dispose()
{
_serviceHandler?.Dispose();
_steps.Dispose();
}
}
}
namespace Ocelot.AcceptanceTests
{
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using Shouldly;
using System;
using System.Collections.Generic;
using TestStack.BDDfy;
using Xunit;
public class StickySessionsTests : IDisposable
{
private readonly Steps _steps;
private int _counterOne;
private int _counterTwo;
private static readonly object SyncLock = new object();
private readonly ServiceHandler _serviceHandler;
public StickySessionsTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
}
[Fact]
public void should_use_same_downstream_host()
{
var downstreamPortOne = RandomPortFinder.GetRandomPort();
var downstreamPortTwo = RandomPortFinder.GetRandomPort();
var downstreamServiceOneUrl = $"http://localhost:{downstreamPortOne}";
var downstreamServiceTwoUrl = $"http://localhost:{downstreamPortTwo}";
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
LoadBalancerOptions = new FileLoadBalancerOptions
{
Type = "CookieStickySessions",
Key = "sessionid",
Expiry = 300000
},
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = downstreamPortOne
},
new FileHostAndPort
{
Host = "localhost",
Port = downstreamPortTwo
}
}
}
}
};
this.Given(x => x.GivenProductServiceOneIsRunning(downstreamServiceOneUrl, 200))
.And(x => x.GivenProductServiceTwoIsRunning(downstreamServiceTwoUrl, 200))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimes("/", 10, "sessionid", "123"))
.Then(x => x.ThenTheFirstServiceIsCalled(10))
.Then(x => x.ThenTheSecondServiceIsCalled(0))
.BDDfy();
}
[Fact]
public void should_use_different_downstream_host_for_different_re_route()
{
var downstreamPortOne = RandomPortFinder.GetRandomPort();
var downstreamPortTwo = RandomPortFinder.GetRandomPort();
var downstreamServiceOneUrl = $"http://localhost:{downstreamPortOne}";
var downstreamServiceTwoUrl = $"http://localhost:{downstreamPortTwo}";
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
LoadBalancerOptions = new FileLoadBalancerOptions
{
Type = "CookieStickySessions",
Key = "sessionid",
Expiry = 300000
},
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = downstreamPortOne
},
new FileHostAndPort
{
Host = "localhost",
Port = downstreamPortTwo
}
}
},
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
UpstreamPathTemplate = "/test",
UpstreamHttpMethod = new List<string> { "Get" },
LoadBalancerOptions = new FileLoadBalancerOptions
{
Type = "CookieStickySessions",
Key = "bestid",
Expiry = 300000
},
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = downstreamPortTwo
},
new FileHostAndPort
{
Host = "localhost",
Port = downstreamPortOne
}
}
}
}
};
this.Given(x => x.GivenProductServiceOneIsRunning(downstreamServiceOneUrl, 200))
.And(x => x.GivenProductServiceTwoIsRunning(downstreamServiceTwoUrl, 200))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/", "sessionid", "123"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/test", "bestid", "123"))
.Then(x => x.ThenTheFirstServiceIsCalled(1))
.Then(x => x.ThenTheSecondServiceIsCalled(1))
.BDDfy();
}
[Fact]
public void should_use_same_downstream_host_for_different_re_route()
{
var downstreamPortOne = RandomPortFinder.GetRandomPort();
var downstreamPortTwo = RandomPortFinder.GetRandomPort();
var downstreamServiceOneUrl = $"http://localhost:{downstreamPortOne}";
var downstreamServiceTwoUrl = $"http://localhost:{downstreamPortTwo}";
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
LoadBalancerOptions = new FileLoadBalancerOptions
{
Type = "CookieStickySessions",
Key = "sessionid",
Expiry = 300000
},
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = downstreamPortOne
},
new FileHostAndPort
{
Host = "localhost",
Port = downstreamPortTwo
}
}
},
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
UpstreamPathTemplate = "/test",
UpstreamHttpMethod = new List<string> { "Get" },
LoadBalancerOptions = new FileLoadBalancerOptions
{
Type = "CookieStickySessions",
Key = "sessionid",
Expiry = 300000
},
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = downstreamPortTwo
},
new FileHostAndPort
{
Host = "localhost",
Port = downstreamPortOne
}
}
}
}
};
this.Given(x => x.GivenProductServiceOneIsRunning(downstreamServiceOneUrl, 200))
.And(x => x.GivenProductServiceTwoIsRunning(downstreamServiceTwoUrl, 200))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/", "sessionid", "123"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/test", "sessionid", "123"))
.Then(x => x.ThenTheFirstServiceIsCalled(2))
.Then(x => x.ThenTheSecondServiceIsCalled(0))
.BDDfy();
}
private void ThenTheFirstServiceIsCalled(int expected)
{
_counterOne.ShouldBe(expected);
}
private void ThenTheSecondServiceIsCalled(int expected)
{
_counterTwo.ShouldBe(expected);
}
private void GivenProductServiceOneIsRunning(string url, int statusCode)
{
_serviceHandler.GivenThereIsAServiceRunningOn(url, async context =>
{
try
{
var response = string.Empty;
lock (SyncLock)
{
_counterOne++;
response = _counterOne.ToString();
}
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(response);
}
catch (Exception exception)
{
await context.Response.WriteAsync(exception.StackTrace);
}
});
}
private void GivenProductServiceTwoIsRunning(string url, int statusCode)
{
_serviceHandler.GivenThereIsAServiceRunningOn(url, async context =>
{
try
{
var response = string.Empty;
lock (SyncLock)
{
_counterTwo++;
response = _counterTwo.ToString();
}
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(response);
}
catch (Exception exception)
{
await context.Response.WriteAsync(exception.StackTrace);
}
});
}
public void Dispose()
{
_serviceHandler?.Dispose();
_steps.Dispose();
}
}
}

View File

@ -1,157 +1,157 @@
namespace Ocelot.AcceptanceTests
{
using Configuration.File;
using Consul;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net;
using TestStack.BDDfy;
using Xunit;
public class TwoDownstreamServicesTests : IDisposable
{
private readonly Steps _steps;
private readonly List<ServiceEntry> _serviceEntries;
private string _downstreamPathOne;
private string _downstreamPathTwo;
private readonly ServiceHandler _serviceHandler;
public TwoDownstreamServicesTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
_serviceEntries = new List<ServiceEntry>();
}
[Fact]
public void should_fix_issue_194()
{
var consulPort = RandomPortFinder.GetRandomPort();
var servicePort1 = RandomPortFinder.GetRandomPort();
var servicePort2 = RandomPortFinder.GetRandomPort();
var downstreamServiceOneUrl = $"http://localhost:{servicePort1}";
var downstreamServiceTwoUrl = $"http://localhost:{servicePort2}";
var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}";
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/api/user/{user}",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = servicePort1,
}
},
UpstreamPathTemplate = "/api/user/{user}",
UpstreamHttpMethod = new List<string> { "Get" },
},
new FileReRoute
{
DownstreamPathTemplate = "/api/product/{product}",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = servicePort2,
}
},
UpstreamPathTemplate = "/api/product/{product}",
UpstreamHttpMethod = new List<string> { "Get" },
}
},
GlobalConfiguration = new FileGlobalConfiguration()
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Scheme = "https",
Host = "localhost",
Port = consulPort
}
}
};
this.Given(x => x.GivenProductServiceOneIsRunning(downstreamServiceOneUrl, "/api/user/info", 200, "user"))
.And(x => x.GivenProductServiceTwoIsRunning(downstreamServiceTwoUrl, "/api/product/info", 200, "product"))
.And(x => x.GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/api/user/info?id=1"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("user"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/api/product/info?id=1"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("product"))
.BDDfy();
}
private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url)
{
_serviceHandler.GivenThereIsAServiceRunningOn(url, async context =>
{
if (context.Request.Path.Value == "/v1/health/service/product")
{
var json = JsonConvert.SerializeObject(_serviceEntries);
context.Response.Headers.Add("Content-Type", "application/json");
await context.Response.WriteAsync(json);
}
});
}
private void GivenProductServiceOneIsRunning(string baseUrl, string basePath, int statusCode, string responseBody)
{
_serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
{
_downstreamPathOne = !string.IsNullOrEmpty(context.Request.PathBase.Value)
? context.Request.PathBase.Value
: context.Request.Path.Value;
if (_downstreamPathOne != basePath)
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync("downstream path didnt match base path");
}
else
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
}
});
}
private void GivenProductServiceTwoIsRunning(string baseUrl, string basePath, int statusCode, string responseBody)
{
_serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
{
_downstreamPathTwo = !string.IsNullOrEmpty(context.Request.PathBase.Value) ? context.Request.PathBase.Value : context.Request.Path.Value;
if (_downstreamPathTwo != basePath)
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync("downstream path didnt match base path");
}
else
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
}
});
}
public void Dispose()
{
_serviceHandler?.Dispose();
_steps.Dispose();
}
}
}
namespace Ocelot.AcceptanceTests
{
using Configuration.File;
using Consul;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net;
using TestStack.BDDfy;
using Xunit;
public class TwoDownstreamServicesTests : IDisposable
{
private readonly Steps _steps;
private readonly List<ServiceEntry> _serviceEntries;
private string _downstreamPathOne;
private string _downstreamPathTwo;
private readonly ServiceHandler _serviceHandler;
public TwoDownstreamServicesTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
_serviceEntries = new List<ServiceEntry>();
}
[Fact]
public void should_fix_issue_194()
{
var consulPort = RandomPortFinder.GetRandomPort();
var servicePort1 = RandomPortFinder.GetRandomPort();
var servicePort2 = RandomPortFinder.GetRandomPort();
var downstreamServiceOneUrl = $"http://localhost:{servicePort1}";
var downstreamServiceTwoUrl = $"http://localhost:{servicePort2}";
var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}";
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/api/user/{user}",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = servicePort1,
}
},
UpstreamPathTemplate = "/api/user/{user}",
UpstreamHttpMethod = new List<string> { "Get" },
},
new FileRoute
{
DownstreamPathTemplate = "/api/product/{product}",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = servicePort2,
}
},
UpstreamPathTemplate = "/api/product/{product}",
UpstreamHttpMethod = new List<string> { "Get" },
}
},
GlobalConfiguration = new FileGlobalConfiguration()
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
{
Scheme = "https",
Host = "localhost",
Port = consulPort
}
}
};
this.Given(x => x.GivenProductServiceOneIsRunning(downstreamServiceOneUrl, "/api/user/info", 200, "user"))
.And(x => x.GivenProductServiceTwoIsRunning(downstreamServiceTwoUrl, "/api/product/info", 200, "product"))
.And(x => x.GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/api/user/info?id=1"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("user"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/api/product/info?id=1"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("product"))
.BDDfy();
}
private void GivenThereIsAFakeConsulServiceDiscoveryProvider(string url)
{
_serviceHandler.GivenThereIsAServiceRunningOn(url, async context =>
{
if (context.Request.Path.Value == "/v1/health/service/product")
{
var json = JsonConvert.SerializeObject(_serviceEntries);
context.Response.Headers.Add("Content-Type", "application/json");
await context.Response.WriteAsync(json);
}
});
}
private void GivenProductServiceOneIsRunning(string baseUrl, string basePath, int statusCode, string responseBody)
{
_serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
{
_downstreamPathOne = !string.IsNullOrEmpty(context.Request.PathBase.Value)
? context.Request.PathBase.Value
: context.Request.Path.Value;
if (_downstreamPathOne != basePath)
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync("downstream path didnt match base path");
}
else
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
}
});
}
private void GivenProductServiceTwoIsRunning(string baseUrl, string basePath, int statusCode, string responseBody)
{
_serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
{
_downstreamPathTwo = !string.IsNullOrEmpty(context.Request.PathBase.Value) ? context.Request.PathBase.Value : context.Request.Path.Value;
if (_downstreamPathTwo != basePath)
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync("downstream path didnt match base path");
}
else
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
}
});
}
public void Dispose()
{
_serviceHandler?.Dispose();
_steps.Dispose();
}
}
}

View File

@ -1,279 +1,279 @@
namespace Ocelot.AcceptanceTests
{
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using System;
using System.Collections.Generic;
using System.Net;
using TestStack.BDDfy;
using Xunit;
public class UpstreamHostTests : IDisposable
{
private readonly Steps _steps;
private string _downstreamPath;
private readonly ServiceHandler _serviceHandler;
public UpstreamHostTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
}
[Fact]
public void should_return_response_200_with_simple_url_and_hosts_match()
{
int port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
UpstreamHost = "localhost"
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_return_response_200_with_simple_url_and_hosts_match_multiple_re_routes()
{
int port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
UpstreamHost = "localhost"
},
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 50000,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
UpstreamHost = "DONTMATCH"
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_return_response_200_with_simple_url_and_hosts_match_multiple_re_routes_reversed()
{
int port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 50000,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
UpstreamHost = "DONTMATCH"
},
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
UpstreamHost = "localhost"
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_return_response_200_with_simple_url_and_hosts_match_multiple_re_routes_reversed_with_no_host_first()
{
int port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 50000,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
},
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
UpstreamHost = "localhost"
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_return_response_404_with_simple_url_and_hosts_dont_match()
{
int port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
UpstreamHost = "127.0.0.20:5000"
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody)
{
_serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
{
_downstreamPath = !string.IsNullOrEmpty(context.Request.PathBase.Value) ? context.Request.PathBase.Value : context.Request.Path.Value;
if (_downstreamPath != basePath)
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync("downstream path didnt match base path");
}
else
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
}
});
}
public void Dispose()
{
_serviceHandler?.Dispose();
_steps.Dispose();
}
}
}
namespace Ocelot.AcceptanceTests
{
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using System;
using System.Collections.Generic;
using System.Net;
using TestStack.BDDfy;
using Xunit;
public class UpstreamHostTests : IDisposable
{
private readonly Steps _steps;
private string _downstreamPath;
private readonly ServiceHandler _serviceHandler;
public UpstreamHostTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
}
[Fact]
public void should_return_response_200_with_simple_url_and_hosts_match()
{
int port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
UpstreamHost = "localhost"
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_return_response_200_with_simple_url_and_hosts_match_multiple_re_routes()
{
int port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
UpstreamHost = "localhost"
},
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 50000,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
UpstreamHost = "DONTMATCH"
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_return_response_200_with_simple_url_and_hosts_match_multiple_re_routes_reversed()
{
int port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 50000,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
UpstreamHost = "DONTMATCH"
},
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
UpstreamHost = "localhost"
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_return_response_200_with_simple_url_and_hosts_match_multiple_re_routes_reversed_with_no_host_first()
{
int port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 50000,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
},
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
UpstreamHost = "localhost"
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact]
public void should_return_response_404_with_simple_url_and_hosts_dont_match()
{
int port = RandomPortFinder.GetRandomPort();
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = port,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
UpstreamHost = "127.0.0.20:5000"
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}", "/", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound))
.BDDfy();
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody)
{
_serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
{
_downstreamPath = !string.IsNullOrEmpty(context.Request.PathBase.Value) ? context.Request.PathBase.Value : context.Request.Path.Value;
if (_downstreamPath != basePath)
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync("downstream path didnt match base path");
}
else
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
}
});
}
public void Dispose()
{
_serviceHandler?.Dispose();
_steps.Dispose();
}
}
}

View File

@ -1,334 +1,334 @@
namespace Ocelot.AcceptanceTests
{
using Ocelot.Configuration.File;
using Shouldly;
using System;
using System.Collections.Generic;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using TestStack.BDDfy;
using Xunit;
public class WebSocketTests : IDisposable
{
private readonly List<string> _secondRecieved;
private readonly List<string> _firstRecieved;
private readonly Steps _steps;
private readonly ServiceHandler _serviceHandler;
public WebSocketTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
_firstRecieved = new List<string>();
_secondRecieved = new List<string>();
}
[Fact]
public void should_proxy_websocket_input_to_downstream_service()
{
var downstreamPort = RandomPortFinder.GetRandomPort();
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 void should_proxy_websocket_input_to_downstream_service_and_use_load_balancer()
{
var downstreamPort = RandomPortFinder.GetRandomPort();
var downstreamHost = "localhost";
var secondDownstreamPort = RandomPortFinder.GetRandomPort();
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
}
},
LoadBalancerOptions = new FileLoadBalancerOptions { Type = "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();
}
private void ThenBothDownstreamServicesAreCalled()
{
_firstRecieved.Count.ShouldBe(10);
_firstRecieved.ForEach(x =>
{
x.ShouldBe("test");
});
_secondRecieved.Count.ShouldBe(10);
_secondRecieved.ForEach(x =>
{
x.ShouldBe("chocolate");
});
}
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)
{
if (client.State != WebSocketState.Closed)
{
// Last version, the client state is CloseReceived
// Valid states are: Open, CloseReceived, CloseSent
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)
{
if (client.State != WebSocketState.Closed)
{
// Last version, the client state is CloseReceived
// Valid states are: Open, CloseReceived, CloseSent
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
}
break;
}
}
});
await Task.WhenAll(sending, receiving);
}
private async Task StartFakeDownstreamService(string url, string path)
{
await _serviceHandler.StartFakeDownstreamService(url, path, async (context, next) =>
{
if (context.Request.Path == path)
{
if (context.WebSockets.IsWebSocketRequest)
{
var webSocket = await context.WebSockets.AcceptWebSocketAsync();
await Echo(webSocket);
}
else
{
context.Response.StatusCode = 400;
}
}
else
{
await next();
}
});
}
private async Task StartSecondFakeDownstreamService(string url, string path)
{
await _serviceHandler.StartFakeDownstreamService(url, path, 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();
}
});
}
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()
{
_serviceHandler?.Dispose();
_steps.Dispose();
}
}
}
namespace Ocelot.AcceptanceTests
{
using Ocelot.Configuration.File;
using Shouldly;
using System;
using System.Collections.Generic;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using TestStack.BDDfy;
using Xunit;
public class WebSocketTests : IDisposable
{
private readonly List<string> _secondRecieved;
private readonly List<string> _firstRecieved;
private readonly Steps _steps;
private readonly ServiceHandler _serviceHandler;
public WebSocketTests()
{
_serviceHandler = new ServiceHandler();
_steps = new Steps();
_firstRecieved = new List<string>();
_secondRecieved = new List<string>();
}
[Fact]
public void should_proxy_websocket_input_to_downstream_service()
{
var downstreamPort = RandomPortFinder.GetRandomPort();
var downstreamHost = "localhost";
var config = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
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 void should_proxy_websocket_input_to_downstream_service_and_use_load_balancer()
{
var downstreamPort = RandomPortFinder.GetRandomPort();
var downstreamHost = "localhost";
var secondDownstreamPort = RandomPortFinder.GetRandomPort();
var secondDownstreamHost = "localhost";
var config = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
UpstreamPathTemplate = "/",
DownstreamPathTemplate = "/ws",
DownstreamScheme = "ws",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = downstreamHost,
Port = downstreamPort
},
new FileHostAndPort
{
Host = secondDownstreamHost,
Port = secondDownstreamPort
}
},
LoadBalancerOptions = new FileLoadBalancerOptions { Type = "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();
}
private void ThenBothDownstreamServicesAreCalled()
{
_firstRecieved.Count.ShouldBe(10);
_firstRecieved.ForEach(x =>
{
x.ShouldBe("test");
});
_secondRecieved.Count.ShouldBe(10);
_secondRecieved.ForEach(x =>
{
x.ShouldBe("chocolate");
});
}
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)
{
if (client.State != WebSocketState.Closed)
{
// Last version, the client state is CloseReceived
// Valid states are: Open, CloseReceived, CloseSent
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)
{
if (client.State != WebSocketState.Closed)
{
// Last version, the client state is CloseReceived
// Valid states are: Open, CloseReceived, CloseSent
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
}
break;
}
}
});
await Task.WhenAll(sending, receiving);
}
private async Task StartFakeDownstreamService(string url, string path)
{
await _serviceHandler.StartFakeDownstreamService(url, path, async (context, next) =>
{
if (context.Request.Path == path)
{
if (context.WebSockets.IsWebSocketRequest)
{
var webSocket = await context.WebSockets.AcceptWebSocketAsync();
await Echo(webSocket);
}
else
{
context.Response.StatusCode = 400;
}
}
else
{
await next();
}
});
}
private async Task StartSecondFakeDownstreamService(string url, string path)
{
await _serviceHandler.StartFakeDownstreamService(url, path, 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();
}
});
}
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()
{
_serviceHandler?.Dispose();
_steps.Dispose();
}
}
}

View File

@ -1,156 +1,156 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Columns;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Validators;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Ocelot.Configuration.File;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
namespace Ocelot.Benchmarks
{
[Config(typeof(AllTheThingsBenchmarks))]
public class AllTheThingsBenchmarks : ManualConfig
{
private IWebHost _service;
private IWebHost _ocelot;
private HttpClient _httpClient;
public AllTheThingsBenchmarks()
{
Add(StatisticColumn.AllStatistics);
Add(MemoryDiagnoser.Default);
Add(BaselineValidator.FailOnError);
}
[GlobalSetup]
public void SetUp()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51879,
}
},
DownstreamScheme = "http",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
GivenThereIsAServiceRunningOn("http://localhost:51879", "/", 201, string.Empty);
GivenThereIsAConfiguration(configuration);
GivenOcelotIsRunning("http://localhost:5000");
_httpClient = new HttpClient();
}
[Benchmark(Baseline = true)]
public async Task Baseline()
{
var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost:5000/");
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
}
/* * Summary*
BenchmarkDotNet = v0.10.13, OS = macOS 10.12.6 (16G1212) [Darwin 16.7.0]
Intel Core i5-4278U CPU 2.60GHz(Haswell), 1 CPU, 4 logical cores and 2 physical cores
.NET Core SDK = 2.1.4
[Host] : .NET Core 2.0.6 (CoreCLR 4.6.0.0, CoreFX 4.6.26212.01), 64bit RyuJIT
DefaultJob : .NET Core 2.0.6 (CoreCLR 4.6.0.0, CoreFX 4.6.26212.01), 64bit RyuJIT
Method | Mean | Error | StdDev | StdErr | Min | Q1 | Median | Q3 | Max | Op/s | Scaled | Gen 0 | Gen 1 | Allocated |
--------- |---------:|----------:|----------:|----------:|---------:|---------:|---------:|---------:|---------:|------:|-------:|--------:|-------:|----------:|
Baseline | 2.102 ms | 0.0292 ms | 0.0273 ms | 0.0070 ms | 2.063 ms | 2.080 ms | 2.093 ms | 2.122 ms | 2.152 ms | 475.8 | 1.00 | 31.2500 | 3.9063 | 1.63 KB |*/
private void GivenOcelotIsRunning(string url)
{
_ocelot = new WebHostBuilder()
.UseKestrel()
.UseUrls(url)
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((hostingContext, config) =>
{
config
.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
.AddJsonFile("appsettings.json", true, true)
.AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true)
.AddJsonFile("ocelot.json", false, false)
.AddEnvironmentVariables();
})
.ConfigureServices(s =>
{
s.AddOcelot();
})
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
})
.UseIISIntegration()
.Configure(app =>
{
app.UseOcelot().Wait();
})
.Build();
_ocelot.Start();
}
public void GivenThereIsAConfiguration(FileConfiguration fileConfiguration)
{
var configurationPath = Path.Combine(AppContext.BaseDirectory, "ocelot.json");
var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration);
if (File.Exists(configurationPath))
{
File.Delete(configurationPath);
}
File.WriteAllText(configurationPath, jsonConfiguration);
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody)
{
_service = new WebHostBuilder()
.UseUrls(baseUrl)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.Configure(app =>
{
app.UsePathBase(basePath);
app.Run(async context =>
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
});
})
.Build();
_service.Start();
}
}
}
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Columns;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Validators;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Ocelot.Configuration.File;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
namespace Ocelot.Benchmarks
{
[Config(typeof(AllTheThingsBenchmarks))]
public class AllTheThingsBenchmarks : ManualConfig
{
private IWebHost _service;
private IWebHost _ocelot;
private HttpClient _httpClient;
public AllTheThingsBenchmarks()
{
Add(StatisticColumn.AllStatistics);
Add(MemoryDiagnoser.Default);
Add(BaselineValidator.FailOnError);
}
[GlobalSetup]
public void SetUp()
{
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 51879,
}
},
DownstreamScheme = "http",
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
GivenThereIsAServiceRunningOn("http://localhost:51879", "/", 201, string.Empty);
GivenThereIsAConfiguration(configuration);
GivenOcelotIsRunning("http://localhost:5000");
_httpClient = new HttpClient();
}
[Benchmark(Baseline = true)]
public async Task Baseline()
{
var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost:5000/");
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
}
/* * Summary*
BenchmarkDotNet = v0.10.13, OS = macOS 10.12.6 (16G1212) [Darwin 16.7.0]
Intel Core i5-4278U CPU 2.60GHz(Haswell), 1 CPU, 4 logical cores and 2 physical cores
.NET Core SDK = 2.1.4
[Host] : .NET Core 2.0.6 (CoreCLR 4.6.0.0, CoreFX 4.6.26212.01), 64bit RyuJIT
DefaultJob : .NET Core 2.0.6 (CoreCLR 4.6.0.0, CoreFX 4.6.26212.01), 64bit RyuJIT
Method | Mean | Error | StdDev | StdErr | Min | Q1 | Median | Q3 | Max | Op/s | Scaled | Gen 0 | Gen 1 | Allocated |
--------- |---------:|----------:|----------:|----------:|---------:|---------:|---------:|---------:|---------:|------:|-------:|--------:|-------:|----------:|
Baseline | 2.102 ms | 0.0292 ms | 0.0273 ms | 0.0070 ms | 2.063 ms | 2.080 ms | 2.093 ms | 2.122 ms | 2.152 ms | 475.8 | 1.00 | 31.2500 | 3.9063 | 1.63 KB |*/
private void GivenOcelotIsRunning(string url)
{
_ocelot = new WebHostBuilder()
.UseKestrel()
.UseUrls(url)
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((hostingContext, config) =>
{
config
.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
.AddJsonFile("appsettings.json", true, true)
.AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true)
.AddJsonFile("ocelot.json", false, false)
.AddEnvironmentVariables();
})
.ConfigureServices(s =>
{
s.AddOcelot();
})
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
})
.UseIISIntegration()
.Configure(app =>
{
app.UseOcelot().Wait();
})
.Build();
_ocelot.Start();
}
public void GivenThereIsAConfiguration(FileConfiguration fileConfiguration)
{
var configurationPath = Path.Combine(AppContext.BaseDirectory, "ocelot.json");
var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration);
if (File.Exists(configurationPath))
{
File.Delete(configurationPath);
}
File.WriteAllText(configurationPath, jsonConfiguration);
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody)
{
_service = new WebHostBuilder()
.UseUrls(baseUrl)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.Configure(app =>
{
app.UsePathBase(basePath);
app.Run(async context =>
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
});
})
.Build();
_service.Start();
}
}
}

View File

@ -1,77 +1,76 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Columns;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Validators;
using System.Net.Http;
namespace Ocelot.Benchmarks
{
using Configuration;
using Configuration.Builder;
using Requester;
using System.Collections.Concurrent;
[Config(typeof(DictionaryBenchmarks))]
public class DictionaryBenchmarks : ManualConfig
{
private ConcurrentDictionary<DownstreamReRoute, IHttpClient> _downstreamReRouteDictionary;
private ConcurrentDictionary<string, IHttpClient> _stringReRouteDictionary;
private HttpClientWrapper _client;
private string _stringKey;
private DownstreamReRoute _downstreamReRouteKey;
public DictionaryBenchmarks()
{
Add(StatisticColumn.AllStatistics);
Add(MemoryDiagnoser.Default);
Add(BaselineValidator.FailOnError);
}
[GlobalSetup]
public void SetUp()
{
_downstreamReRouteKey = new DownstreamReRouteBuilder().Build();
_stringKey = "test";
_client = new HttpClientWrapper(new HttpClient());
_downstreamReRouteDictionary = new ConcurrentDictionary<DownstreamReRoute, IHttpClient>();
_downstreamReRouteDictionary.TryAdd(new DownstreamReRouteBuilder().Build(), new HttpClientWrapper(new HttpClient()));
_downstreamReRouteDictionary.TryAdd(new DownstreamReRouteBuilder().Build(), new HttpClientWrapper(new HttpClient()));
_downstreamReRouteDictionary.TryAdd(new DownstreamReRouteBuilder().Build(), new HttpClientWrapper(new HttpClient()));
_downstreamReRouteDictionary.TryAdd(new DownstreamReRouteBuilder().Build(), new HttpClientWrapper(new HttpClient()));
_downstreamReRouteDictionary.TryAdd(new DownstreamReRouteBuilder().Build(), new HttpClientWrapper(new HttpClient()));
_downstreamReRouteDictionary.TryAdd(new DownstreamReRouteBuilder().Build(), new HttpClientWrapper(new HttpClient()));
_downstreamReRouteDictionary.TryAdd(new DownstreamReRouteBuilder().Build(), new HttpClientWrapper(new HttpClient()));
_downstreamReRouteDictionary.TryAdd(new DownstreamReRouteBuilder().Build(), new HttpClientWrapper(new HttpClient()));
_downstreamReRouteDictionary.TryAdd(new DownstreamReRouteBuilder().Build(), new HttpClientWrapper(new HttpClient()));
_downstreamReRouteDictionary.TryAdd(new DownstreamReRouteBuilder().Build(), new HttpClientWrapper(new HttpClient()));
_stringReRouteDictionary = new ConcurrentDictionary<string, IHttpClient>();
_stringReRouteDictionary.TryAdd("1", new HttpClientWrapper(new HttpClient()));
_stringReRouteDictionary.TryAdd("2", new HttpClientWrapper(new HttpClient()));
_stringReRouteDictionary.TryAdd("3", new HttpClientWrapper(new HttpClient()));
_stringReRouteDictionary.TryAdd("4", new HttpClientWrapper(new HttpClient()));
_stringReRouteDictionary.TryAdd("5", new HttpClientWrapper(new HttpClient()));
_stringReRouteDictionary.TryAdd("6", new HttpClientWrapper(new HttpClient()));
_stringReRouteDictionary.TryAdd("7", new HttpClientWrapper(new HttpClient()));
_stringReRouteDictionary.TryAdd("8", new HttpClientWrapper(new HttpClient()));
_stringReRouteDictionary.TryAdd("9", new HttpClientWrapper(new HttpClient()));
_stringReRouteDictionary.TryAdd("10", new HttpClientWrapper(new HttpClient()));
}
[Benchmark(Baseline = true)]
public IHttpClient StringKey()
{
_stringReRouteDictionary.AddOrUpdate(_stringKey, _client, (k, oldValue) => _client);
return _stringReRouteDictionary.TryGetValue(_stringKey, out var client) ? client : null;
}
[Benchmark]
public IHttpClient DownstreamReRouteKey()
{
_downstreamReRouteDictionary.AddOrUpdate(_downstreamReRouteKey, _client, (k, oldValue) => _client);
return _downstreamReRouteDictionary.TryGetValue(_downstreamReRouteKey, out var client) ? client : null;
}
}
}
namespace Ocelot.Benchmarks
{
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Requester;
using System.Collections.Concurrent;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Columns;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Validators;
using System.Net.Http;
[Config(typeof(DictionaryBenchmarks))]
public class DictionaryBenchmarks : ManualConfig
{
private ConcurrentDictionary<DownstreamRoute, IHttpClient> _downstreamRouteDictionary;
private ConcurrentDictionary<string, IHttpClient> _stringRouteDictionary;
private HttpClientWrapper _client;
private string _stringKey;
private DownstreamRoute _downstreamRouteKey;
public DictionaryBenchmarks()
{
Add(StatisticColumn.AllStatistics);
Add(MemoryDiagnoser.Default);
Add(BaselineValidator.FailOnError);
}
[GlobalSetup]
public void SetUp()
{
_downstreamRouteKey = new DownstreamRouteBuilder().Build();
_stringKey = "test";
_client = new HttpClientWrapper(new HttpClient());
_downstreamRouteDictionary = new ConcurrentDictionary<DownstreamRoute, IHttpClient>();
_downstreamRouteDictionary.TryAdd(new DownstreamRouteBuilder().Build(), new HttpClientWrapper(new HttpClient()));
_downstreamRouteDictionary.TryAdd(new DownstreamRouteBuilder().Build(), new HttpClientWrapper(new HttpClient()));
_downstreamRouteDictionary.TryAdd(new DownstreamRouteBuilder().Build(), new HttpClientWrapper(new HttpClient()));
_downstreamRouteDictionary.TryAdd(new DownstreamRouteBuilder().Build(), new HttpClientWrapper(new HttpClient()));
_downstreamRouteDictionary.TryAdd(new DownstreamRouteBuilder().Build(), new HttpClientWrapper(new HttpClient()));
_downstreamRouteDictionary.TryAdd(new DownstreamRouteBuilder().Build(), new HttpClientWrapper(new HttpClient()));
_downstreamRouteDictionary.TryAdd(new DownstreamRouteBuilder().Build(), new HttpClientWrapper(new HttpClient()));
_downstreamRouteDictionary.TryAdd(new DownstreamRouteBuilder().Build(), new HttpClientWrapper(new HttpClient()));
_downstreamRouteDictionary.TryAdd(new DownstreamRouteBuilder().Build(), new HttpClientWrapper(new HttpClient()));
_downstreamRouteDictionary.TryAdd(new DownstreamRouteBuilder().Build(), new HttpClientWrapper(new HttpClient()));
_stringRouteDictionary = new ConcurrentDictionary<string, IHttpClient>();
_stringRouteDictionary.TryAdd("1", new HttpClientWrapper(new HttpClient()));
_stringRouteDictionary.TryAdd("2", new HttpClientWrapper(new HttpClient()));
_stringRouteDictionary.TryAdd("3", new HttpClientWrapper(new HttpClient()));
_stringRouteDictionary.TryAdd("4", new HttpClientWrapper(new HttpClient()));
_stringRouteDictionary.TryAdd("5", new HttpClientWrapper(new HttpClient()));
_stringRouteDictionary.TryAdd("6", new HttpClientWrapper(new HttpClient()));
_stringRouteDictionary.TryAdd("7", new HttpClientWrapper(new HttpClient()));
_stringRouteDictionary.TryAdd("8", new HttpClientWrapper(new HttpClient()));
_stringRouteDictionary.TryAdd("9", new HttpClientWrapper(new HttpClient()));
_stringRouteDictionary.TryAdd("10", new HttpClientWrapper(new HttpClient()));
}
[Benchmark(Baseline = true)]
public IHttpClient StringKey()
{
_stringRouteDictionary.AddOrUpdate(_stringKey, _client, (k, oldValue) => _client);
return _stringRouteDictionary.TryGetValue(_stringKey, out var client) ? client : null;
}
[Benchmark]
public IHttpClient DownstreamRouteKey()
{
_downstreamRouteDictionary.AddOrUpdate(_downstreamRouteKey, _client, (k, oldValue) => _client);
return _downstreamRouteDictionary.TryGetValue(_downstreamRouteKey, out var client) ? client : null;
}
}
}

View File

@ -55,7 +55,7 @@ namespace Ocelot.Benchmarks
httpContext.Request.Path = new PathString("/test");
httpContext.Request.QueryString = new QueryString("?a=b");
httpContext.Request.Headers.Add("Host", "most");
httpContext.Items.SetIInternalConfiguration(new InternalConfiguration(new List<ReRoute>(), null, null, null, null, null, null, null, null));
httpContext.Items.SetIInternalConfiguration(new InternalConfiguration(new List<Route>(), null, null, null, null, null, null, null, null));
_httpContext = httpContext;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,220 +1,220 @@
namespace Ocelot.IntegrationTests
{
using Configuration.File;
using DependencyInjection;
using global::CacheManager.Core;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Ocelot.Administration;
using Ocelot.Cache.CacheManager;
using Ocelot.Middleware;
using Shouldly;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using TestStack.BDDfy;
using Xunit;
public class CacheManagerTests : IDisposable
{
private HttpClient _httpClient;
private readonly HttpClient _httpClientTwo;
private HttpResponseMessage _response;
private IHost _builder;
private IHostBuilder _webHostBuilder;
private string _ocelotBaseUrl;
private BearerToken _token;
public CacheManagerTests()
{
_httpClient = new HttpClient();
_httpClientTwo = new HttpClient();
_ocelotBaseUrl = "http://localhost:5000";
_httpClient.BaseAddress = new Uri(_ocelotBaseUrl);
}
[Fact]
public void should_clear_region()
{
var initialConfiguration = new FileConfiguration
{
GlobalConfiguration = new FileGlobalConfiguration
{
},
ReRoutes = new List<FileReRoute>()
{
new FileReRoute()
{
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 80,
},
},
DownstreamScheme = "https",
DownstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "get" },
UpstreamPathTemplate = "/",
FileCacheOptions = new FileCacheOptions
{
TtlSeconds = 10,
},
},
new FileReRoute()
{
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 80,
},
},
DownstreamScheme = "https",
DownstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "get" },
UpstreamPathTemplate = "/test",
FileCacheOptions = new FileCacheOptions
{
TtlSeconds = 10,
},
},
},
};
var regionToClear = "gettest";
this.Given(x => GivenThereIsAConfiguration(initialConfiguration))
.And(x => GivenOcelotIsRunning())
.And(x => GivenIHaveAnOcelotToken("/administration"))
.And(x => GivenIHaveAddedATokenToMyRequest())
.When(x => WhenIDeleteOnTheApiGateway($"/administration/outputcache/{regionToClear}"))
.Then(x => ThenTheStatusCodeShouldBe(HttpStatusCode.NoContent))
.BDDfy();
}
private void GivenIHaveAddedATokenToMyRequest()
{
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _token.AccessToken);
}
private 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>("grant_type", "client_credentials"),
};
var content = new FormUrlEncodedContent(formData);
var response = _httpClient.PostAsync(tokenUrl, content).Result;
var responseContent = response.Content.ReadAsStringAsync().Result;
response.EnsureSuccessStatusCode();
_token = JsonConvert.DeserializeObject<BearerToken>(responseContent);
var configPath = $"{adminPath}/.well-known/openid-configuration";
response = _httpClient.GetAsync(configPath).Result;
response.EnsureSuccessStatusCode();
}
private void GivenOcelotIsRunning()
{
_webHostBuilder = Host.CreateDefaultBuilder()
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: false);
config.AddJsonFile("ocelot.json", false, false);
config.AddEnvironmentVariables();
})
.ConfigureServices(x =>
{
Action<ConfigurationBuilderCachePart> settings = (s) =>
{
s.WithMicrosoftLogging(log =>
{
//log.AddConsole(LogLevel.Debug);
})
.WithDictionaryHandle();
};
x.AddMvc(option => option.EnableEndpointRouting = false);
x.AddOcelot()
.AddCacheManager(settings)
.AddAdministration("/administration", "secret");
})
.ConfigureWebHost(webBuilder =>
{
webBuilder.UseUrls(_ocelotBaseUrl)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.Configure(app =>
{
app.UseOcelot().Wait();
});
});
_builder = _webHostBuilder.Build();
_builder.Start();
}
private void GivenThereIsAConfiguration(FileConfiguration fileConfiguration)
{
var configurationPath = $"{Directory.GetCurrentDirectory()}/ocelot.json";
var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration);
if (File.Exists(configurationPath))
{
File.Delete(configurationPath);
}
File.WriteAllText(configurationPath, jsonConfiguration);
var text = File.ReadAllText(configurationPath);
configurationPath = $"{AppContext.BaseDirectory}/ocelot.json";
if (File.Exists(configurationPath))
{
File.Delete(configurationPath);
}
File.WriteAllText(configurationPath, jsonConfiguration);
text = File.ReadAllText(configurationPath);
}
private void WhenIDeleteOnTheApiGateway(string url)
{
_response = _httpClient.DeleteAsync(url).Result;
}
private void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode)
{
_response.StatusCode.ShouldBe(expectedHttpStatusCode);
}
public void Dispose()
{
Environment.SetEnvironmentVariable("OCELOT_CERTIFICATE", "");
Environment.SetEnvironmentVariable("OCELOT_CERTIFICATE_PASSWORD", "");
_builder?.Dispose();
_httpClient?.Dispose();
//_identityServerBuilder?.Dispose();
}
}
}
namespace Ocelot.IntegrationTests
{
using Configuration.File;
using DependencyInjection;
using global::CacheManager.Core;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Ocelot.Administration;
using Ocelot.Cache.CacheManager;
using Ocelot.Middleware;
using Shouldly;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using TestStack.BDDfy;
using Xunit;
public class CacheManagerTests : IDisposable
{
private HttpClient _httpClient;
private readonly HttpClient _httpClientTwo;
private HttpResponseMessage _response;
private IHost _builder;
private IHostBuilder _webHostBuilder;
private string _ocelotBaseUrl;
private BearerToken _token;
public CacheManagerTests()
{
_httpClient = new HttpClient();
_httpClientTwo = new HttpClient();
_ocelotBaseUrl = "http://localhost:5000";
_httpClient.BaseAddress = new Uri(_ocelotBaseUrl);
}
[Fact]
public void should_clear_region()
{
var initialConfiguration = new FileConfiguration
{
GlobalConfiguration = new FileGlobalConfiguration
{
},
Routes = new List<FileRoute>()
{
new FileRoute()
{
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 80,
},
},
DownstreamScheme = "https",
DownstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "get" },
UpstreamPathTemplate = "/",
FileCacheOptions = new FileCacheOptions
{
TtlSeconds = 10,
},
},
new FileRoute()
{
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 80,
},
},
DownstreamScheme = "https",
DownstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "get" },
UpstreamPathTemplate = "/test",
FileCacheOptions = new FileCacheOptions
{
TtlSeconds = 10,
},
},
},
};
var regionToClear = "gettest";
this.Given(x => GivenThereIsAConfiguration(initialConfiguration))
.And(x => GivenOcelotIsRunning())
.And(x => GivenIHaveAnOcelotToken("/administration"))
.And(x => GivenIHaveAddedATokenToMyRequest())
.When(x => WhenIDeleteOnTheApiGateway($"/administration/outputcache/{regionToClear}"))
.Then(x => ThenTheStatusCodeShouldBe(HttpStatusCode.NoContent))
.BDDfy();
}
private void GivenIHaveAddedATokenToMyRequest()
{
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _token.AccessToken);
}
private 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>("grant_type", "client_credentials"),
};
var content = new FormUrlEncodedContent(formData);
var response = _httpClient.PostAsync(tokenUrl, content).Result;
var responseContent = response.Content.ReadAsStringAsync().Result;
response.EnsureSuccessStatusCode();
_token = JsonConvert.DeserializeObject<BearerToken>(responseContent);
var configPath = $"{adminPath}/.well-known/openid-configuration";
response = _httpClient.GetAsync(configPath).Result;
response.EnsureSuccessStatusCode();
}
private void GivenOcelotIsRunning()
{
_webHostBuilder = Host.CreateDefaultBuilder()
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: false);
config.AddJsonFile("ocelot.json", false, false);
config.AddEnvironmentVariables();
})
.ConfigureServices(x =>
{
Action<ConfigurationBuilderCachePart> settings = (s) =>
{
s.WithMicrosoftLogging(log =>
{
//log.AddConsole(LogLevel.Debug);
})
.WithDictionaryHandle();
};
x.AddMvc(option => option.EnableEndpointRouting = false);
x.AddOcelot()
.AddCacheManager(settings)
.AddAdministration("/administration", "secret");
})
.ConfigureWebHost(webBuilder =>
{
webBuilder.UseUrls(_ocelotBaseUrl)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.Configure(app =>
{
app.UseOcelot().Wait();
});
});
_builder = _webHostBuilder.Build();
_builder.Start();
}
private void GivenThereIsAConfiguration(FileConfiguration fileConfiguration)
{
var configurationPath = $"{Directory.GetCurrentDirectory()}/ocelot.json";
var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration);
if (File.Exists(configurationPath))
{
File.Delete(configurationPath);
}
File.WriteAllText(configurationPath, jsonConfiguration);
var text = File.ReadAllText(configurationPath);
configurationPath = $"{AppContext.BaseDirectory}/ocelot.json";
if (File.Exists(configurationPath))
{
File.Delete(configurationPath);
}
File.WriteAllText(configurationPath, jsonConfiguration);
text = File.ReadAllText(configurationPath);
}
private void WhenIDeleteOnTheApiGateway(string url)
{
_response = _httpClient.DeleteAsync(url).Result;
}
private void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode)
{
_response.StatusCode.ShouldBe(expectedHttpStatusCode);
}
public void Dispose()
{
Environment.SetEnvironmentVariable("OCELOT_CERTIFICATE", "");
Environment.SetEnvironmentVariable("OCELOT_CERTIFICATE_PASSWORD", "");
_builder?.Dispose();
_httpClient?.Dispose();
//_identityServerBuilder?.Dispose();
}
}
}

View File

@ -43,9 +43,9 @@ namespace Ocelot.IntegrationTests
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",

File diff suppressed because it is too large Load Diff

View File

@ -42,9 +42,9 @@ namespace Ocelot.IntegrationTests
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
Routes = new List<FileRoute>
{
new FileReRoute
new FileRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",

View File

@ -1,57 +1,57 @@
{
"ReRoutes": [
{
"DownstreamPathTemplate": "/",
"UpstreamPathTemplate": "/",
"UpstreamHttpMethod": "Get",
"AuthenticationOptions": {
"Provider": null,
"ProviderRootUrl": null,
"ApiName": null,
"RequireHttps": false,
"AllowedScopes": [],
"ApiSecret": null
},
"AddHeadersToRequest": {},
"AddClaimsToRequest": {},
"RouteClaimsRequirement": {},
"AddQueriesToRequest": {},
"RequestIdKey": null,
"FileCacheOptions": { "TtlSeconds": 0 },
"ReRouteIsCaseSensitive": false,
"ServiceName": null,
"DownstreamScheme": "http",
"DownstreamHost": "localhost",
"DownstreamPort": 51879,
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 0,
"DurationOfBreak": 0,
"TimeoutValue": 0
},
"LoadBalancer": null,
"RateLimitOptions": {
"ClientWhitelist": [],
"EnableRateLimiting": false,
"Period": null,
"PeriodTimespan": 0.0,
"Limit": 0
}
}
],
"GlobalConfiguration": {
"RequestIdKey": null,
"ServiceDiscoveryProvider": {
"Provider": null,
"Host": null,
"Port": 0
},
"AdministrationPath": null,
"RateLimitOptions": {
"ClientIdHeader": "ClientId",
"QuotaExceededMessage": null,
"RateLimitCounterPrefix": "ocelot",
"DisableRateLimitHeaders": false,
"HttpStatusCode": 429
}
}
}
{
"Routes": [
{
"DownstreamPathTemplate": "/",
"UpstreamPathTemplate": "/",
"UpstreamHttpMethod": "Get",
"AuthenticationOptions": {
"Provider": null,
"ProviderRootUrl": null,
"ApiName": null,
"RequireHttps": false,
"AllowedScopes": [],
"ApiSecret": null
},
"AddHeadersToRequest": {},
"AddClaimsToRequest": {},
"RouteClaimsRequirement": {},
"AddQueriesToRequest": {},
"RequestIdKey": null,
"FileCacheOptions": { "TtlSeconds": 0 },
"RouteIsCaseSensitive": false,
"ServiceName": null,
"DownstreamScheme": "http",
"DownstreamHost": "localhost",
"DownstreamPort": 51879,
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 0,
"DurationOfBreak": 0,
"TimeoutValue": 0
},
"LoadBalancer": null,
"RateLimitOptions": {
"ClientWhitelist": [],
"EnableRateLimiting": false,
"Period": null,
"PeriodTimespan": 0.0,
"Limit": 0
}
}
],
"GlobalConfiguration": {
"RequestIdKey": null,
"ServiceDiscoveryProvider": {
"Provider": null,
"Host": null,
"Port": 0
},
"AdministrationPath": null,
"RateLimitOptions": {
"ClientIdHeader": "ClientId",
"QuotaExceededMessage": null,
"RateLimitCounterPrefix": "ocelot",
"DisableRateLimitHeaders": false,
"HttpStatusCode": 429
}
}
}

View File

@ -1,345 +1,345 @@
{
"ReRoutes": [
{
"DownstreamPathTemplate": "/profile",
"DownstreamScheme": "http",
"UpstreamPathTemplate": "/profile",
"UpstreamHttpMethod": [ "Get" ],
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5001
}
],
"QoSOptions": {
"TimeoutValue": 360000
}
},
{
"DownstreamPathTemplate": "/api/v1/todo/",
"DownstreamScheme": "http",
"UpstreamPathTemplate": "/api/v1/todo/",
"UpstreamHttpMethod": [ "Get", "Post" ],
"DownstreamHostAndPorts": [
{
"Host": "lxtodo.azurewebsites.net",
"Port": 80
}
],
"DownstreamHeaderTransform": {
"Location": "{DownstreamBaseUrl}, {BaseUrl}"
}
},
{
"DownstreamPathTemplate": "/api/values",
"DownstreamScheme": "https",
"UpstreamPathTemplate": "/api/values",
"UpstreamHttpMethod": [ "Get" ],
"DownstreamHostAndPorts": [
{
"Host": "testapivalues.azurewebsites.net",
"Port": 443
}
]
},
{
"DownstreamPathTemplate": "/",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 52876
}
],
"UpstreamPathTemplate": "/identityserverexample",
"UpstreamHttpMethod": [ "Get" ],
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
},
"AuthenticationOptions": {
"AuthenticationProviderKey": "TestKey",
"AllowedScopes": [
"openid",
"offline_access"
]
},
"AddHeadersToRequest": {
"CustomerId": "Claims[CustomerId] > value",
"LocationId": "Claims[LocationId] > value",
"UserType": "Claims[sub] > value[0] > |",
"UserId": "Claims[sub] > value[1] > |"
},
"AddClaimsToRequest": {
"CustomerId": "Claims[CustomerId] > value",
"LocationId": "Claims[LocationId] > value",
"UserType": "Claims[sub] > value[0] > |",
"UserId": "Claims[sub] > value[1] > |"
},
"AddQueriesToRequest": {
"CustomerId": "Claims[CustomerId] > value",
"LocationId": "Claims[LocationId] > value",
"UserType": "Claims[sub] > value[0] > |",
"UserId": "Claims[sub] > value[1] > |"
},
"RouteClaimsRequirement": {
"UserType": "registered"
},
"RequestIdKey": "OcRequestId"
},
{
"DownstreamPathTemplate": "/posts",
"DownstreamScheme": "https",
"DownstreamHostAndPorts": [
{
"Host": "jsonplaceholder.typicode.com",
"Port": 443
}
],
"UpstreamPathTemplate": "/posts",
"UpstreamHttpMethod": [ "Get" ],
"HttpHandlerOptions": {
"AllowAutoRedirect": true,
"UseCookieContainer": true
},
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
},
{
"DownstreamPathTemplate": "/posts/{postId}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "jsonplaceholder.typicode.com",
"Port": 80
}
],
"UpstreamPathTemplate": "/posts/{postId}",
"UpstreamHttpMethod": [ "Get" ],
"RequestIdKey": "ReRouteRequestId",
"HttpHandlerOptions": {
"AllowAutoRedirect": true,
"UseCookieContainer": true,
"UseTracing": true,
"UseProxy": true
},
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
},
{
"DownstreamPathTemplate": "/posts/{postId}/comments",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "jsonplaceholder.typicode.com",
"Port": 80
}
],
"UpstreamPathTemplate": "/posts/{postId}/comments",
"UpstreamHttpMethod": [ "Get" ],
"HttpHandlerOptions": {
"AllowAutoRedirect": true,
"UseCookieContainer": true,
"UseTracing": false
},
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
},
{
"DownstreamPathTemplate": "/comments",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "jsonplaceholder.typicode.com",
"Port": 80
}
],
"UpstreamPathTemplate": "/comments",
"UpstreamHttpMethod": [ "Get" ],
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
},
{
"DownstreamPathTemplate": "/posts",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "jsonplaceholder.typicode.com",
"Port": 80
}
],
"UpstreamPathTemplate": "/posts",
"UpstreamHttpMethod": [ "Post" ],
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
},
{
"DownstreamPathTemplate": "/posts/{postId}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "jsonplaceholder.typicode.com",
"Port": 80
}
],
"UpstreamPathTemplate": "/posts/{postId}",
"UpstreamHttpMethod": [ "Put" ],
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
},
{
"DownstreamPathTemplate": "/posts/{postId}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "jsonplaceholder.typicode.com",
"Port": 80
}
],
"UpstreamPathTemplate": "/posts/{postId}",
"UpstreamHttpMethod": [ "Patch" ],
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
},
{
"DownstreamPathTemplate": "/posts/{postId}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "jsonplaceholder.typicode.com",
"Port": 80
}
],
"UpstreamPathTemplate": "/posts/{postId}",
"UpstreamHttpMethod": [ "Delete" ],
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
},
{
"DownstreamPathTemplate": "/api/products",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "jsonplaceholder.typicode.com",
"Port": 80
}
],
"UpstreamPathTemplate": "/products",
"UpstreamHttpMethod": [ "Get" ],
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
},
"FileCacheOptions": { "TtlSeconds": 15 }
},
{
"DownstreamPathTemplate": "/api/products/{productId}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "jsonplaceholder.typicode.com",
"Port": 80
}
],
"UpstreamPathTemplate": "/products/{productId}",
"UpstreamHttpMethod": [ "Get" ],
"FileCacheOptions": { "TtlSeconds": 15 }
},
{
"DownstreamPathTemplate": "/api/products",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "jsonplaceholder.typicode.com",
"Port": 80
}
],
"UpstreamPathTemplate": "/products",
"UpstreamHttpMethod": [ "Post" ],
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
},
{
"DownstreamPathTemplate": "/api/products/{productId}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "jsonplaceholder.typicode.com",
"Port": 80
}
],
"UpstreamPathTemplate": "/products/{productId}",
"UpstreamHttpMethod": [ "Put" ],
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
},
"FileCacheOptions": { "TtlSeconds": 15 }
},
{
"DownstreamPathTemplate": "/posts",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "jsonplaceholder.typicode.com",
"Port": 80
}
],
"UpstreamPathTemplate": "/posts/",
"UpstreamHttpMethod": [ "Get" ],
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
},
"FileCacheOptions": { "TtlSeconds": 15 }
},
{
"DownstreamPathTemplate": "/",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "www.bbc.co.uk",
"Port": 80
}
],
"UpstreamPathTemplate": "/bbc/",
"UpstreamHttpMethod": [ "Get" ]
}
],
"GlobalConfiguration": {
"RequestIdKey": "ot-traceid"
}
}
{
"Routes": [
{
"DownstreamPathTemplate": "/profile",
"DownstreamScheme": "http",
"UpstreamPathTemplate": "/profile",
"UpstreamHttpMethod": [ "Get" ],
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5001
}
],
"QoSOptions": {
"TimeoutValue": 360000
}
},
{
"DownstreamPathTemplate": "/api/v1/todo/",
"DownstreamScheme": "http",
"UpstreamPathTemplate": "/api/v1/todo/",
"UpstreamHttpMethod": [ "Get", "Post" ],
"DownstreamHostAndPorts": [
{
"Host": "lxtodo.azurewebsites.net",
"Port": 80
}
],
"DownstreamHeaderTransform": {
"Location": "{DownstreamBaseUrl}, {BaseUrl}"
}
},
{
"DownstreamPathTemplate": "/api/values",
"DownstreamScheme": "https",
"UpstreamPathTemplate": "/api/values",
"UpstreamHttpMethod": [ "Get" ],
"DownstreamHostAndPorts": [
{
"Host": "testapivalues.azurewebsites.net",
"Port": 443
}
]
},
{
"DownstreamPathTemplate": "/",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 52876
}
],
"UpstreamPathTemplate": "/identityserverexample",
"UpstreamHttpMethod": [ "Get" ],
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
},
"AuthenticationOptions": {
"AuthenticationProviderKey": "TestKey",
"AllowedScopes": [
"openid",
"offline_access"
]
},
"AddHeadersToRequest": {
"CustomerId": "Claims[CustomerId] > value",
"LocationId": "Claims[LocationId] > value",
"UserType": "Claims[sub] > value[0] > |",
"UserId": "Claims[sub] > value[1] > |"
},
"AddClaimsToRequest": {
"CustomerId": "Claims[CustomerId] > value",
"LocationId": "Claims[LocationId] > value",
"UserType": "Claims[sub] > value[0] > |",
"UserId": "Claims[sub] > value[1] > |"
},
"AddQueriesToRequest": {
"CustomerId": "Claims[CustomerId] > value",
"LocationId": "Claims[LocationId] > value",
"UserType": "Claims[sub] > value[0] > |",
"UserId": "Claims[sub] > value[1] > |"
},
"RouteClaimsRequirement": {
"UserType": "registered"
},
"RequestIdKey": "OcRequestId"
},
{
"DownstreamPathTemplate": "/posts",
"DownstreamScheme": "https",
"DownstreamHostAndPorts": [
{
"Host": "jsonplaceholder.typicode.com",
"Port": 443
}
],
"UpstreamPathTemplate": "/posts",
"UpstreamHttpMethod": [ "Get" ],
"HttpHandlerOptions": {
"AllowAutoRedirect": true,
"UseCookieContainer": true
},
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
},
{
"DownstreamPathTemplate": "/posts/{postId}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "jsonplaceholder.typicode.com",
"Port": 80
}
],
"UpstreamPathTemplate": "/posts/{postId}",
"UpstreamHttpMethod": [ "Get" ],
"RequestIdKey": "RouteRequestId",
"HttpHandlerOptions": {
"AllowAutoRedirect": true,
"UseCookieContainer": true,
"UseTracing": true,
"UseProxy": true
},
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
},
{
"DownstreamPathTemplate": "/posts/{postId}/comments",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "jsonplaceholder.typicode.com",
"Port": 80
}
],
"UpstreamPathTemplate": "/posts/{postId}/comments",
"UpstreamHttpMethod": [ "Get" ],
"HttpHandlerOptions": {
"AllowAutoRedirect": true,
"UseCookieContainer": true,
"UseTracing": false
},
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
},
{
"DownstreamPathTemplate": "/comments",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "jsonplaceholder.typicode.com",
"Port": 80
}
],
"UpstreamPathTemplate": "/comments",
"UpstreamHttpMethod": [ "Get" ],
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
},
{
"DownstreamPathTemplate": "/posts",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "jsonplaceholder.typicode.com",
"Port": 80
}
],
"UpstreamPathTemplate": "/posts",
"UpstreamHttpMethod": [ "Post" ],
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
},
{
"DownstreamPathTemplate": "/posts/{postId}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "jsonplaceholder.typicode.com",
"Port": 80
}
],
"UpstreamPathTemplate": "/posts/{postId}",
"UpstreamHttpMethod": [ "Put" ],
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
},
{
"DownstreamPathTemplate": "/posts/{postId}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "jsonplaceholder.typicode.com",
"Port": 80
}
],
"UpstreamPathTemplate": "/posts/{postId}",
"UpstreamHttpMethod": [ "Patch" ],
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
},
{
"DownstreamPathTemplate": "/posts/{postId}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "jsonplaceholder.typicode.com",
"Port": 80
}
],
"UpstreamPathTemplate": "/posts/{postId}",
"UpstreamHttpMethod": [ "Delete" ],
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
},
{
"DownstreamPathTemplate": "/api/products",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "jsonplaceholder.typicode.com",
"Port": 80
}
],
"UpstreamPathTemplate": "/products",
"UpstreamHttpMethod": [ "Get" ],
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
},
"FileCacheOptions": { "TtlSeconds": 15 }
},
{
"DownstreamPathTemplate": "/api/products/{productId}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "jsonplaceholder.typicode.com",
"Port": 80
}
],
"UpstreamPathTemplate": "/products/{productId}",
"UpstreamHttpMethod": [ "Get" ],
"FileCacheOptions": { "TtlSeconds": 15 }
},
{
"DownstreamPathTemplate": "/api/products",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "jsonplaceholder.typicode.com",
"Port": 80
}
],
"UpstreamPathTemplate": "/products",
"UpstreamHttpMethod": [ "Post" ],
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
}
},
{
"DownstreamPathTemplate": "/api/products/{productId}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "jsonplaceholder.typicode.com",
"Port": 80
}
],
"UpstreamPathTemplate": "/products/{productId}",
"UpstreamHttpMethod": [ "Put" ],
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
},
"FileCacheOptions": { "TtlSeconds": 15 }
},
{
"DownstreamPathTemplate": "/posts",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "jsonplaceholder.typicode.com",
"Port": 80
}
],
"UpstreamPathTemplate": "/posts/",
"UpstreamHttpMethod": [ "Get" ],
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10,
"TimeoutValue": 5000
},
"FileCacheOptions": { "TtlSeconds": 15 }
},
{
"DownstreamPathTemplate": "/",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "www.bbc.co.uk",
"Port": 80
}
],
"UpstreamPathTemplate": "/bbc/",
"UpstreamHttpMethod": [ "Get" ]
}
],
"GlobalConfiguration": {
"RequestIdKey": "ot-traceid"
}
}

View File

@ -1,119 +1,119 @@
using Xunit;
[assembly: CollectionBehavior(DisableTestParallelization = true)]
namespace Ocelot.UnitTests.Authentication
{
using Microsoft.AspNetCore.Http;
using Moq;
using Ocelot.Authentication.Middleware;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Logging;
using Ocelot.Middleware;
using Shouldly;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Ocelot.Infrastructure.RequestData;
using TestStack.BDDfy;
using Xunit;
[assembly: CollectionBehavior(DisableTestParallelization = true)]
namespace Ocelot.UnitTests.Authentication
{
using Microsoft.AspNetCore.Http;
using Moq;
using Ocelot.Authentication.Middleware;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Logging;
using Ocelot.Middleware;
using Shouldly;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Ocelot.Infrastructure.RequestData;
using TestStack.BDDfy;
using Xunit;
using Ocelot.DownstreamRouteFinder.Middleware;
public class AuthenticationMiddlewareTests
{
private AuthenticationMiddleware _middleware;
private readonly Mock<IOcelotLoggerFactory> _factory;
private Mock<IOcelotLogger> _logger;
private RequestDelegate _next;
private HttpContext _httpContext;
private Mock<IRequestScopedDataRepository> _repo;
public AuthenticationMiddlewareTests()
{
_repo = new Mock<IRequestScopedDataRepository>();
_httpContext = new DefaultHttpContext();
_factory = new Mock<IOcelotLoggerFactory>();
_logger = new Mock<IOcelotLogger>();
_factory.Setup(x => x.CreateLogger<AuthenticationMiddleware>()).Returns(_logger.Object);
}
[Fact]
public void should_call_next_middleware_if_route_is_not_authenticated()
{
this.Given(x => GivenTheDownStreamRouteIs(
new DownstreamReRouteBuilder().WithUpstreamHttpMethod(new List<string> { "Get" }).Build()))
.And(x => GivenTheTestServerPipelineIsConfigured())
.When(x => WhenICallTheMiddleware())
.Then(x => ThenTheUserIsAuthenticated())
.BDDfy();
}
[Fact]
public void should_call_next_middleware_if_route_is_using_options_method()
{
this.Given(x => GivenTheDownStreamRouteIs(
new DownstreamReRouteBuilder()
.WithUpstreamHttpMethod(new List<string> { "Options" })
.WithIsAuthenticated(true)
.Build()))
.And(x => GivenTheRequestIsUsingOptionsMethod())
.When(x => WhenICallTheMiddleware())
.Then(x => ThenTheUserIsAuthenticated())
.BDDfy();
}
private void WhenICallTheMiddleware()
{
_next = (context) =>
{
byte[] byteArray = Encoding.ASCII.GetBytes("The user is authenticated");
var stream = new MemoryStream(byteArray);
_httpContext.Response.Body = stream;
return Task.CompletedTask;
};
_middleware = new AuthenticationMiddleware(_next, _factory.Object);
_middleware.Invoke(_httpContext).GetAwaiter().GetResult();
}
private void GivenTheTestServerPipelineIsConfigured()
{
_next = (context) =>
{
byte[] byteArray = Encoding.ASCII.GetBytes("The user is authenticated");
var stream = new MemoryStream(byteArray);
_httpContext.Response.Body = stream;
return Task.CompletedTask;
};
}
private void GivenTheRequestIsUsingOptionsMethod()
{
_httpContext.Request.Method = "OPTIONS";
}
private void ThenTheUserIsAuthenticated()
{
var content = _httpContext.Response.Body.AsString();
content.ShouldBe("The user is authenticated");
}
private void GivenTheDownStreamRouteIs(DownstreamReRoute downstreamRoute)
public class AuthenticationMiddlewareTests
{
private AuthenticationMiddleware _middleware;
private readonly Mock<IOcelotLoggerFactory> _factory;
private Mock<IOcelotLogger> _logger;
private RequestDelegate _next;
private HttpContext _httpContext;
private Mock<IRequestScopedDataRepository> _repo;
public AuthenticationMiddlewareTests()
{
_httpContext.Items.UpsertDownstreamReRoute(downstreamRoute);
}
}
public static class StreamExtensions
{
public static string AsString(this Stream stream)
{
using (var reader = new StreamReader(stream))
{
string text = reader.ReadToEnd();
return text;
}
}
}
}
_repo = new Mock<IRequestScopedDataRepository>();
_httpContext = new DefaultHttpContext();
_factory = new Mock<IOcelotLoggerFactory>();
_logger = new Mock<IOcelotLogger>();
_factory.Setup(x => x.CreateLogger<AuthenticationMiddleware>()).Returns(_logger.Object);
}
[Fact]
public void should_call_next_middleware_if_route_is_not_authenticated()
{
this.Given(x => GivenTheDownStreamRouteIs(
new DownstreamRouteBuilder().WithUpstreamHttpMethod(new List<string> { "Get" }).Build()))
.And(x => GivenTheTestServerPipelineIsConfigured())
.When(x => WhenICallTheMiddleware())
.Then(x => ThenTheUserIsAuthenticated())
.BDDfy();
}
[Fact]
public void should_call_next_middleware_if_route_is_using_options_method()
{
this.Given(x => GivenTheDownStreamRouteIs(
new DownstreamRouteBuilder()
.WithUpstreamHttpMethod(new List<string> { "Options" })
.WithIsAuthenticated(true)
.Build()))
.And(x => GivenTheRequestIsUsingOptionsMethod())
.When(x => WhenICallTheMiddleware())
.Then(x => ThenTheUserIsAuthenticated())
.BDDfy();
}
private void WhenICallTheMiddleware()
{
_next = (context) =>
{
byte[] byteArray = Encoding.ASCII.GetBytes("The user is authenticated");
var stream = new MemoryStream(byteArray);
_httpContext.Response.Body = stream;
return Task.CompletedTask;
};
_middleware = new AuthenticationMiddleware(_next, _factory.Object);
_middleware.Invoke(_httpContext).GetAwaiter().GetResult();
}
private void GivenTheTestServerPipelineIsConfigured()
{
_next = (context) =>
{
byte[] byteArray = Encoding.ASCII.GetBytes("The user is authenticated");
var stream = new MemoryStream(byteArray);
_httpContext.Response.Body = stream;
return Task.CompletedTask;
};
}
private void GivenTheRequestIsUsingOptionsMethod()
{
_httpContext.Request.Method = "OPTIONS";
}
private void ThenTheUserIsAuthenticated()
{
var content = _httpContext.Response.Body.AsString();
content.ShouldBe("The user is authenticated");
}
private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute)
{
_httpContext.Items.UpsertDownstreamRoute(downstreamRoute);
}
}
public static class StreamExtensions
{
public static string AsString(this Stream stream)
{
using (var reader = new StreamReader(stream))
{
string text = reader.ReadToEnd();
return text;
}
}
}
}

View File

@ -44,7 +44,7 @@ namespace Ocelot.UnitTests.Authorization
public void should_call_authorisation_service()
{
this.Given(x => x.GivenTheDownStreamRouteIs(new List<PlaceholderNameAndValue>(),
new DownstreamReRouteBuilder()
new DownstreamRouteBuilder()
.WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().Build())
.WithIsAuthorised(true)
.WithUpstreamHttpMethod(new List<string> { "Get" })
@ -60,10 +60,10 @@ namespace Ocelot.UnitTests.Authorization
_middleware.Invoke(_httpContext).GetAwaiter().GetResult();
}
private void GivenTheDownStreamRouteIs(List<PlaceholderNameAndValue> templatePlaceholderNameAndValues, DownstreamReRoute downstreamReRoute)
private void GivenTheDownStreamRouteIs(List<PlaceholderNameAndValue> templatePlaceholderNameAndValues, DownstreamRoute downstreamRoute)
{
_httpContext.Items.UpsertTemplatePlaceholderNameAndValues(templatePlaceholderNameAndValues);
_httpContext.Items.UpsertDownstreamReRoute(downstreamReRoute);
_httpContext.Items.UpsertDownstreamRoute(downstreamRoute);
}
private void GivenTheAuthServiceReturns(Response<bool> expected)

View File

@ -1,144 +1,144 @@
namespace Ocelot.UnitTests.Cache
{
using Microsoft.AspNetCore.Http;
using Moq;
using Ocelot.Cache;
using Ocelot.Cache.Middleware;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.DownstreamRouteFinder;
using Ocelot.DownstreamRouteFinder.UrlMatcher;
using Ocelot.Logging;
using Ocelot.Middleware;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Ocelot.Infrastructure.RequestData;
using TestStack.BDDfy;
namespace Ocelot.UnitTests.Cache
{
using Microsoft.AspNetCore.Http;
using Moq;
using Ocelot.Cache;
using Ocelot.Cache.Middleware;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.DownstreamRouteFinder;
using Ocelot.DownstreamRouteFinder.UrlMatcher;
using Ocelot.Logging;
using Ocelot.Middleware;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Ocelot.Infrastructure.RequestData;
using TestStack.BDDfy;
using Xunit;
using Ocelot.DownstreamRouteFinder.Middleware;
public class OutputCacheMiddlewareTests
{
private readonly Mock<IOcelotCache<CachedResponse>> _cache;
private readonly Mock<IOcelotLoggerFactory> _loggerFactory;
private Mock<IOcelotLogger> _logger;
private OutputCacheMiddleware _middleware;
private readonly RequestDelegate _next;
private readonly ICacheKeyGenerator _cacheKeyGenerator;
private CachedResponse _response;
private HttpContext _httpContext;
private Mock<IRequestScopedDataRepository> _repo;
public OutputCacheMiddlewareTests()
{
_repo = new Mock<IRequestScopedDataRepository>();
_httpContext = new DefaultHttpContext();
_cache = new Mock<IOcelotCache<CachedResponse>>();
_loggerFactory = new Mock<IOcelotLoggerFactory>();
_logger = new Mock<IOcelotLogger>();
_cacheKeyGenerator = new CacheKeyGenerator();
_loggerFactory.Setup(x => x.CreateLogger<OutputCacheMiddleware>()).Returns(_logger.Object);
_next = context => Task.CompletedTask;
_httpContext.Items.UpsertDownstreamRequest(new Ocelot.Request.Middleware.DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "https://some.url/blah?abcd=123")));
}
[Fact]
public void should_returned_cached_item_when_it_is_in_cache()
{
var headers = new Dictionary<string, IEnumerable<string>>
{
{ "test", new List<string> { "test" } }
};
var contentHeaders = new Dictionary<string, IEnumerable<string>>
{
{ "content-type", new List<string> { "application/json" } }
};
var cachedResponse = new CachedResponse(HttpStatusCode.OK, headers, "", contentHeaders, "some reason");
this.Given(x => x.GivenThereIsACachedResponse(cachedResponse))
.And(x => x.GivenTheDownstreamRouteIs())
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheCacheGetIsCalledCorrectly())
.BDDfy();
}
[Fact]
public void should_returned_cached_item_when_it_is_in_cache_expires_header()
{
var contentHeaders = new Dictionary<string, IEnumerable<string>>
{
{ "Expires", new List<string> { "-1" } }
};
var cachedResponse = new CachedResponse(HttpStatusCode.OK, new Dictionary<string, IEnumerable<string>>(), "", contentHeaders, "some reason");
this.Given(x => x.GivenThereIsACachedResponse(cachedResponse))
.And(x => x.GivenTheDownstreamRouteIs())
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheCacheGetIsCalledCorrectly())
.BDDfy();
}
[Fact]
public void should_continue_with_pipeline_and_cache_response()
{
this.Given(x => x.GivenResponseIsNotCached(new HttpResponseMessage()))
.And(x => x.GivenTheDownstreamRouteIs())
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheCacheAddIsCalledCorrectly())
.BDDfy();
}
private void WhenICallTheMiddleware()
{
_middleware = new OutputCacheMiddleware(_next, _loggerFactory.Object, _cache.Object, _cacheKeyGenerator);
_middleware.Invoke(_httpContext).GetAwaiter().GetResult();
}
private void GivenThereIsACachedResponse(CachedResponse response)
{
_response = response;
_cache
.Setup(x => x.Get(It.IsAny<string>(), It.IsAny<string>()))
.Returns(_response);
}
private void GivenResponseIsNotCached(HttpResponseMessage responseMessage)
public class OutputCacheMiddlewareTests
{
private readonly Mock<IOcelotCache<CachedResponse>> _cache;
private readonly Mock<IOcelotLoggerFactory> _loggerFactory;
private Mock<IOcelotLogger> _logger;
private OutputCacheMiddleware _middleware;
private readonly RequestDelegate _next;
private readonly ICacheKeyGenerator _cacheKeyGenerator;
private CachedResponse _response;
private HttpContext _httpContext;
private Mock<IRequestScopedDataRepository> _repo;
public OutputCacheMiddlewareTests()
{
_httpContext.Items.UpsertDownstreamResponse(new DownstreamResponse(responseMessage));
}
private void GivenTheDownstreamRouteIs()
{
var reRoute = new ReRouteBuilder()
.WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithIsCached(true)
.WithCacheOptions(new CacheOptions(100, "kanken"))
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build();
var downstreamRoute = new DownstreamRoute(new List<PlaceholderNameAndValue>(), reRoute);
_repo = new Mock<IRequestScopedDataRepository>();
_httpContext = new DefaultHttpContext();
_cache = new Mock<IOcelotCache<CachedResponse>>();
_loggerFactory = new Mock<IOcelotLoggerFactory>();
_logger = new Mock<IOcelotLogger>();
_cacheKeyGenerator = new CacheKeyGenerator();
_loggerFactory.Setup(x => x.CreateLogger<OutputCacheMiddleware>()).Returns(_logger.Object);
_next = context => Task.CompletedTask;
_httpContext.Items.UpsertDownstreamRequest(new Ocelot.Request.Middleware.DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "https://some.url/blah?abcd=123")));
}
[Fact]
public void should_returned_cached_item_when_it_is_in_cache()
{
var headers = new Dictionary<string, IEnumerable<string>>
{
{ "test", new List<string> { "test" } }
};
var contentHeaders = new Dictionary<string, IEnumerable<string>>
{
{ "content-type", new List<string> { "application/json" } }
};
var cachedResponse = new CachedResponse(HttpStatusCode.OK, headers, "", contentHeaders, "some reason");
this.Given(x => x.GivenThereIsACachedResponse(cachedResponse))
.And(x => x.GivenTheDownstreamRouteIs())
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheCacheGetIsCalledCorrectly())
.BDDfy();
}
[Fact]
public void should_returned_cached_item_when_it_is_in_cache_expires_header()
{
var contentHeaders = new Dictionary<string, IEnumerable<string>>
{
{ "Expires", new List<string> { "-1" } }
};
var cachedResponse = new CachedResponse(HttpStatusCode.OK, new Dictionary<string, IEnumerable<string>>(), "", contentHeaders, "some reason");
this.Given(x => x.GivenThereIsACachedResponse(cachedResponse))
.And(x => x.GivenTheDownstreamRouteIs())
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheCacheGetIsCalledCorrectly())
.BDDfy();
}
[Fact]
public void should_continue_with_pipeline_and_cache_response()
{
this.Given(x => x.GivenResponseIsNotCached(new HttpResponseMessage()))
.And(x => x.GivenTheDownstreamRouteIs())
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheCacheAddIsCalledCorrectly())
.BDDfy();
}
private void WhenICallTheMiddleware()
{
_middleware = new OutputCacheMiddleware(_next, _loggerFactory.Object, _cache.Object, _cacheKeyGenerator);
_middleware.Invoke(_httpContext).GetAwaiter().GetResult();
}
private void GivenThereIsACachedResponse(CachedResponse response)
{
_response = response;
_cache
.Setup(x => x.Get(It.IsAny<string>(), It.IsAny<string>()))
.Returns(_response);
}
private void GivenResponseIsNotCached(HttpResponseMessage responseMessage)
{
_httpContext.Items.UpsertDownstreamResponse(new DownstreamResponse(responseMessage));
}
private void GivenTheDownstreamRouteIs()
{
var route = new RouteBuilder()
.WithDownstreamRoute(new DownstreamRouteBuilder()
.WithIsCached(true)
.WithCacheOptions(new CacheOptions(100, "kanken"))
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build();
var downstreamRoute = new Ocelot.DownstreamRouteFinder.DownstreamRouteHolder(new List<PlaceholderNameAndValue>(), route);
_httpContext.Items.UpsertTemplatePlaceholderNameAndValues(downstreamRoute.TemplatePlaceholderNameAndValues);
_httpContext.Items.UpsertDownstreamReRoute(downstreamRoute.ReRoute.DownstreamReRoute[0]);
}
private void ThenTheCacheGetIsCalledCorrectly()
{
_cache
.Verify(x => x.Get(It.IsAny<string>(), It.IsAny<string>()), Times.Once);
}
private void ThenTheCacheAddIsCalledCorrectly()
{
_cache
.Verify(x => x.Add(It.IsAny<string>(), It.IsAny<CachedResponse>(), It.IsAny<TimeSpan>(), It.IsAny<string>()), Times.Once);
}
}
}
_httpContext.Items.UpsertDownstreamRoute(downstreamRoute.Route.DownstreamRoute[0]);
}
private void ThenTheCacheGetIsCalledCorrectly()
{
_cache
.Verify(x => x.Get(It.IsAny<string>(), It.IsAny<string>()), Times.Once);
}
private void ThenTheCacheAddIsCalledCorrectly()
{
_cache
.Verify(x => x.Add(It.IsAny<string>(), It.IsAny<CachedResponse>(), It.IsAny<TimeSpan>(), It.IsAny<string>()), Times.Once);
}
}
}

View File

@ -10,18 +10,18 @@ namespace Ocelot.UnitTests.Cache
public class RegionCreatorTests
{
private string _result;
private FileReRoute _reRoute;
private FileRoute _route;
[Fact]
public void should_create_region()
{
var reRoute = new FileReRoute
var route = new FileRoute
{
UpstreamHttpMethod = new List<string> { "Get" },
UpstreamPathTemplate = "/testdummy"
};
this.Given(_ => GivenTheReRoute(reRoute))
this.Given(_ => GivenTheRoute(route))
.When(_ => WhenICreateTheRegion())
.Then(_ => ThenTheRegionIs("Gettestdummy"))
.BDDfy();
@ -30,7 +30,7 @@ namespace Ocelot.UnitTests.Cache
[Fact]
public void should_use_region()
{
var reRoute = new FileReRoute
var route = new FileRoute
{
FileCacheOptions = new FileCacheOptions
{
@ -38,21 +38,21 @@ namespace Ocelot.UnitTests.Cache
}
};
this.Given(_ => GivenTheReRoute(reRoute))
this.Given(_ => GivenTheRoute(route))
.When(_ => WhenICreateTheRegion())
.Then(_ => ThenTheRegionIs("region"))
.BDDfy();
}
private void GivenTheReRoute(FileReRoute reRoute)
}
private void GivenTheRoute(FileRoute route)
{
_reRoute = reRoute;
_route = route;
}
private void WhenICreateTheRegion()
{
{
RegionCreator regionCreator = new RegionCreator();
_result = regionCreator.Create(_reRoute);
_result = regionCreator.Create(_route);
}
private void ThenTheRegionIs(string expected)
@ -60,4 +60,4 @@ namespace Ocelot.UnitTests.Cache
_result.ShouldBe(expected);
}
}
}
}

View File

@ -7,8 +7,8 @@
using Ocelot.Cache.CacheManager;
using Ocelot.Cache.Middleware;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.DownstreamRouteFinder.Middleware;
using Ocelot.Configuration.Builder;
using Ocelot.DownstreamRouteFinder.Middleware;
using Ocelot.Logging;
using Ocelot.Middleware;
using Shouldly;
@ -42,7 +42,7 @@
x.WithDictionaryHandle();
});
_cacheManager = new OcelotCacheManagerCache<CachedResponse>(cacheManagerOutputCache);
_cacheKeyGenerator = new CacheKeyGenerator();
_cacheKeyGenerator = new CacheKeyGenerator();
_httpContext.Items.UpsertDownstreamRequest(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, _cacheKeyGenerator);
@ -85,13 +85,13 @@
private void GivenTheDownstreamRouteIs()
{
var reRoute = new DownstreamReRouteBuilder()
var route = new DownstreamRouteBuilder()
.WithIsCached(true)
.WithCacheOptions(new CacheOptions(100, "kanken"))
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build();
_httpContext.Items.UpsertDownstreamReRoute(reRoute);
.Build();
_httpContext.Items.UpsertDownstreamRoute(route);
}
}
}

View File

@ -1,91 +1,91 @@
using Ocelot.Middleware;
namespace Ocelot.UnitTests.Claims
{
using Microsoft.AspNetCore.Http;
using Moq;
using Ocelot.Claims;
using Ocelot.Claims.Middleware;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Middleware;
namespace Ocelot.UnitTests.Claims
{
using Microsoft.AspNetCore.Http;
using Moq;
using Ocelot.Claims;
using Ocelot.Claims.Middleware;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.DownstreamRouteFinder;
using Ocelot.DownstreamRouteFinder.Middleware;
using Ocelot.DownstreamRouteFinder.UrlMatcher;
using Ocelot.Logging;
using Ocelot.Responses;
using System.Collections.Generic;
using System.Threading.Tasks;
using TestStack.BDDfy;
using Xunit;
public class ClaimsToClaimsMiddlewareTests
{
private readonly Mock<IAddClaimsToRequest> _addHeaders;
private Mock<IOcelotLoggerFactory> _loggerFactory;
private Mock<IOcelotLogger> _logger;
private readonly ClaimsToClaimsMiddleware _middleware;
private RequestDelegate _next;
private HttpContext _httpContext;
public ClaimsToClaimsMiddlewareTests()
{
_httpContext = new DefaultHttpContext();
_addHeaders = new Mock<IAddClaimsToRequest>();
_loggerFactory = new Mock<IOcelotLoggerFactory>();
_logger = new Mock<IOcelotLogger>();
_loggerFactory.Setup(x => x.CreateLogger<ClaimsToClaimsMiddleware>()).Returns(_logger.Object);
_next = context => Task.CompletedTask;
_middleware = new ClaimsToClaimsMiddleware(_next, _loggerFactory.Object, _addHeaders.Object);
}
[Fact]
public void should_call_claims_to_request_correctly()
{
var downstreamRoute = new DownstreamRoute(new List<PlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("any old string")
.WithClaimsToClaims(new List<ClaimToThing>
{
new ClaimToThing("sub", "UserType", "|", 0)
})
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build());
this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
.And(x => x.GivenTheAddClaimsToRequestReturns())
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheClaimsToRequestIsCalledCorrectly())
.BDDfy();
}
private void WhenICallTheMiddleware()
{
_middleware.Invoke(_httpContext).GetAwaiter().GetResult();
}
private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute)
using Ocelot.DownstreamRouteFinder.UrlMatcher;
using Ocelot.Logging;
using Ocelot.Responses;
using System.Collections.Generic;
using System.Threading.Tasks;
using TestStack.BDDfy;
using Xunit;
public class ClaimsToClaimsMiddlewareTests
{
private readonly Mock<IAddClaimsToRequest> _addHeaders;
private Mock<IOcelotLoggerFactory> _loggerFactory;
private Mock<IOcelotLogger> _logger;
private readonly ClaimsToClaimsMiddleware _middleware;
private RequestDelegate _next;
private HttpContext _httpContext;
public ClaimsToClaimsMiddlewareTests()
{
_httpContext = new DefaultHttpContext();
_addHeaders = new Mock<IAddClaimsToRequest>();
_loggerFactory = new Mock<IOcelotLoggerFactory>();
_logger = new Mock<IOcelotLogger>();
_loggerFactory.Setup(x => x.CreateLogger<ClaimsToClaimsMiddleware>()).Returns(_logger.Object);
_next = context => Task.CompletedTask;
_middleware = new ClaimsToClaimsMiddleware(_next, _loggerFactory.Object, _addHeaders.Object);
}
[Fact]
public void should_call_claims_to_request_correctly()
{
var downstreamRoute = new Ocelot.DownstreamRouteFinder.DownstreamRouteHolder(new List<PlaceholderNameAndValue>(),
new RouteBuilder()
.WithDownstreamRoute(new DownstreamRouteBuilder()
.WithDownstreamPathTemplate("any old string")
.WithClaimsToClaims(new List<ClaimToThing>
{
new ClaimToThing("sub", "UserType", "|", 0)
})
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build());
this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
.And(x => x.GivenTheAddClaimsToRequestReturns())
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheClaimsToRequestIsCalledCorrectly())
.BDDfy();
}
private void WhenICallTheMiddleware()
{
_middleware.Invoke(_httpContext).GetAwaiter().GetResult();
}
private void GivenTheDownStreamRouteIs(Ocelot.DownstreamRouteFinder.DownstreamRouteHolder downstreamRoute)
{
_httpContext.Items.UpsertTemplatePlaceholderNameAndValues(downstreamRoute.TemplatePlaceholderNameAndValues);
_httpContext.Items.UpsertDownstreamReRoute(downstreamRoute.ReRoute.DownstreamReRoute[0]);
}
private void GivenTheAddClaimsToRequestReturns()
{
_addHeaders
.Setup(x => x.SetClaimsOnContext(It.IsAny<List<ClaimToThing>>(),
It.IsAny<HttpContext>()))
.Returns(new OkResponse());
}
private void ThenTheClaimsToRequestIsCalledCorrectly()
{
_addHeaders
.Verify(x => x.SetClaimsOnContext(It.IsAny<List<ClaimToThing>>(),
It.IsAny<HttpContext>()), Times.Once);
}
}
}
_httpContext.Items.UpsertDownstreamRoute(downstreamRoute.Route.DownstreamRoute[0]);
}
private void GivenTheAddClaimsToRequestReturns()
{
_addHeaders
.Setup(x => x.SetClaimsOnContext(It.IsAny<List<ClaimToThing>>(),
It.IsAny<HttpContext>()))
.Returns(new OkResponse());
}
private void ThenTheClaimsToRequestIsCalledCorrectly()
{
_addHeaders
.Verify(x => x.SetClaimsOnContext(It.IsAny<List<ClaimToThing>>(),
It.IsAny<HttpContext>()), Times.Once);
}
}
}

View File

@ -1,164 +1,164 @@
namespace Ocelot.UnitTests.Configuration
{
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Shouldly;
using System.Collections.Generic;
using System.Net.Http;
using TestStack.BDDfy;
using Values;
using Xunit;
public class AggregatesCreatorTests
{
private readonly AggregatesCreator _creator;
private readonly Mock<IUpstreamTemplatePatternCreator> _utpCreator;
private FileConfiguration _fileConfiguration;
private List<ReRoute> _reRoutes;
private List<ReRoute> _result;
private UpstreamPathTemplate _aggregate1Utp;
private UpstreamPathTemplate _aggregate2Utp;
public AggregatesCreatorTests()
{
_utpCreator = new Mock<IUpstreamTemplatePatternCreator>();
_creator = new AggregatesCreator(_utpCreator.Object);
}
[Fact]
public void should_return_no_aggregates()
{
var fileConfig = new FileConfiguration
{
Aggregates = new List<FileAggregateReRoute>
{
new FileAggregateReRoute
{
ReRouteKeys = new List<string>{"key1"}
}
}
};
var reRoutes = new List<ReRoute>();
this.Given(_ => GivenThe(fileConfig))
.And(_ => GivenThe(reRoutes))
.When(_ => WhenICreate())
.Then(_ => TheUtpCreatorIsNotCalled())
.And(_ => ThenTheResultIsNotNull())
.And(_ => ThenTheResultIsEmpty())
.BDDfy();
}
[Fact]
public void should_create_aggregates()
{
var fileConfig = new FileConfiguration
{
Aggregates = new List<FileAggregateReRoute>
{
new FileAggregateReRoute
{
ReRouteKeys = new List<string>{"key1", "key2"},
UpstreamHost = "hosty",
UpstreamPathTemplate = "templatey",
Aggregator = "aggregatory",
ReRouteIsCaseSensitive = true
},
new FileAggregateReRoute
{
ReRouteKeys = new List<string>{"key3", "key4"},
UpstreamHost = "hosty",
UpstreamPathTemplate = "templatey",
Aggregator = "aggregatory",
ReRouteIsCaseSensitive = true
}
}
};
var reRoutes = new List<ReRoute>
{
new ReRouteBuilder().WithDownstreamReRoute(new DownstreamReRouteBuilder().WithKey("key1").Build()).Build(),
new ReRouteBuilder().WithDownstreamReRoute(new DownstreamReRouteBuilder().WithKey("key2").Build()).Build(),
new ReRouteBuilder().WithDownstreamReRoute(new DownstreamReRouteBuilder().WithKey("key3").Build()).Build(),
new ReRouteBuilder().WithDownstreamReRoute(new DownstreamReRouteBuilder().WithKey("key4").Build()).Build()
};
this.Given(_ => GivenThe(fileConfig))
.And(_ => GivenThe(reRoutes))
.And(_ => GivenTheUtpCreatorReturns())
.When(_ => WhenICreate())
.Then(_ => ThenTheUtpCreatorIsCalledCorrectly())
.And(_ => ThenTheAggregatesAreCreated())
.BDDfy();
}
private void ThenTheAggregatesAreCreated()
{
_result.ShouldNotBeNull();
_result.Count.ShouldBe(2);
_result[0].UpstreamHttpMethod.ShouldContain(x => x == HttpMethod.Get);
_result[0].UpstreamHost.ShouldBe(_fileConfiguration.Aggregates[0].UpstreamHost);
_result[0].UpstreamTemplatePattern.ShouldBe(_aggregate1Utp);
_result[0].Aggregator.ShouldBe(_fileConfiguration.Aggregates[0].Aggregator);
_result[0].DownstreamReRoute.ShouldContain(x => x == _reRoutes[0].DownstreamReRoute[0]);
_result[0].DownstreamReRoute.ShouldContain(x => x == _reRoutes[1].DownstreamReRoute[0]);
_result[1].UpstreamHttpMethod.ShouldContain(x => x == HttpMethod.Get);
_result[1].UpstreamHost.ShouldBe(_fileConfiguration.Aggregates[1].UpstreamHost);
_result[1].UpstreamTemplatePattern.ShouldBe(_aggregate2Utp);
_result[1].Aggregator.ShouldBe(_fileConfiguration.Aggregates[1].Aggregator);
_result[1].DownstreamReRoute.ShouldContain(x => x == _reRoutes[2].DownstreamReRoute[0]);
_result[1].DownstreamReRoute.ShouldContain(x => x == _reRoutes[3].DownstreamReRoute[0]);
}
private void ThenTheUtpCreatorIsCalledCorrectly()
{
_utpCreator.Verify(x => x.Create(_fileConfiguration.Aggregates[0]), Times.Once);
_utpCreator.Verify(x => x.Create(_fileConfiguration.Aggregates[1]), Times.Once);
}
private void GivenTheUtpCreatorReturns()
{
_aggregate1Utp = new UpstreamPathTemplateBuilder().Build();
_aggregate2Utp = new UpstreamPathTemplateBuilder().Build();
_utpCreator.SetupSequence(x => x.Create(It.IsAny<IReRoute>()))
.Returns(_aggregate1Utp)
.Returns(_aggregate2Utp);
}
private void ThenTheResultIsEmpty()
{
_result.Count.ShouldBe(0);
}
private void ThenTheResultIsNotNull()
{
_result.ShouldNotBeNull();
}
private void TheUtpCreatorIsNotCalled()
{
_utpCreator.Verify(x => x.Create(It.IsAny<FileAggregateReRoute>()), Times.Never);
}
private void GivenThe(FileConfiguration fileConfiguration)
{
_fileConfiguration = fileConfiguration;
}
private void GivenThe(List<ReRoute> reRoutes)
{
_reRoutes = reRoutes;
}
private void WhenICreate()
{
_result = _creator.Create(_fileConfiguration, _reRoutes);
}
}
}
namespace Ocelot.UnitTests.Configuration
{
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Shouldly;
using System.Collections.Generic;
using System.Net.Http;
using TestStack.BDDfy;
using Values;
using Xunit;
public class AggregatesCreatorTests
{
private readonly AggregatesCreator _creator;
private readonly Mock<IUpstreamTemplatePatternCreator> _utpCreator;
private FileConfiguration _fileConfiguration;
private List<Route> _routes;
private List<Route> _result;
private UpstreamPathTemplate _aggregate1Utp;
private UpstreamPathTemplate _aggregate2Utp;
public AggregatesCreatorTests()
{
_utpCreator = new Mock<IUpstreamTemplatePatternCreator>();
_creator = new AggregatesCreator(_utpCreator.Object);
}
[Fact]
public void should_return_no_aggregates()
{
var fileConfig = new FileConfiguration
{
Aggregates = new List<FileAggregateRoute>
{
new FileAggregateRoute
{
RouteKeys = new List<string>{"key1"}
}
}
};
var routes = new List<Route>();
this.Given(_ => GivenThe(fileConfig))
.And(_ => GivenThe(routes))
.When(_ => WhenICreate())
.Then(_ => TheUtpCreatorIsNotCalled())
.And(_ => ThenTheResultIsNotNull())
.And(_ => ThenTheResultIsEmpty())
.BDDfy();
}
[Fact]
public void should_create_aggregates()
{
var fileConfig = new FileConfiguration
{
Aggregates = new List<FileAggregateRoute>
{
new FileAggregateRoute
{
RouteKeys = new List<string>{"key1", "key2"},
UpstreamHost = "hosty",
UpstreamPathTemplate = "templatey",
Aggregator = "aggregatory",
RouteIsCaseSensitive = true
},
new FileAggregateRoute
{
RouteKeys = new List<string>{"key3", "key4"},
UpstreamHost = "hosty",
UpstreamPathTemplate = "templatey",
Aggregator = "aggregatory",
RouteIsCaseSensitive = true
}
}
};
var routes = new List<Route>
{
new RouteBuilder().WithDownstreamRoute(new DownstreamRouteBuilder().WithKey("key1").Build()).Build(),
new RouteBuilder().WithDownstreamRoute(new DownstreamRouteBuilder().WithKey("key2").Build()).Build(),
new RouteBuilder().WithDownstreamRoute(new DownstreamRouteBuilder().WithKey("key3").Build()).Build(),
new RouteBuilder().WithDownstreamRoute(new DownstreamRouteBuilder().WithKey("key4").Build()).Build()
};
this.Given(_ => GivenThe(fileConfig))
.And(_ => GivenThe(routes))
.And(_ => GivenTheUtpCreatorReturns())
.When(_ => WhenICreate())
.Then(_ => ThenTheUtpCreatorIsCalledCorrectly())
.And(_ => ThenTheAggregatesAreCreated())
.BDDfy();
}
private void ThenTheAggregatesAreCreated()
{
_result.ShouldNotBeNull();
_result.Count.ShouldBe(2);
_result[0].UpstreamHttpMethod.ShouldContain(x => x == HttpMethod.Get);
_result[0].UpstreamHost.ShouldBe(_fileConfiguration.Aggregates[0].UpstreamHost);
_result[0].UpstreamTemplatePattern.ShouldBe(_aggregate1Utp);
_result[0].Aggregator.ShouldBe(_fileConfiguration.Aggregates[0].Aggregator);
_result[0].DownstreamRoute.ShouldContain(x => x == _routes[0].DownstreamRoute[0]);
_result[0].DownstreamRoute.ShouldContain(x => x == _routes[1].DownstreamRoute[0]);
_result[1].UpstreamHttpMethod.ShouldContain(x => x == HttpMethod.Get);
_result[1].UpstreamHost.ShouldBe(_fileConfiguration.Aggregates[1].UpstreamHost);
_result[1].UpstreamTemplatePattern.ShouldBe(_aggregate2Utp);
_result[1].Aggregator.ShouldBe(_fileConfiguration.Aggregates[1].Aggregator);
_result[1].DownstreamRoute.ShouldContain(x => x == _routes[2].DownstreamRoute[0]);
_result[1].DownstreamRoute.ShouldContain(x => x == _routes[3].DownstreamRoute[0]);
}
private void ThenTheUtpCreatorIsCalledCorrectly()
{
_utpCreator.Verify(x => x.Create(_fileConfiguration.Aggregates[0]), Times.Once);
_utpCreator.Verify(x => x.Create(_fileConfiguration.Aggregates[1]), Times.Once);
}
private void GivenTheUtpCreatorReturns()
{
_aggregate1Utp = new UpstreamPathTemplateBuilder().Build();
_aggregate2Utp = new UpstreamPathTemplateBuilder().Build();
_utpCreator.SetupSequence(x => x.Create(It.IsAny<IRoute>()))
.Returns(_aggregate1Utp)
.Returns(_aggregate2Utp);
}
private void ThenTheResultIsEmpty()
{
_result.Count.ShouldBe(0);
}
private void ThenTheResultIsNotNull()
{
_result.ShouldNotBeNull();
}
private void TheUtpCreatorIsNotCalled()
{
_utpCreator.Verify(x => x.Create(It.IsAny<FileAggregateRoute>()), Times.Never);
}
private void GivenThe(FileConfiguration fileConfiguration)
{
_fileConfiguration = fileConfiguration;
}
private void GivenThe(List<Route> routes)
{
_routes = routes;
}
private void WhenICreate()
{
_result = _creator.Create(_fileConfiguration, _routes);
}
}
}

View File

@ -1,62 +1,62 @@
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Shouldly;
using System.Collections.Generic;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration
{
public class AuthenticationOptionsCreatorTests
{
private readonly AuthenticationOptionsCreator _authOptionsCreator;
private FileReRoute _fileReRoute;
private AuthenticationOptions _result;
public AuthenticationOptionsCreatorTests()
{
_authOptionsCreator = new AuthenticationOptionsCreator();
}
[Fact]
public void should_return_auth_options()
{
var fileReRoute = new FileReRoute()
{
AuthenticationOptions = new FileAuthenticationOptions
{
AuthenticationProviderKey = "Test",
AllowedScopes = new List<string> { "cheese" },
}
};
var expected = new AuthenticationOptionsBuilder()
.WithAllowedScopes(fileReRoute.AuthenticationOptions?.AllowedScopes)
.WithAuthenticationProviderKey("Test")
.Build();
this.Given(x => x.GivenTheFollowing(fileReRoute))
.When(x => x.WhenICreateTheAuthenticationOptions())
.Then(x => x.ThenTheFollowingConfigIsReturned(expected))
.BDDfy();
}
private void GivenTheFollowing(FileReRoute fileReRoute)
{
_fileReRoute = fileReRoute;
}
private void WhenICreateTheAuthenticationOptions()
{
_result = _authOptionsCreator.Create(_fileReRoute);
}
private void ThenTheFollowingConfigIsReturned(AuthenticationOptions expected)
namespace Ocelot.UnitTests.Configuration
{
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Shouldly;
using System.Collections.Generic;
using TestStack.BDDfy;
using Xunit;
public class AuthenticationOptionsCreatorTests
{
private readonly AuthenticationOptionsCreator _authOptionsCreator;
private FileRoute _fileRoute;
private AuthenticationOptions _result;
public AuthenticationOptionsCreatorTests()
{
_result.AllowedScopes.ShouldBe(expected.AllowedScopes);
_result.AuthenticationProviderKey.ShouldBe(expected.AuthenticationProviderKey);
}
}
_authOptionsCreator = new AuthenticationOptionsCreator();
}
[Fact]
public void should_return_auth_options()
{
var fileRoute = new FileRoute()
{
AuthenticationOptions = new FileAuthenticationOptions
{
AuthenticationProviderKey = "Test",
AllowedScopes = new List<string> { "cheese" },
}
};
var expected = new AuthenticationOptionsBuilder()
.WithAllowedScopes(fileRoute.AuthenticationOptions?.AllowedScopes)
.WithAuthenticationProviderKey("Test")
.Build();
this.Given(x => x.GivenTheFollowing(fileRoute))
.When(x => x.WhenICreateTheAuthenticationOptions())
.Then(x => x.ThenTheFollowingConfigIsReturned(expected))
.BDDfy();
}
private void GivenTheFollowing(FileRoute fileRoute)
{
_fileRoute = fileRoute;
}
private void WhenICreateTheAuthenticationOptions()
{
_result = _authOptionsCreator.Create(_fileRoute);
}
private void ThenTheFollowingConfigIsReturned(AuthenticationOptions expected)
{
_result.AllowedScopes.ShouldBe(expected.AllowedScopes);
_result.AuthenticationProviderKey.ShouldBe(expected.AuthenticationProviderKey);
}
}
}

View File

@ -1,126 +1,126 @@
namespace Ocelot.UnitTests.Configuration
{
using Microsoft.Extensions.DependencyInjection;
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Ocelot.DependencyInjection;
using Shouldly;
using System.Collections.Generic;
using TestStack.BDDfy;
using Xunit;
public class ConfigurationCreatorTests
{
private ConfigurationCreator _creator;
private InternalConfiguration _result;
private readonly Mock<IServiceProviderConfigurationCreator> _spcCreator;
private readonly Mock<IQoSOptionsCreator> _qosCreator;
private readonly Mock<IHttpHandlerOptionsCreator> _hhoCreator;
private readonly Mock<ILoadBalancerOptionsCreator> _lboCreator;
private readonly Mock<IVersionCreator> _vCreator;
private FileConfiguration _fileConfig;
private List<ReRoute> _reRoutes;
private ServiceProviderConfiguration _spc;
private LoadBalancerOptions _lbo;
private QoSOptions _qoso;
private HttpHandlerOptions _hho;
private AdministrationPath _adminPath;
private readonly ServiceCollection _serviceCollection;
public ConfigurationCreatorTests()
{
_vCreator = new Mock<IVersionCreator>();
_lboCreator = new Mock<ILoadBalancerOptionsCreator>();
_hhoCreator = new Mock<IHttpHandlerOptionsCreator>();
_qosCreator = new Mock<IQoSOptionsCreator>();
_spcCreator = new Mock<IServiceProviderConfigurationCreator>();
_serviceCollection = new ServiceCollection();
}
[Fact]
public void should_build_configuration_with_no_admin_path()
{
this.Given(_ => GivenTheDependenciesAreSetUp())
.When(_ => WhenICreate())
.Then(_ => ThenTheDepdenciesAreCalledCorrectly())
.And(_ => ThenThePropertiesAreSetCorrectly())
.And(_ => ThenTheAdminPathIsNull())
.BDDfy();
}
[Fact]
public void should_build_configuration_with_admin_path()
{
this.Given(_ => GivenTheDependenciesAreSetUp())
.And(_ => GivenTheAdminPath())
.When(_ => WhenICreate())
.Then(_ => ThenTheDepdenciesAreCalledCorrectly())
.And(_ => ThenThePropertiesAreSetCorrectly())
.And(_ => ThenTheAdminPathIsSet())
.BDDfy();
}
private void ThenTheAdminPathIsNull()
{
_result.AdministrationPath.ShouldBeNull();
}
private void ThenThePropertiesAreSetCorrectly()
{
_result.ShouldNotBeNull();
_result.ServiceProviderConfiguration.ShouldBe(_spc);
_result.LoadBalancerOptions.ShouldBe(_lbo);
_result.QoSOptions.ShouldBe(_qoso);
_result.HttpHandlerOptions.ShouldBe(_hho);
_result.ReRoutes.ShouldBe(_reRoutes);
_result.RequestId.ShouldBe(_fileConfig.GlobalConfiguration.RequestIdKey);
_result.DownstreamScheme.ShouldBe(_fileConfig.GlobalConfiguration.DownstreamScheme);
}
private void ThenTheAdminPathIsSet()
{
_result.AdministrationPath.ShouldBe("wooty");
}
private void ThenTheDepdenciesAreCalledCorrectly()
{
_spcCreator.Verify(x => x.Create(_fileConfig.GlobalConfiguration), Times.Once);
_lboCreator.Verify(x => x.Create(_fileConfig.GlobalConfiguration.LoadBalancerOptions), Times.Once);
_qosCreator.Verify(x => x.Create(_fileConfig.GlobalConfiguration.QoSOptions), Times.Once);
_hhoCreator.Verify(x => x.Create(_fileConfig.GlobalConfiguration.HttpHandlerOptions), Times.Once);
}
private void GivenTheAdminPath()
{
_adminPath = new AdministrationPath("wooty");
_serviceCollection.AddSingleton<IAdministrationPath>(_adminPath);
}
private void GivenTheDependenciesAreSetUp()
{
_fileConfig = new FileConfiguration
{
GlobalConfiguration = new FileGlobalConfiguration()
};
_reRoutes = new List<ReRoute>();
_spc = new ServiceProviderConfiguration("", "", "", 1, "", "", 1);
_lbo = new LoadBalancerOptionsBuilder().Build();
_qoso = new QoSOptions(1, 1, 1, "");
_hho = new HttpHandlerOptionsBuilder().Build();
_spcCreator.Setup(x => x.Create(It.IsAny<FileGlobalConfiguration>())).Returns(_spc);
_lboCreator.Setup(x => x.Create(It.IsAny<FileLoadBalancerOptions>())).Returns(_lbo);
_qosCreator.Setup(x => x.Create(It.IsAny<FileQoSOptions>())).Returns(_qoso);
_hhoCreator.Setup(x => x.Create(It.IsAny<FileHttpHandlerOptions>())).Returns(_hho);
}
private void WhenICreate()
{
var serviceProvider = _serviceCollection.BuildServiceProvider();
_creator = new ConfigurationCreator(_spcCreator.Object, _qosCreator.Object, _hhoCreator.Object, serviceProvider, _lboCreator.Object, _vCreator.Object);
_result = _creator.Create(_fileConfig, _reRoutes);
}
}
}
namespace Ocelot.UnitTests.Configuration
{
using Microsoft.Extensions.DependencyInjection;
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Ocelot.DependencyInjection;
using Shouldly;
using System.Collections.Generic;
using TestStack.BDDfy;
using Xunit;
public class ConfigurationCreatorTests
{
private ConfigurationCreator _creator;
private InternalConfiguration _result;
private readonly Mock<IServiceProviderConfigurationCreator> _spcCreator;
private readonly Mock<IQoSOptionsCreator> _qosCreator;
private readonly Mock<IHttpHandlerOptionsCreator> _hhoCreator;
private readonly Mock<ILoadBalancerOptionsCreator> _lboCreator;
private readonly Mock<IVersionCreator> _vCreator;
private FileConfiguration _fileConfig;
private List<Route> _routes;
private ServiceProviderConfiguration _spc;
private LoadBalancerOptions _lbo;
private QoSOptions _qoso;
private HttpHandlerOptions _hho;
private AdministrationPath _adminPath;
private readonly ServiceCollection _serviceCollection;
public ConfigurationCreatorTests()
{
_vCreator = new Mock<IVersionCreator>();
_lboCreator = new Mock<ILoadBalancerOptionsCreator>();
_hhoCreator = new Mock<IHttpHandlerOptionsCreator>();
_qosCreator = new Mock<IQoSOptionsCreator>();
_spcCreator = new Mock<IServiceProviderConfigurationCreator>();
_serviceCollection = new ServiceCollection();
}
[Fact]
public void should_build_configuration_with_no_admin_path()
{
this.Given(_ => GivenTheDependenciesAreSetUp())
.When(_ => WhenICreate())
.Then(_ => ThenTheDepdenciesAreCalledCorrectly())
.And(_ => ThenThePropertiesAreSetCorrectly())
.And(_ => ThenTheAdminPathIsNull())
.BDDfy();
}
[Fact]
public void should_build_configuration_with_admin_path()
{
this.Given(_ => GivenTheDependenciesAreSetUp())
.And(_ => GivenTheAdminPath())
.When(_ => WhenICreate())
.Then(_ => ThenTheDepdenciesAreCalledCorrectly())
.And(_ => ThenThePropertiesAreSetCorrectly())
.And(_ => ThenTheAdminPathIsSet())
.BDDfy();
}
private void ThenTheAdminPathIsNull()
{
_result.AdministrationPath.ShouldBeNull();
}
private void ThenThePropertiesAreSetCorrectly()
{
_result.ShouldNotBeNull();
_result.ServiceProviderConfiguration.ShouldBe(_spc);
_result.LoadBalancerOptions.ShouldBe(_lbo);
_result.QoSOptions.ShouldBe(_qoso);
_result.HttpHandlerOptions.ShouldBe(_hho);
_result.Routes.ShouldBe(_routes);
_result.RequestId.ShouldBe(_fileConfig.GlobalConfiguration.RequestIdKey);
_result.DownstreamScheme.ShouldBe(_fileConfig.GlobalConfiguration.DownstreamScheme);
}
private void ThenTheAdminPathIsSet()
{
_result.AdministrationPath.ShouldBe("wooty");
}
private void ThenTheDepdenciesAreCalledCorrectly()
{
_spcCreator.Verify(x => x.Create(_fileConfig.GlobalConfiguration), Times.Once);
_lboCreator.Verify(x => x.Create(_fileConfig.GlobalConfiguration.LoadBalancerOptions), Times.Once);
_qosCreator.Verify(x => x.Create(_fileConfig.GlobalConfiguration.QoSOptions), Times.Once);
_hhoCreator.Verify(x => x.Create(_fileConfig.GlobalConfiguration.HttpHandlerOptions), Times.Once);
}
private void GivenTheAdminPath()
{
_adminPath = new AdministrationPath("wooty");
_serviceCollection.AddSingleton<IAdministrationPath>(_adminPath);
}
private void GivenTheDependenciesAreSetUp()
{
_fileConfig = new FileConfiguration
{
GlobalConfiguration = new FileGlobalConfiguration()
};
_routes = new List<Route>();
_spc = new ServiceProviderConfiguration("", "", "", 1, "", "", 1);
_lbo = new LoadBalancerOptionsBuilder().Build();
_qoso = new QoSOptions(1, 1, 1, "");
_hho = new HttpHandlerOptionsBuilder().Build();
_spcCreator.Setup(x => x.Create(It.IsAny<FileGlobalConfiguration>())).Returns(_spc);
_lboCreator.Setup(x => x.Create(It.IsAny<FileLoadBalancerOptions>())).Returns(_lbo);
_qosCreator.Setup(x => x.Create(It.IsAny<FileQoSOptions>())).Returns(_qoso);
_hhoCreator.Setup(x => x.Create(It.IsAny<FileHttpHandlerOptions>())).Returns(_hho);
}
private void WhenICreate()
{
var serviceProvider = _serviceCollection.BuildServiceProvider();
_creator = new ConfigurationCreator(_spcCreator.Object, _qosCreator.Object, _hhoCreator.Object, serviceProvider, _lboCreator.Object, _vCreator.Object);
_result = _creator.Create(_fileConfig, _routes);
}
}
}

View File

@ -1,302 +1,302 @@
namespace Ocelot.UnitTests.Configuration
{
using Microsoft.AspNetCore.Hosting;
using Moq;
using Newtonsoft.Json;
using Ocelot.Configuration.ChangeTracking;
using Ocelot.Configuration.File;
using Ocelot.Configuration.Repository;
using Shouldly;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using TestStack.BDDfy;
using Xunit;
public class DiskFileConfigurationRepositoryTests : IDisposable
{
private readonly Mock<IWebHostEnvironment> _hostingEnvironment;
private readonly Mock<IOcelotConfigurationChangeTokenSource> _changeTokenSource;
private IFileConfigurationRepository _repo;
private string _environmentSpecificPath;
private string _ocelotJsonPath;
private FileConfiguration _result;
private FileConfiguration _fileConfiguration;
// This is a bit dirty and it is dev.dev so that the ConfigurationBuilderExtensionsTests
// cant pick it up if they run in parralel..and the semaphore stops them running at the same time...sigh
// these are not really unit tests but whatever...
private string _environmentName = "DEV.DEV";
private static SemaphoreSlim _semaphore;
public DiskFileConfigurationRepositoryTests()
{
_semaphore = new SemaphoreSlim(1, 1);
_semaphore.Wait();
_hostingEnvironment = new Mock<IWebHostEnvironment>();
_hostingEnvironment.Setup(he => he.EnvironmentName).Returns(_environmentName);
_changeTokenSource = new Mock<IOcelotConfigurationChangeTokenSource>(MockBehavior.Strict);
_changeTokenSource.Setup(m => m.Activate());
_repo = new DiskFileConfigurationRepository(_hostingEnvironment.Object, _changeTokenSource.Object);
}
[Fact]
public void should_return_file_configuration()
{
var config = FakeFileConfigurationForGet();
this.Given(_ => GivenTheConfigurationIs(config))
.When(_ => WhenIGetTheReRoutes())
.Then(_ => ThenTheFollowingIsReturned(config))
.BDDfy();
}
[Fact]
public void should_return_file_configuration_if_environment_name_is_unavailable()
{
var config = FakeFileConfigurationForGet();
this.Given(_ => GivenTheEnvironmentNameIsUnavailable())
.And(_ => GivenTheConfigurationIs(config))
.When(_ => WhenIGetTheReRoutes())
.Then(_ => ThenTheFollowingIsReturned(config))
.BDDfy();
}
[Fact]
public void should_set_file_configuration()
{
var config = FakeFileConfigurationForSet();
this.Given(_ => GivenIHaveAConfiguration(config))
.When(_ => WhenISetTheConfiguration())
.Then(_ => ThenTheConfigurationIsStoredAs(config))
.And(_ => ThenTheConfigurationJsonIsIndented(config))
.And(x => AndTheChangeTokenIsActivated())
.BDDfy();
}
[Fact]
public void should_set_file_configuration_if_environment_name_is_unavailable()
{
var config = FakeFileConfigurationForSet();
this.Given(_ => GivenIHaveAConfiguration(config))
.And(_ => GivenTheEnvironmentNameIsUnavailable())
.When(_ => WhenISetTheConfiguration())
.Then(_ => ThenTheConfigurationIsStoredAs(config))
.And(_ => ThenTheConfigurationJsonIsIndented(config))
.BDDfy();
}
[Fact]
public void should_set_environment_file_configuration_and_ocelot_file_configuration()
{
var config = FakeFileConfigurationForSet();
this.Given(_ => GivenIHaveAConfiguration(config))
.And(_ => GivenTheConfigurationIs(config))
.And(_ => GivenTheUserAddedOcelotJson())
.When(_ => WhenISetTheConfiguration())
.Then(_ => ThenTheConfigurationIsStoredAs(config))
.And(_ => ThenTheConfigurationJsonIsIndented(config))
.Then(_ => ThenTheOcelotJsonIsStoredAs(config))
.BDDfy();
}
private void GivenTheUserAddedOcelotJson()
{
_ocelotJsonPath = $"{AppContext.BaseDirectory}/ocelot.json";
if (File.Exists(_ocelotJsonPath))
{
File.Delete(_ocelotJsonPath);
}
File.WriteAllText(_ocelotJsonPath, "Doesnt matter");
}
private void GivenTheEnvironmentNameIsUnavailable()
{
_environmentName = null;
_hostingEnvironment.Setup(he => he.EnvironmentName).Returns(_environmentName);
_repo = new DiskFileConfigurationRepository(_hostingEnvironment.Object, _changeTokenSource.Object);
}
private void GivenIHaveAConfiguration(FileConfiguration fileConfiguration)
{
_fileConfiguration = fileConfiguration;
}
private void WhenISetTheConfiguration()
{
_repo.Set(_fileConfiguration);
_result = _repo.Get().Result.Data;
}
private void ThenTheConfigurationIsStoredAs(FileConfiguration expecteds)
{
_result.GlobalConfiguration.RequestIdKey.ShouldBe(expecteds.GlobalConfiguration.RequestIdKey);
_result.GlobalConfiguration.ServiceDiscoveryProvider.Scheme.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Scheme);
_result.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Host);
_result.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Port);
for (var i = 0; i < _result.ReRoutes.Count; i++)
{
for (int j = 0; j < _result.ReRoutes[i].DownstreamHostAndPorts.Count; j++)
{
var result = _result.ReRoutes[i].DownstreamHostAndPorts[j];
var expected = expecteds.ReRoutes[i].DownstreamHostAndPorts[j];
result.Host.ShouldBe(expected.Host);
result.Port.ShouldBe(expected.Port);
}
_result.ReRoutes[i].DownstreamPathTemplate.ShouldBe(expecteds.ReRoutes[i].DownstreamPathTemplate);
_result.ReRoutes[i].DownstreamScheme.ShouldBe(expecteds.ReRoutes[i].DownstreamScheme);
}
}
private void ThenTheOcelotJsonIsStoredAs(FileConfiguration expecteds)
{
var resultText = File.ReadAllText(_ocelotJsonPath);
var expectedText = JsonConvert.SerializeObject(expecteds, Formatting.Indented);
resultText.ShouldBe(expectedText);
}
private void GivenTheConfigurationIs(FileConfiguration fileConfiguration)
{
_environmentSpecificPath = $"{AppContext.BaseDirectory}/ocelot{(string.IsNullOrEmpty(_environmentName) ? string.Empty : ".")}{_environmentName}.json";
var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration, Formatting.Indented);
if (File.Exists(_environmentSpecificPath))
{
File.Delete(_environmentSpecificPath);
}
File.WriteAllText(_environmentSpecificPath, jsonConfiguration);
}
private void ThenTheConfigurationJsonIsIndented(FileConfiguration expecteds)
{
var path = !string.IsNullOrEmpty(_environmentSpecificPath) ? _environmentSpecificPath : _environmentSpecificPath = $"{AppContext.BaseDirectory}/ocelot{(string.IsNullOrEmpty(_environmentName) ? string.Empty : ".")}{_environmentName}.json";
var resultText = File.ReadAllText(path);
var expectedText = JsonConvert.SerializeObject(expecteds, Formatting.Indented);
resultText.ShouldBe(expectedText);
}
private void WhenIGetTheReRoutes()
{
_result = _repo.Get().Result.Data;
}
private void ThenTheFollowingIsReturned(FileConfiguration expecteds)
{
_result.GlobalConfiguration.RequestIdKey.ShouldBe(expecteds.GlobalConfiguration.RequestIdKey);
_result.GlobalConfiguration.ServiceDiscoveryProvider.Scheme.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Scheme);
_result.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Host);
_result.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Port);
for (var i = 0; i < _result.ReRoutes.Count; i++)
{
for (int j = 0; j < _result.ReRoutes[i].DownstreamHostAndPorts.Count; j++)
{
var result = _result.ReRoutes[i].DownstreamHostAndPorts[j];
var expected = expecteds.ReRoutes[i].DownstreamHostAndPorts[j];
result.Host.ShouldBe(expected.Host);
result.Port.ShouldBe(expected.Port);
}
_result.ReRoutes[i].DownstreamPathTemplate.ShouldBe(expecteds.ReRoutes[i].DownstreamPathTemplate);
_result.ReRoutes[i].DownstreamScheme.ShouldBe(expecteds.ReRoutes[i].DownstreamScheme);
}
}
private void AndTheChangeTokenIsActivated()
{
_changeTokenSource.Verify(m => m.Activate(), Times.Once);
}
private FileConfiguration FakeFileConfigurationForSet()
{
var reRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "123.12.12.12",
Port = 80,
},
},
DownstreamScheme = "https",
DownstreamPathTemplate = "/asdfs/test/{test}",
},
};
var globalConfiguration = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{
Scheme = "https",
Port = 198,
Host = "blah"
}
};
return new FileConfiguration
{
GlobalConfiguration = globalConfiguration,
ReRoutes = reRoutes
};
}
private FileConfiguration FakeFileConfigurationForGet()
{
var reRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 80,
}
},
DownstreamScheme = "https",
DownstreamPathTemplate = "/test/test/{test}"
}
};
var globalConfiguration = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{
Scheme = "https",
Port = 198,
Host = "blah"
}
};
return new FileConfiguration
{
GlobalConfiguration = globalConfiguration,
ReRoutes = reRoutes
};
}
public void Dispose()
{
_semaphore.Release();
}
}
}
namespace Ocelot.UnitTests.Configuration
{
using Microsoft.AspNetCore.Hosting;
using Moq;
using Newtonsoft.Json;
using Ocelot.Configuration.ChangeTracking;
using Ocelot.Configuration.File;
using Ocelot.Configuration.Repository;
using Shouldly;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using TestStack.BDDfy;
using Xunit;
public class DiskFileConfigurationRepositoryTests : IDisposable
{
private readonly Mock<IWebHostEnvironment> _hostingEnvironment;
private readonly Mock<IOcelotConfigurationChangeTokenSource> _changeTokenSource;
private IFileConfigurationRepository _repo;
private string _environmentSpecificPath;
private string _ocelotJsonPath;
private FileConfiguration _result;
private FileConfiguration _fileConfiguration;
// This is a bit dirty and it is dev.dev so that the ConfigurationBuilderExtensionsTests
// cant pick it up if they run in parralel..and the semaphore stops them running at the same time...sigh
// these are not really unit tests but whatever...
private string _environmentName = "DEV.DEV";
private static SemaphoreSlim _semaphore;
public DiskFileConfigurationRepositoryTests()
{
_semaphore = new SemaphoreSlim(1, 1);
_semaphore.Wait();
_hostingEnvironment = new Mock<IWebHostEnvironment>();
_hostingEnvironment.Setup(he => he.EnvironmentName).Returns(_environmentName);
_changeTokenSource = new Mock<IOcelotConfigurationChangeTokenSource>(MockBehavior.Strict);
_changeTokenSource.Setup(m => m.Activate());
_repo = new DiskFileConfigurationRepository(_hostingEnvironment.Object, _changeTokenSource.Object);
}
[Fact]
public void should_return_file_configuration()
{
var config = FakeFileConfigurationForGet();
this.Given(_ => GivenTheConfigurationIs(config))
.When(_ => WhenIGetTheRoutes())
.Then(_ => ThenTheFollowingIsReturned(config))
.BDDfy();
}
[Fact]
public void should_return_file_configuration_if_environment_name_is_unavailable()
{
var config = FakeFileConfigurationForGet();
this.Given(_ => GivenTheEnvironmentNameIsUnavailable())
.And(_ => GivenTheConfigurationIs(config))
.When(_ => WhenIGetTheRoutes())
.Then(_ => ThenTheFollowingIsReturned(config))
.BDDfy();
}
[Fact]
public void should_set_file_configuration()
{
var config = FakeFileConfigurationForSet();
this.Given(_ => GivenIHaveAConfiguration(config))
.When(_ => WhenISetTheConfiguration())
.Then(_ => ThenTheConfigurationIsStoredAs(config))
.And(_ => ThenTheConfigurationJsonIsIndented(config))
.And(x => AndTheChangeTokenIsActivated())
.BDDfy();
}
[Fact]
public void should_set_file_configuration_if_environment_name_is_unavailable()
{
var config = FakeFileConfigurationForSet();
this.Given(_ => GivenIHaveAConfiguration(config))
.And(_ => GivenTheEnvironmentNameIsUnavailable())
.When(_ => WhenISetTheConfiguration())
.Then(_ => ThenTheConfigurationIsStoredAs(config))
.And(_ => ThenTheConfigurationJsonIsIndented(config))
.BDDfy();
}
[Fact]
public void should_set_environment_file_configuration_and_ocelot_file_configuration()
{
var config = FakeFileConfigurationForSet();
this.Given(_ => GivenIHaveAConfiguration(config))
.And(_ => GivenTheConfigurationIs(config))
.And(_ => GivenTheUserAddedOcelotJson())
.When(_ => WhenISetTheConfiguration())
.Then(_ => ThenTheConfigurationIsStoredAs(config))
.And(_ => ThenTheConfigurationJsonIsIndented(config))
.Then(_ => ThenTheOcelotJsonIsStoredAs(config))
.BDDfy();
}
private void GivenTheUserAddedOcelotJson()
{
_ocelotJsonPath = $"{AppContext.BaseDirectory}/ocelot.json";
if (File.Exists(_ocelotJsonPath))
{
File.Delete(_ocelotJsonPath);
}
File.WriteAllText(_ocelotJsonPath, "Doesnt matter");
}
private void GivenTheEnvironmentNameIsUnavailable()
{
_environmentName = null;
_hostingEnvironment.Setup(he => he.EnvironmentName).Returns(_environmentName);
_repo = new DiskFileConfigurationRepository(_hostingEnvironment.Object, _changeTokenSource.Object);
}
private void GivenIHaveAConfiguration(FileConfiguration fileConfiguration)
{
_fileConfiguration = fileConfiguration;
}
private void WhenISetTheConfiguration()
{
_repo.Set(_fileConfiguration);
_result = _repo.Get().Result.Data;
}
private void ThenTheConfigurationIsStoredAs(FileConfiguration expecteds)
{
_result.GlobalConfiguration.RequestIdKey.ShouldBe(expecteds.GlobalConfiguration.RequestIdKey);
_result.GlobalConfiguration.ServiceDiscoveryProvider.Scheme.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Scheme);
_result.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Host);
_result.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Port);
for (var i = 0; i < _result.Routes.Count; i++)
{
for (int j = 0; j < _result.Routes[i].DownstreamHostAndPorts.Count; j++)
{
var result = _result.Routes[i].DownstreamHostAndPorts[j];
var expected = expecteds.Routes[i].DownstreamHostAndPorts[j];
result.Host.ShouldBe(expected.Host);
result.Port.ShouldBe(expected.Port);
}
_result.Routes[i].DownstreamPathTemplate.ShouldBe(expecteds.Routes[i].DownstreamPathTemplate);
_result.Routes[i].DownstreamScheme.ShouldBe(expecteds.Routes[i].DownstreamScheme);
}
}
private void ThenTheOcelotJsonIsStoredAs(FileConfiguration expecteds)
{
var resultText = File.ReadAllText(_ocelotJsonPath);
var expectedText = JsonConvert.SerializeObject(expecteds, Formatting.Indented);
resultText.ShouldBe(expectedText);
}
private void GivenTheConfigurationIs(FileConfiguration fileConfiguration)
{
_environmentSpecificPath = $"{AppContext.BaseDirectory}/ocelot{(string.IsNullOrEmpty(_environmentName) ? string.Empty : ".")}{_environmentName}.json";
var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration, Formatting.Indented);
if (File.Exists(_environmentSpecificPath))
{
File.Delete(_environmentSpecificPath);
}
File.WriteAllText(_environmentSpecificPath, jsonConfiguration);
}
private void ThenTheConfigurationJsonIsIndented(FileConfiguration expecteds)
{
var path = !string.IsNullOrEmpty(_environmentSpecificPath) ? _environmentSpecificPath : _environmentSpecificPath = $"{AppContext.BaseDirectory}/ocelot{(string.IsNullOrEmpty(_environmentName) ? string.Empty : ".")}{_environmentName}.json";
var resultText = File.ReadAllText(path);
var expectedText = JsonConvert.SerializeObject(expecteds, Formatting.Indented);
resultText.ShouldBe(expectedText);
}
private void WhenIGetTheRoutes()
{
_result = _repo.Get().Result.Data;
}
private void ThenTheFollowingIsReturned(FileConfiguration expecteds)
{
_result.GlobalConfiguration.RequestIdKey.ShouldBe(expecteds.GlobalConfiguration.RequestIdKey);
_result.GlobalConfiguration.ServiceDiscoveryProvider.Scheme.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Scheme);
_result.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Host);
_result.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Port);
for (var i = 0; i < _result.Routes.Count; i++)
{
for (int j = 0; j < _result.Routes[i].DownstreamHostAndPorts.Count; j++)
{
var result = _result.Routes[i].DownstreamHostAndPorts[j];
var expected = expecteds.Routes[i].DownstreamHostAndPorts[j];
result.Host.ShouldBe(expected.Host);
result.Port.ShouldBe(expected.Port);
}
_result.Routes[i].DownstreamPathTemplate.ShouldBe(expecteds.Routes[i].DownstreamPathTemplate);
_result.Routes[i].DownstreamScheme.ShouldBe(expecteds.Routes[i].DownstreamScheme);
}
}
private void AndTheChangeTokenIsActivated()
{
_changeTokenSource.Verify(m => m.Activate(), Times.Once);
}
private FileConfiguration FakeFileConfigurationForSet()
{
var routes = new List<FileRoute>
{
new FileRoute
{
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "123.12.12.12",
Port = 80,
},
},
DownstreamScheme = "https",
DownstreamPathTemplate = "/asdfs/test/{test}",
},
};
var globalConfiguration = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{
Scheme = "https",
Port = 198,
Host = "blah"
}
};
return new FileConfiguration
{
GlobalConfiguration = globalConfiguration,
Routes = routes
};
}
private FileConfiguration FakeFileConfigurationForGet()
{
var routes = new List<FileRoute>
{
new FileRoute
{
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 80,
}
},
DownstreamScheme = "https",
DownstreamPathTemplate = "/test/test/{test}"
}
};
var globalConfiguration = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{
Scheme = "https",
Port = 198,
Host = "blah"
}
};
return new FileConfiguration
{
GlobalConfiguration = globalConfiguration,
Routes = routes
};
}
public void Dispose()
{
_semaphore.Release();
}
}
}

View File

@ -1,121 +1,121 @@
using Ocelot.Configuration;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Shouldly;
using System.Collections.Generic;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration
{
public class DownstreamAddressesCreatorTests
{
public DownstreamAddressesCreator _creator;
private FileReRoute _reRoute;
private List<DownstreamHostAndPort> _result;
public DownstreamAddressesCreatorTests()
{
_creator = new DownstreamAddressesCreator();
}
[Fact]
public void should_do_nothing()
{
var reRoute = new FileReRoute
{
};
var expected = new List<DownstreamHostAndPort>
{
};
this.Given(x => GivenTheFollowingReRoute(reRoute))
.When(x => WhenICreate())
.Then(x => TheThenFollowingIsReturned(expected))
.BDDfy();
}
[Fact]
public void should_create_downstream_addresses_from_old_downstream_path_and_port()
{
var reRoute = new FileReRoute
{
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "test",
Port = 80
}
},
};
var expected = new List<DownstreamHostAndPort>
{
new DownstreamHostAndPort("test", 80),
};
this.Given(x => GivenTheFollowingReRoute(reRoute))
.When(x => WhenICreate())
.Then(x => TheThenFollowingIsReturned(expected))
.BDDfy();
}
[Fact]
public void should_create_downstream_addresses_from_downstream_host_and_ports()
{
var reRoute = new FileReRoute
{
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "test",
Port = 80
},
new FileHostAndPort
{
Host = "west",
Port = 443
}
}
};
var expected = new List<DownstreamHostAndPort>
{
new DownstreamHostAndPort("test", 80),
new DownstreamHostAndPort("west", 443)
namespace Ocelot.UnitTests.Configuration
{
using Ocelot.Configuration;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Shouldly;
using System.Collections.Generic;
using TestStack.BDDfy;
using Xunit;
public class DownstreamAddressesCreatorTests
{
public DownstreamAddressesCreator _creator;
private FileRoute _route;
private List<DownstreamHostAndPort> _result;
public DownstreamAddressesCreatorTests()
{
_creator = new DownstreamAddressesCreator();
}
[Fact]
public void should_do_nothing()
{
var route = new FileRoute
{
};
this.Given(x => GivenTheFollowingReRoute(reRoute))
.When(x => WhenICreate())
.Then(x => TheThenFollowingIsReturned(expected))
.BDDfy();
}
private void GivenTheFollowingReRoute(FileReRoute reRoute)
{
_reRoute = reRoute;
}
private void WhenICreate()
{
_result = _creator.Create(_reRoute);
}
private void TheThenFollowingIsReturned(List<DownstreamHostAndPort> expecteds)
{
_result.Count.ShouldBe(expecteds.Count);
for (int i = 0; i < _result.Count; i++)
{
var result = _result[i];
var expected = expecteds[i];
result.Host.ShouldBe(expected.Host);
result.Port.ShouldBe(expected.Port);
}
}
}
var expected = new List<DownstreamHostAndPort>
{
};
this.Given(x => GivenTheFollowingRoute(route))
.When(x => WhenICreate())
.Then(x => TheThenFollowingIsReturned(expected))
.BDDfy();
}
[Fact]
public void should_create_downstream_addresses_from_old_downstream_path_and_port()
{
var route = new FileRoute
{
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "test",
Port = 80
}
},
};
var expected = new List<DownstreamHostAndPort>
{
new DownstreamHostAndPort("test", 80),
};
this.Given(x => GivenTheFollowingRoute(route))
.When(x => WhenICreate())
.Then(x => TheThenFollowingIsReturned(expected))
.BDDfy();
}
[Fact]
public void should_create_downstream_addresses_from_downstream_host_and_ports()
{
var route = new FileRoute
{
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "test",
Port = 80
},
new FileHostAndPort
{
Host = "west",
Port = 443
}
}
};
var expected = new List<DownstreamHostAndPort>
{
new DownstreamHostAndPort("test", 80),
new DownstreamHostAndPort("west", 443)
};
this.Given(x => GivenTheFollowingRoute(route))
.When(x => WhenICreate())
.Then(x => TheThenFollowingIsReturned(expected))
.BDDfy();
}
private void GivenTheFollowingRoute(FileRoute route)
{
_route = route;
}
private void WhenICreate()
{
_result = _creator.Create(_route);
}
private void TheThenFollowingIsReturned(List<DownstreamHostAndPort> expecteds)
{
_result.Count.ShouldBe(expecteds.Count);
for (int i = 0; i < _result.Count; i++)
{
var result = _result[i];
var expected = expecteds[i];
result.Host.ShouldBe(expected.Host);
result.Port.ShouldBe(expected.Port);
}
}
}
}

View File

@ -1,148 +1,148 @@
namespace Ocelot.UnitTests.Configuration
{
using System;
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Shouldly;
using System.Collections.Generic;
using TestStack.BDDfy;
using Xunit;
public class DynamicsCreatorTests
{
private readonly DynamicsCreator _creator;
private readonly Mock<IRateLimitOptionsCreator> _rloCreator;
private readonly Mock<IVersionCreator> _versionCreator;
private List<ReRoute> _result;
private FileConfiguration _fileConfig;
private RateLimitOptions _rlo1;
private RateLimitOptions _rlo2;
private Version _version;
public DynamicsCreatorTests()
{
_versionCreator = new Mock<IVersionCreator>();
_rloCreator = new Mock<IRateLimitOptionsCreator>();
_creator = new DynamicsCreator(_rloCreator.Object, _versionCreator.Object);
}
[Fact]
public void should_return_nothing()
{
var fileConfig = new FileConfiguration();
this.Given(_ => GivenThe(fileConfig))
.When(_ => WhenICreate())
.Then(_ => ThenNothingIsReturned())
.And(_ => ThenTheRloCreatorIsNotCalled())
.BDDfy();
}
[Fact]
public void should_return_re_routes()
{
var fileConfig = new FileConfiguration
{
DynamicReRoutes = new List<FileDynamicReRoute>
{
new FileDynamicReRoute
{
ServiceName = "1",
RateLimitRule = new FileRateLimitRule
{
EnableRateLimiting = false
},
DownstreamHttpVersion = "1.1"
},
new FileDynamicReRoute
{
ServiceName = "2",
RateLimitRule = new FileRateLimitRule
{
EnableRateLimiting = true
},
DownstreamHttpVersion = "2.0"
}
}
};
this.Given(_ => GivenThe(fileConfig))
.And(_ => GivenTheRloCreatorReturns())
.And(_ => GivenTheVersionCreatorReturns())
.When(_ => WhenICreate())
.Then(_ => ThenTheReRoutesAreReturned())
.And(_ => ThenTheRloCreatorIsCalledCorrectly())
.And(_ => ThenTheVersionCreatorIsCalledCorrectly())
.BDDfy();
}
private void ThenTheRloCreatorIsCalledCorrectly()
{
_rloCreator.Verify(x => x.Create(_fileConfig.DynamicReRoutes[0].RateLimitRule,
_fileConfig.GlobalConfiguration), Times.Once);
_rloCreator.Verify(x => x.Create(_fileConfig.DynamicReRoutes[1].RateLimitRule,
_fileConfig.GlobalConfiguration), Times.Once);
}
private void ThenTheVersionCreatorIsCalledCorrectly()
{
_versionCreator.Verify(x => x.Create(_fileConfig.DynamicReRoutes[0].DownstreamHttpVersion), Times.Once);
_versionCreator.Verify(x => x.Create(_fileConfig.DynamicReRoutes[1].DownstreamHttpVersion), Times.Once);
}
private void ThenTheReRoutesAreReturned()
{
_result.Count.ShouldBe(2);
_result[0].DownstreamReRoute[0].EnableEndpointEndpointRateLimiting.ShouldBeFalse();
_result[0].DownstreamReRoute[0].RateLimitOptions.ShouldBe(_rlo1);
_result[0].DownstreamReRoute[0].DownstreamHttpVersion.ShouldBe(_version);
_result[0].DownstreamReRoute[0].ServiceName.ShouldBe(_fileConfig.DynamicReRoutes[0].ServiceName);
_result[1].DownstreamReRoute[0].EnableEndpointEndpointRateLimiting.ShouldBeTrue();
_result[1].DownstreamReRoute[0].RateLimitOptions.ShouldBe(_rlo2);
_result[1].DownstreamReRoute[0].DownstreamHttpVersion.ShouldBe(_version);
_result[1].DownstreamReRoute[0].ServiceName.ShouldBe(_fileConfig.DynamicReRoutes[1].ServiceName);
}
private void GivenTheVersionCreatorReturns()
{
_version = new Version("1.1");
_versionCreator.Setup(x => x.Create(It.IsAny<string>())).Returns(_version);
}
private void GivenTheRloCreatorReturns()
{
_rlo1 = new RateLimitOptionsBuilder().Build();
_rlo2 = new RateLimitOptionsBuilder().WithEnableRateLimiting(true).Build();
_rloCreator
.SetupSequence(x => x.Create(It.IsAny<FileRateLimitRule>(), It.IsAny<FileGlobalConfiguration>()))
.Returns(_rlo1)
.Returns(_rlo2);
}
private void ThenTheRloCreatorIsNotCalled()
{
_rloCreator.Verify(x => x.Create(It.IsAny<FileRateLimitRule>(), It.IsAny<FileGlobalConfiguration>()), Times.Never);
}
private void ThenNothingIsReturned()
{
_result.Count.ShouldBe(0);
}
private void WhenICreate()
{
_result = _creator.Create(_fileConfig);
}
private void GivenThe(FileConfiguration fileConfig)
{
_fileConfig = fileConfig;
}
}
}
namespace Ocelot.UnitTests.Configuration
{
using System;
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Shouldly;
using System.Collections.Generic;
using TestStack.BDDfy;
using Xunit;
public class DynamicsCreatorTests
{
private readonly DynamicsCreator _creator;
private readonly Mock<IRateLimitOptionsCreator> _rloCreator;
private readonly Mock<IVersionCreator> _versionCreator;
private List<Route> _result;
private FileConfiguration _fileConfig;
private RateLimitOptions _rlo1;
private RateLimitOptions _rlo2;
private Version _version;
public DynamicsCreatorTests()
{
_versionCreator = new Mock<IVersionCreator>();
_rloCreator = new Mock<IRateLimitOptionsCreator>();
_creator = new DynamicsCreator(_rloCreator.Object, _versionCreator.Object);
}
[Fact]
public void should_return_nothing()
{
var fileConfig = new FileConfiguration();
this.Given(_ => GivenThe(fileConfig))
.When(_ => WhenICreate())
.Then(_ => ThenNothingIsReturned())
.And(_ => ThenTheRloCreatorIsNotCalled())
.BDDfy();
}
[Fact]
public void should_return_re_routes()
{
var fileConfig = new FileConfiguration
{
DynamicRoutes = new List<FileDynamicRoute>
{
new FileDynamicRoute
{
ServiceName = "1",
RateLimitRule = new FileRateLimitRule
{
EnableRateLimiting = false
},
DownstreamHttpVersion = "1.1"
},
new FileDynamicRoute
{
ServiceName = "2",
RateLimitRule = new FileRateLimitRule
{
EnableRateLimiting = true
},
DownstreamHttpVersion = "2.0"
}
}
};
this.Given(_ => GivenThe(fileConfig))
.And(_ => GivenTheRloCreatorReturns())
.And(_ => GivenTheVersionCreatorReturns())
.When(_ => WhenICreate())
.Then(_ => ThenTheRoutesAreReturned())
.And(_ => ThenTheRloCreatorIsCalledCorrectly())
.And(_ => ThenTheVersionCreatorIsCalledCorrectly())
.BDDfy();
}
private void ThenTheRloCreatorIsCalledCorrectly()
{
_rloCreator.Verify(x => x.Create(_fileConfig.DynamicRoutes[0].RateLimitRule,
_fileConfig.GlobalConfiguration), Times.Once);
_rloCreator.Verify(x => x.Create(_fileConfig.DynamicRoutes[1].RateLimitRule,
_fileConfig.GlobalConfiguration), Times.Once);
}
private void ThenTheVersionCreatorIsCalledCorrectly()
{
_versionCreator.Verify(x => x.Create(_fileConfig.DynamicRoutes[0].DownstreamHttpVersion), Times.Once);
_versionCreator.Verify(x => x.Create(_fileConfig.DynamicRoutes[1].DownstreamHttpVersion), Times.Once);
}
private void ThenTheRoutesAreReturned()
{
_result.Count.ShouldBe(2);
_result[0].DownstreamRoute[0].EnableEndpointEndpointRateLimiting.ShouldBeFalse();
_result[0].DownstreamRoute[0].RateLimitOptions.ShouldBe(_rlo1);
_result[0].DownstreamRoute[0].DownstreamHttpVersion.ShouldBe(_version);
_result[0].DownstreamRoute[0].ServiceName.ShouldBe(_fileConfig.DynamicRoutes[0].ServiceName);
_result[1].DownstreamRoute[0].EnableEndpointEndpointRateLimiting.ShouldBeTrue();
_result[1].DownstreamRoute[0].RateLimitOptions.ShouldBe(_rlo2);
_result[1].DownstreamRoute[0].DownstreamHttpVersion.ShouldBe(_version);
_result[1].DownstreamRoute[0].ServiceName.ShouldBe(_fileConfig.DynamicRoutes[1].ServiceName);
}
private void GivenTheVersionCreatorReturns()
{
_version = new Version("1.1");
_versionCreator.Setup(x => x.Create(It.IsAny<string>())).Returns(_version);
}
private void GivenTheRloCreatorReturns()
{
_rlo1 = new RateLimitOptionsBuilder().Build();
_rlo2 = new RateLimitOptionsBuilder().WithEnableRateLimiting(true).Build();
_rloCreator
.SetupSequence(x => x.Create(It.IsAny<FileRateLimitRule>(), It.IsAny<FileGlobalConfiguration>()))
.Returns(_rlo1)
.Returns(_rlo2);
}
private void ThenTheRloCreatorIsNotCalled()
{
_rloCreator.Verify(x => x.Create(It.IsAny<FileRateLimitRule>(), It.IsAny<FileGlobalConfiguration>()), Times.Never);
}
private void ThenNothingIsReturned()
{
_result.Count.ShouldBe(0);
}
private void WhenICreate()
{
_result = _creator.Create(_fileConfig);
}
private void GivenThe(FileConfiguration fileConfig)
{
_fileConfig = fileConfig;
}
}
}

View File

@ -1,205 +1,205 @@
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Ocelot.Configuration.Repository;
using Ocelot.Logging;
using Ocelot.Responses;
using Ocelot.UnitTests.Responder;
using Shouldly;
using System;
using System.Collections.Generic;
using System.Threading;
using TestStack.BDDfy;
using Xunit;
using static Ocelot.Infrastructure.Wait;
namespace Ocelot.UnitTests.Configuration
{
public class FileConfigurationPollerTests : IDisposable
{
private readonly FileConfigurationPoller _poller;
private Mock<IOcelotLoggerFactory> _factory;
private readonly Mock<IFileConfigurationRepository> _repo;
private readonly FileConfiguration _fileConfig;
private Mock<IFileConfigurationPollerOptions> _config;
private readonly Mock<IInternalConfigurationRepository> _internalConfigRepo;
private readonly Mock<IInternalConfigurationCreator> _internalConfigCreator;
private IInternalConfiguration _internalConfig;
public FileConfigurationPollerTests()
{
var logger = new Mock<IOcelotLogger>();
_factory = new Mock<IOcelotLoggerFactory>();
_factory.Setup(x => x.CreateLogger<FileConfigurationPoller>()).Returns(logger.Object);
_repo = new Mock<IFileConfigurationRepository>();
_fileConfig = new FileConfiguration();
_config = new Mock<IFileConfigurationPollerOptions>();
_repo.Setup(x => x.Get()).ReturnsAsync(new OkResponse<FileConfiguration>(_fileConfig));
_config.Setup(x => x.Delay).Returns(100);
_internalConfigRepo = new Mock<IInternalConfigurationRepository>();
_internalConfigCreator = new Mock<IInternalConfigurationCreator>();
_internalConfigCreator.Setup(x => x.Create(It.IsAny<FileConfiguration>())).ReturnsAsync(new OkResponse<IInternalConfiguration>(_internalConfig));
_poller = new FileConfigurationPoller(_factory.Object, _repo.Object, _config.Object, _internalConfigRepo.Object, _internalConfigCreator.Object);
}
[Fact]
public void should_start()
{
this.Given(x => GivenPollerHasStarted())
.Given(x => ThenTheSetterIsCalled(_fileConfig, 1))
.BDDfy();
}
[Fact]
public void should_call_setter_when_gets_new_config()
{
var newConfig = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "test"
}
},
}
}
};
this.Given(x => GivenPollerHasStarted())
.Given(x => WhenTheConfigIsChanged(newConfig, 0))
.Then(x => ThenTheSetterIsCalledAtLeast(newConfig, 1))
.BDDfy();
}
[Fact]
public void should_not_poll_if_already_polling()
{
var newConfig = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "test"
}
},
}
}
};
this.Given(x => GivenPollerHasStarted())
.Given(x => WhenTheConfigIsChanged(newConfig, 10))
.Then(x => ThenTheSetterIsCalled(newConfig, 1))
.BDDfy();
}
[Fact]
public void should_do_nothing_if_call_to_provider_fails()
{
var newConfig = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "test"
}
},
}
}
};
this.Given(x => GivenPollerHasStarted())
.Given(x => WhenProviderErrors())
.Then(x => ThenTheSetterIsCalled(newConfig, 0))
.BDDfy();
}
[Fact]
public void should_dispose_cleanly_without_starting()
{
this.When(x => WhenPollerIsDisposed())
.BDDfy();
}
private void GivenPollerHasStarted()
{
_poller.StartAsync(CancellationToken.None);
}
private void WhenProviderErrors()
{
_repo
.Setup(x => x.Get())
.ReturnsAsync(new ErrorResponse<FileConfiguration>(new AnyError()));
}
private void WhenTheConfigIsChanged(FileConfiguration newConfig, int delay)
{
_repo
.Setup(x => x.Get())
.Callback(() => Thread.Sleep(delay))
.ReturnsAsync(new OkResponse<FileConfiguration>(newConfig));
}
private void WhenPollerIsDisposed()
{
_poller.Dispose();
}
private void ThenTheSetterIsCalled(FileConfiguration fileConfig, int times)
{
var result = WaitFor(4000).Until(() =>
{
try
{
_internalConfigRepo.Verify(x => x.AddOrReplace(_internalConfig), Times.Exactly(times));
_internalConfigCreator.Verify(x => x.Create(fileConfig), Times.Exactly(times));
return true;
}
catch (Exception)
{
return false;
}
});
result.ShouldBeTrue();
}
private void ThenTheSetterIsCalledAtLeast(FileConfiguration fileConfig, int times)
{
var result = WaitFor(4000).Until(() =>
{
try
{
_internalConfigRepo.Verify(x => x.AddOrReplace(_internalConfig), Times.AtLeast(times));
_internalConfigCreator.Verify(x => x.Create(fileConfig), Times.AtLeast(times));
return true;
}
catch (Exception)
{
return false;
}
});
result.ShouldBeTrue();
}
public void Dispose()
{
_poller.Dispose();
}
}
}
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Ocelot.Configuration.Repository;
using Ocelot.Logging;
using Ocelot.Responses;
using Ocelot.UnitTests.Responder;
using Shouldly;
using System;
using System.Collections.Generic;
using System.Threading;
using TestStack.BDDfy;
using Xunit;
using static Ocelot.Infrastructure.Wait;
namespace Ocelot.UnitTests.Configuration
{
public class FileConfigurationPollerTests : IDisposable
{
private readonly FileConfigurationPoller _poller;
private Mock<IOcelotLoggerFactory> _factory;
private readonly Mock<IFileConfigurationRepository> _repo;
private readonly FileConfiguration _fileConfig;
private Mock<IFileConfigurationPollerOptions> _config;
private readonly Mock<IInternalConfigurationRepository> _internalConfigRepo;
private readonly Mock<IInternalConfigurationCreator> _internalConfigCreator;
private IInternalConfiguration _internalConfig;
public FileConfigurationPollerTests()
{
var logger = new Mock<IOcelotLogger>();
_factory = new Mock<IOcelotLoggerFactory>();
_factory.Setup(x => x.CreateLogger<FileConfigurationPoller>()).Returns(logger.Object);
_repo = new Mock<IFileConfigurationRepository>();
_fileConfig = new FileConfiguration();
_config = new Mock<IFileConfigurationPollerOptions>();
_repo.Setup(x => x.Get()).ReturnsAsync(new OkResponse<FileConfiguration>(_fileConfig));
_config.Setup(x => x.Delay).Returns(100);
_internalConfigRepo = new Mock<IInternalConfigurationRepository>();
_internalConfigCreator = new Mock<IInternalConfigurationCreator>();
_internalConfigCreator.Setup(x => x.Create(It.IsAny<FileConfiguration>())).ReturnsAsync(new OkResponse<IInternalConfiguration>(_internalConfig));
_poller = new FileConfigurationPoller(_factory.Object, _repo.Object, _config.Object, _internalConfigRepo.Object, _internalConfigCreator.Object);
}
[Fact]
public void should_start()
{
this.Given(x => GivenPollerHasStarted())
.Given(x => ThenTheSetterIsCalled(_fileConfig, 1))
.BDDfy();
}
[Fact]
public void should_call_setter_when_gets_new_config()
{
var newConfig = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "test"
}
},
}
}
};
this.Given(x => GivenPollerHasStarted())
.Given(x => WhenTheConfigIsChanged(newConfig, 0))
.Then(x => ThenTheSetterIsCalledAtLeast(newConfig, 1))
.BDDfy();
}
[Fact]
public void should_not_poll_if_already_polling()
{
var newConfig = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "test"
}
},
}
}
};
this.Given(x => GivenPollerHasStarted())
.Given(x => WhenTheConfigIsChanged(newConfig, 10))
.Then(x => ThenTheSetterIsCalled(newConfig, 1))
.BDDfy();
}
[Fact]
public void should_do_nothing_if_call_to_provider_fails()
{
var newConfig = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "test"
}
},
}
}
};
this.Given(x => GivenPollerHasStarted())
.Given(x => WhenProviderErrors())
.Then(x => ThenTheSetterIsCalled(newConfig, 0))
.BDDfy();
}
[Fact]
public void should_dispose_cleanly_without_starting()
{
this.When(x => WhenPollerIsDisposed())
.BDDfy();
}
private void GivenPollerHasStarted()
{
_poller.StartAsync(CancellationToken.None);
}
private void WhenProviderErrors()
{
_repo
.Setup(x => x.Get())
.ReturnsAsync(new ErrorResponse<FileConfiguration>(new AnyError()));
}
private void WhenTheConfigIsChanged(FileConfiguration newConfig, int delay)
{
_repo
.Setup(x => x.Get())
.Callback(() => Thread.Sleep(delay))
.ReturnsAsync(new OkResponse<FileConfiguration>(newConfig));
}
private void WhenPollerIsDisposed()
{
_poller.Dispose();
}
private void ThenTheSetterIsCalled(FileConfiguration fileConfig, int times)
{
var result = WaitFor(4000).Until(() =>
{
try
{
_internalConfigRepo.Verify(x => x.AddOrReplace(_internalConfig), Times.Exactly(times));
_internalConfigCreator.Verify(x => x.Create(fileConfig), Times.Exactly(times));
return true;
}
catch (Exception)
{
return false;
}
});
result.ShouldBeTrue();
}
private void ThenTheSetterIsCalledAtLeast(FileConfiguration fileConfig, int times)
{
var result = WaitFor(4000).Until(() =>
{
try
{
_internalConfigRepo.Verify(x => x.AddOrReplace(_internalConfig), Times.AtLeast(times));
_internalConfigCreator.Verify(x => x.Create(fileConfig), Times.AtLeast(times));
return true;
}
catch (Exception)
{
return false;
}
});
result.ShouldBeTrue();
}
public void Dispose()
{
_poller.Dispose();
}
}
}

View File

@ -40,7 +40,7 @@ namespace Ocelot.UnitTests.Configuration
{
var fileConfig = new FileConfiguration();
var serviceProviderConfig = new ServiceProviderConfigurationBuilder().Build();
var config = new InternalConfiguration(new List<ReRoute>(), string.Empty, serviceProviderConfig, "asdf", new LoadBalancerOptionsBuilder().Build(), "", new QoSOptionsBuilder().Build(), new HttpHandlerOptionsBuilder().Build(), new Version("1.1"));
var config = new InternalConfiguration(new List<Route>(), string.Empty, serviceProviderConfig, "asdf", new LoadBalancerOptionsBuilder().Build(), "", new QoSOptionsBuilder().Build(), new HttpHandlerOptionsBuilder().Build(), new Version("1.1"));
this.Given(x => GivenTheFollowingConfiguration(fileConfig))
.And(x => GivenTheRepoReturns(new OkResponse()))

View File

@ -1,127 +1,127 @@
namespace Ocelot.UnitTests.Configuration
{
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Ocelot.Configuration.Validator;
using Ocelot.Errors;
using Ocelot.Responses;
using Ocelot.UnitTests.Responder;
using Shouldly;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using TestStack.BDDfy;
using Xunit;
public class FileInternalConfigurationCreatorTests
{
private readonly Mock<IConfigurationValidator> _validator;
private readonly Mock<IReRoutesCreator> _reRoutesCreator;
private readonly Mock<IAggregatesCreator> _aggregatesCreator;
private readonly Mock<IDynamicsCreator> _dynamicsCreator;
private readonly Mock<IConfigurationCreator> _configCreator;
private Response<IInternalConfiguration> _config;
private FileConfiguration _fileConfiguration;
private readonly FileInternalConfigurationCreator _creator;
private Response<IInternalConfiguration> _result;
private List<ReRoute> _reRoutes;
private List<ReRoute> _aggregates;
private List<ReRoute> _dynamics;
private InternalConfiguration _internalConfig;
public FileInternalConfigurationCreatorTests()
{
_validator = new Mock<IConfigurationValidator>();
_reRoutesCreator = new Mock<IReRoutesCreator>();
_aggregatesCreator = new Mock<IAggregatesCreator>();
_dynamicsCreator = new Mock<IDynamicsCreator>();
_configCreator = new Mock<IConfigurationCreator>();
_creator = new FileInternalConfigurationCreator(_validator.Object, _reRoutesCreator.Object, _aggregatesCreator.Object, _dynamicsCreator.Object, _configCreator.Object);
}
[Fact]
public void should_return_validation_error()
{
var fileConfiguration = new FileConfiguration();
this.Given(_ => GivenThe(fileConfiguration))
.And(_ => GivenTheValidationFails())
.When(_ => WhenICreate())
.Then(_ => ThenAnErrorIsReturned())
.BDDfy();
}
[Fact]
public void should_return_internal_configuration()
{
var fileConfiguration = new FileConfiguration();
this.Given(_ => GivenThe(fileConfiguration))
.And(_ => GivenTheValidationSucceeds())
.And(_ => GivenTheDependenciesAreSetUp())
.When(_ => WhenICreate())
.Then(_ => ThenTheDependenciesAreCalledCorrectly())
.BDDfy();
}
private void ThenTheDependenciesAreCalledCorrectly()
{
_reRoutesCreator.Verify(x => x.Create(_fileConfiguration), Times.Once);
_aggregatesCreator.Verify(x => x.Create(_fileConfiguration, _reRoutes), Times.Once);
_dynamicsCreator.Verify(x => x.Create(_fileConfiguration), Times.Once);
var mergedReRoutes = _reRoutes
.Union(_aggregates)
.Union(_dynamics)
.ToList();
_configCreator.Verify(x => x.Create(_fileConfiguration, It.Is<List<ReRoute>>(y => y.Count == mergedReRoutes.Count)), Times.Once);
}
private void GivenTheDependenciesAreSetUp()
{
_reRoutes = new List<ReRoute> { new ReRouteBuilder().Build() };
_aggregates = new List<ReRoute> { new ReRouteBuilder().Build() };
_dynamics = new List<ReRoute> { new ReRouteBuilder().Build() };
_internalConfig = new InternalConfiguration(null, "", null, "", null, "", null, null, null);
_reRoutesCreator.Setup(x => x.Create(It.IsAny<FileConfiguration>())).Returns(_reRoutes);
_aggregatesCreator.Setup(x => x.Create(It.IsAny<FileConfiguration>(), It.IsAny<List<ReRoute>>())).Returns(_aggregates);
_dynamicsCreator.Setup(x => x.Create(It.IsAny<FileConfiguration>())).Returns(_dynamics);
_configCreator.Setup(x => x.Create(It.IsAny<FileConfiguration>(), It.IsAny<List<ReRoute>>())).Returns(_internalConfig);
}
private void GivenTheValidationSucceeds()
{
var ok = new ConfigurationValidationResult(false);
var response = new OkResponse<ConfigurationValidationResult>(ok);
_validator.Setup(x => x.IsValid(It.IsAny<FileConfiguration>())).ReturnsAsync(response);
}
private void ThenAnErrorIsReturned()
{
_result.IsError.ShouldBeTrue();
}
private async Task WhenICreate()
{
_result = await _creator.Create(_fileConfiguration);
}
private void GivenTheValidationFails()
{
var error = new ConfigurationValidationResult(true, new List<Error> { new AnyError() });
var response = new OkResponse<ConfigurationValidationResult>(error);
_validator.Setup(x => x.IsValid(It.IsAny<FileConfiguration>())).ReturnsAsync(response);
}
private void GivenThe(FileConfiguration fileConfiguration)
{
_fileConfiguration = fileConfiguration;
}
}
}
namespace Ocelot.UnitTests.Configuration
{
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Ocelot.Configuration.Validator;
using Ocelot.Errors;
using Ocelot.Responses;
using Ocelot.UnitTests.Responder;
using Shouldly;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using TestStack.BDDfy;
using Xunit;
public class FileInternalConfigurationCreatorTests
{
private readonly Mock<IConfigurationValidator> _validator;
private readonly Mock<IRoutesCreator> _routesCreator;
private readonly Mock<IAggregatesCreator> _aggregatesCreator;
private readonly Mock<IDynamicsCreator> _dynamicsCreator;
private readonly Mock<IConfigurationCreator> _configCreator;
private Response<IInternalConfiguration> _config;
private FileConfiguration _fileConfiguration;
private readonly FileInternalConfigurationCreator _creator;
private Response<IInternalConfiguration> _result;
private List<Route> _routes;
private List<Route> _aggregates;
private List<Route> _dynamics;
private InternalConfiguration _internalConfig;
public FileInternalConfigurationCreatorTests()
{
_validator = new Mock<IConfigurationValidator>();
_routesCreator = new Mock<IRoutesCreator>();
_aggregatesCreator = new Mock<IAggregatesCreator>();
_dynamicsCreator = new Mock<IDynamicsCreator>();
_configCreator = new Mock<IConfigurationCreator>();
_creator = new FileInternalConfigurationCreator(_validator.Object, _routesCreator.Object, _aggregatesCreator.Object, _dynamicsCreator.Object, _configCreator.Object);
}
[Fact]
public void should_return_validation_error()
{
var fileConfiguration = new FileConfiguration();
this.Given(_ => GivenThe(fileConfiguration))
.And(_ => GivenTheValidationFails())
.When(_ => WhenICreate())
.Then(_ => ThenAnErrorIsReturned())
.BDDfy();
}
[Fact]
public void should_return_internal_configuration()
{
var fileConfiguration = new FileConfiguration();
this.Given(_ => GivenThe(fileConfiguration))
.And(_ => GivenTheValidationSucceeds())
.And(_ => GivenTheDependenciesAreSetUp())
.When(_ => WhenICreate())
.Then(_ => ThenTheDependenciesAreCalledCorrectly())
.BDDfy();
}
private void ThenTheDependenciesAreCalledCorrectly()
{
_routesCreator.Verify(x => x.Create(_fileConfiguration), Times.Once);
_aggregatesCreator.Verify(x => x.Create(_fileConfiguration, _routes), Times.Once);
_dynamicsCreator.Verify(x => x.Create(_fileConfiguration), Times.Once);
var mergedRoutes = _routes
.Union(_aggregates)
.Union(_dynamics)
.ToList();
_configCreator.Verify(x => x.Create(_fileConfiguration, It.Is<List<Route>>(y => y.Count == mergedRoutes.Count)), Times.Once);
}
private void GivenTheDependenciesAreSetUp()
{
_routes = new List<Route> { new RouteBuilder().Build() };
_aggregates = new List<Route> { new RouteBuilder().Build() };
_dynamics = new List<Route> { new RouteBuilder().Build() };
_internalConfig = new InternalConfiguration(null, "", null, "", null, "", null, null, null);
_routesCreator.Setup(x => x.Create(It.IsAny<FileConfiguration>())).Returns(_routes);
_aggregatesCreator.Setup(x => x.Create(It.IsAny<FileConfiguration>(), It.IsAny<List<Route>>())).Returns(_aggregates);
_dynamicsCreator.Setup(x => x.Create(It.IsAny<FileConfiguration>())).Returns(_dynamics);
_configCreator.Setup(x => x.Create(It.IsAny<FileConfiguration>(), It.IsAny<List<Route>>())).Returns(_internalConfig);
}
private void GivenTheValidationSucceeds()
{
var ok = new ConfigurationValidationResult(false);
var response = new OkResponse<ConfigurationValidationResult>(ok);
_validator.Setup(x => x.IsValid(It.IsAny<FileConfiguration>())).ReturnsAsync(response);
}
private void ThenAnErrorIsReturned()
{
_result.IsError.ShouldBeTrue();
}
private async Task WhenICreate()
{
_result = await _creator.Create(_fileConfiguration);
}
private void GivenTheValidationFails()
{
var error = new ConfigurationValidationResult(true, new List<Error> { new AnyError() });
var response = new OkResponse<ConfigurationValidationResult>(error);
_validator.Setup(x => x.IsValid(It.IsAny<FileConfiguration>())).ReturnsAsync(response);
}
private void GivenThe(FileConfiguration fileConfiguration)
{
_fileConfiguration = fileConfiguration;
}
}
}

View File

@ -16,7 +16,7 @@ namespace Ocelot.UnitTests.Configuration
public class HeaderFindAndReplaceCreatorTests
{
private HeaderFindAndReplaceCreator _creator;
private FileReRoute _reRoute;
private FileRoute _route;
private HeaderTransformations _result;
private Mock<IPlaceholders> _placeholders;
private Mock<IOcelotLoggerFactory> _factory;
@ -34,13 +34,13 @@ namespace Ocelot.UnitTests.Configuration
[Fact]
public void should_create()
{
var reRoute = new FileReRoute
var route = new FileRoute
{
UpstreamHeaderTransform = new Dictionary<string, string>
{
{"Test", "Test, Chicken"},
{"Moop", "o, a"}
},
},
DownstreamHeaderTransform = new Dictionary<string, string>
{
{"Pop", "West, East"},
@ -60,7 +60,7 @@ namespace Ocelot.UnitTests.Configuration
new HeaderFindAndReplace("Bop", "e", "r", 0)
};
this.Given(x => GivenTheReRoute(reRoute))
this.Given(x => GivenTheRoute(route))
.When(x => WhenICreate())
.Then(x => ThenTheFollowingUpstreamIsReturned(upstream))
.Then(x => ThenTheFollowingDownstreamIsReturned(downstream))
@ -71,19 +71,19 @@ namespace Ocelot.UnitTests.Configuration
public void should_create_with_add_headers_to_request()
{
const string key = "X-Forwarded-For";
const string value = "{RemoteIpAddress}";
const string value = "{RemoteIpAddress}";
var reRoute = new FileReRoute
var route = new FileRoute
{
UpstreamHeaderTransform = new Dictionary<string, string>
{
{key, value},
}
};
};
var expected = new AddHeader(key, value);
this.Given(x => GivenTheReRoute(reRoute))
this.Given(x => GivenTheRoute(route))
.When(x => WhenICreate())
.Then(x => ThenTheFollowingAddHeaderToUpstreamIsReturned(expected))
.BDDfy();
@ -92,8 +92,8 @@ namespace Ocelot.UnitTests.Configuration
[Fact]
public void should_use_base_url_placeholder()
{
var reRoute = new FileReRoute
{
var route = new FileRoute
{
DownstreamHeaderTransform = new Dictionary<string, string>
{
{"Location", "http://www.bbc.co.uk/, {BaseUrl}"},
@ -105,7 +105,7 @@ namespace Ocelot.UnitTests.Configuration
new HeaderFindAndReplace("Location", "http://www.bbc.co.uk/", "http://ocelot.com/", 0),
};
this.Given(x => GivenTheReRoute(reRoute))
this.Given(x => GivenTheRoute(route))
.And(x => GivenTheBaseUrlIs("http://ocelot.com/"))
.When(x => WhenICreate())
.Then(x => ThenTheFollowingDownstreamIsReturned(downstream))
@ -115,7 +115,7 @@ namespace Ocelot.UnitTests.Configuration
[Fact]
public void should_log_errors_and_not_add_headers()
{
var reRoute = new FileReRoute
var route = new FileRoute
{
DownstreamHeaderTransform = new Dictionary<string, string>
{
@ -131,7 +131,7 @@ namespace Ocelot.UnitTests.Configuration
{
};
this.Given(x => GivenTheReRoute(reRoute))
this.Given(x => GivenTheRoute(route))
.And(x => GivenTheBaseUrlErrors())
.When(x => WhenICreate())
.Then(x => ThenTheFollowingDownstreamIsReturned(expected))
@ -149,8 +149,8 @@ namespace Ocelot.UnitTests.Configuration
[Fact]
public void should_use_base_url_partial_placeholder()
{
var reRoute = new FileReRoute
{
var route = new FileRoute
{
DownstreamHeaderTransform = new Dictionary<string, string>
{
{"Location", "http://www.bbc.co.uk/pay, {BaseUrl}pay"},
@ -162,7 +162,7 @@ namespace Ocelot.UnitTests.Configuration
new HeaderFindAndReplace("Location", "http://www.bbc.co.uk/pay", "http://ocelot.com/pay", 0),
};
this.Given(x => GivenTheReRoute(reRoute))
this.Given(x => GivenTheRoute(route))
.And(x => GivenTheBaseUrlIs("http://ocelot.com/"))
.When(x => WhenICreate())
.Then(x => ThenTheFollowingDownstreamIsReturned(downstream))
@ -172,8 +172,8 @@ namespace Ocelot.UnitTests.Configuration
[Fact]
public void should_add_trace_id_header()
{
var reRoute = new FileReRoute
{
var route = new FileRoute
{
DownstreamHeaderTransform = new Dictionary<string, string>
{
{"Trace-Id", "{TraceId}"},
@ -182,7 +182,7 @@ namespace Ocelot.UnitTests.Configuration
var expected = new AddHeader("Trace-Id", "{TraceId}");
this.Given(x => GivenTheReRoute(reRoute))
this.Given(x => GivenTheRoute(route))
.And(x => GivenTheBaseUrlIs("http://ocelot.com/"))
.When(x => WhenICreate())
.Then(x => ThenTheFollowingAddHeaderToDownstreamIsReturned(expected))
@ -192,7 +192,7 @@ namespace Ocelot.UnitTests.Configuration
[Fact]
public void should_add_downstream_header_as_is_when_no_replacement_is_given()
{
var reRoute = new FileReRoute
var route = new FileRoute
{
DownstreamHeaderTransform = new Dictionary<string, string>
{
@ -202,7 +202,7 @@ namespace Ocelot.UnitTests.Configuration
var expected = new AddHeader("X-Custom-Header", "Value");
this.Given(x => GivenTheReRoute(reRoute))
this.Given(x => GivenTheRoute(route))
.And(x => WhenICreate())
.Then(x => x.ThenTheFollowingAddHeaderToDownstreamIsReturned(expected))
.BDDfy();
@ -211,7 +211,7 @@ namespace Ocelot.UnitTests.Configuration
[Fact]
public void should_add_upstream_header_as_is_when_no_replacement_is_given()
{
var reRoute = new FileReRoute
var route = new FileRoute
{
UpstreamHeaderTransform = new Dictionary<string, string>
{
@ -221,7 +221,7 @@ namespace Ocelot.UnitTests.Configuration
var expected = new AddHeader("X-Custom-Header", "Value");
this.Given(x => GivenTheReRoute(reRoute))
this.Given(x => GivenTheRoute(route))
.And(x => WhenICreate())
.Then(x => x.ThenTheFollowingAddHeaderToUpstreamIsReturned(expected))
.BDDfy();
@ -241,8 +241,8 @@ namespace Ocelot.UnitTests.Configuration
{
_result.AddHeadersToDownstream[0].Key.ShouldBe(addHeader.Key);
_result.AddHeadersToDownstream[0].Value.ShouldBe(addHeader.Value);
}
}
private void ThenTheFollowingAddHeaderToUpstreamIsReturned(AddHeader addHeader)
{
_result.AddHeadersToUpstream[0].Key.ShouldBe(addHeader.Key);
@ -251,8 +251,8 @@ namespace Ocelot.UnitTests.Configuration
private void ThenTheFollowingDownstreamIsReturned(List<HeaderFindAndReplace> downstream)
{
_result.Downstream.Count.ShouldBe(downstream.Count);
_result.Downstream.Count.ShouldBe(downstream.Count);
for (int i = 0; i < _result.Downstream.Count; i++)
{
var result = _result.Downstream[i];
@ -261,23 +261,23 @@ namespace Ocelot.UnitTests.Configuration
result.Index.ShouldBe(expected.Index);
result.Key.ShouldBe(expected.Key);
result.Replace.ShouldBe(expected.Replace);
}
}
}
private void GivenTheReRoute(FileReRoute reRoute)
private void GivenTheRoute(FileRoute route)
{
_reRoute = reRoute;
_route = route;
}
private void WhenICreate()
{
_result = _creator.Create(_reRoute);
_result = _creator.Create(_route);
}
private void ThenTheFollowingUpstreamIsReturned(List<HeaderFindAndReplace> expecteds)
{
_result.Upstream.Count.ShouldBe(expecteds.Count);
_result.Upstream.Count.ShouldBe(expecteds.Count);
for (int i = 0; i < _result.Upstream.Count; i++)
{
var result = _result.Upstream[i];
@ -289,4 +289,4 @@ namespace Ocelot.UnitTests.Configuration
}
}
}
}
}

View File

@ -1,239 +1,239 @@
using Microsoft.Extensions.DependencyInjection;
using Ocelot.Configuration;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Shouldly;
using System;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration
{
using Microsoft.AspNetCore.Http;
using Ocelot.Logging;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
public class HttpHandlerOptionsCreatorTests
{
private IHttpHandlerOptionsCreator _httpHandlerOptionsCreator;
private FileReRoute _fileReRoute;
private HttpHandlerOptions _httpHandlerOptions;
private IServiceProvider _serviceProvider;
private IServiceCollection _serviceCollection;
public HttpHandlerOptionsCreatorTests()
{
_serviceCollection = new ServiceCollection();
_serviceProvider = _serviceCollection.BuildServiceProvider();
_httpHandlerOptionsCreator = new HttpHandlerOptionsCreator(_serviceProvider);
}
[Fact]
public void should_not_use_tracing_if_fake_tracer_registered()
{
var fileReRoute = new FileReRoute
{
HttpHandlerOptions = new FileHttpHandlerOptions
{
UseTracing = true
}
};
var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue);
this.Given(x => GivenTheFollowing(fileReRoute))
.When(x => WhenICreateHttpHandlerOptions())
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
.BDDfy();
}
[Fact]
public void should_use_tracing_if_real_tracer_registered()
{
var fileReRoute = new FileReRoute
{
HttpHandlerOptions = new FileHttpHandlerOptions
{
UseTracing = true
}
};
var expectedOptions = new HttpHandlerOptions(false, false, true, true, int.MaxValue);
this.Given(x => GivenTheFollowing(fileReRoute))
.And(x => GivenARealTracer())
.When(x => WhenICreateHttpHandlerOptions())
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
.BDDfy();
}
[Fact]
public void should_create_options_with_useCookie_false_and_allowAutoRedirect_true_as_default()
{
var fileReRoute = new FileReRoute();
var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue);
this.Given(x => GivenTheFollowing(fileReRoute))
.When(x => WhenICreateHttpHandlerOptions())
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
.BDDfy();
}
[Fact]
public void should_create_options_with_specified_useCookie_and_allowAutoRedirect()
{
var fileReRoute = new FileReRoute
{
HttpHandlerOptions = new FileHttpHandlerOptions
{
AllowAutoRedirect = false,
UseCookieContainer = false,
UseTracing = false
}
};
var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue);
this.Given(x => GivenTheFollowing(fileReRoute))
.When(x => WhenICreateHttpHandlerOptions())
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
.BDDfy();
}
[Fact]
public void should_create_options_with_useproxy_true_as_default()
{
var fileReRoute = new FileReRoute
{
HttpHandlerOptions = new FileHttpHandlerOptions()
};
var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue);
this.Given(x => GivenTheFollowing(fileReRoute))
.When(x => WhenICreateHttpHandlerOptions())
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
.BDDfy();
}
[Fact]
public void should_create_options_with_specified_useproxy()
{
var fileReRoute = new FileReRoute
{
HttpHandlerOptions = new FileHttpHandlerOptions
{
UseProxy = false
}
};
var expectedOptions = new HttpHandlerOptions(false, false, false, false, int.MaxValue);
this.Given(x => GivenTheFollowing(fileReRoute))
.When(x => WhenICreateHttpHandlerOptions())
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
.BDDfy();
}
[Fact]
public void should_create_options_with_specified_MaxConnectionsPerServer()
{
var fileReRoute = new FileReRoute
{
HttpHandlerOptions = new FileHttpHandlerOptions
{
MaxConnectionsPerServer = 10
}
};
var expectedOptions = new HttpHandlerOptions(false, false, false, true, 10);
this.Given(x => GivenTheFollowing(fileReRoute))
.When(x => WhenICreateHttpHandlerOptions())
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
.BDDfy();
}
[Fact]
public void should_create_options_fixing_specified_MaxConnectionsPerServer_range()
{
var fileReRoute = new FileReRoute
{
HttpHandlerOptions = new FileHttpHandlerOptions
{
MaxConnectionsPerServer = -1
}
};
var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue);
this.Given(x => GivenTheFollowing(fileReRoute))
.When(x => WhenICreateHttpHandlerOptions())
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
.BDDfy();
}
[Fact]
public void should_create_options_fixing_specified_MaxConnectionsPerServer_range_when_zero()
{
var fileReRoute = new FileReRoute
{
HttpHandlerOptions = new FileHttpHandlerOptions
{
MaxConnectionsPerServer = 0
}
};
var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue);
this.Given(x => GivenTheFollowing(fileReRoute))
.When(x => WhenICreateHttpHandlerOptions())
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
.BDDfy();
}
private void GivenTheFollowing(FileReRoute fileReRoute)
{
_fileReRoute = fileReRoute;
}
private void WhenICreateHttpHandlerOptions()
{
_httpHandlerOptions = _httpHandlerOptionsCreator.Create(_fileReRoute.HttpHandlerOptions);
}
private void ThenTheFollowingOptionsReturned(HttpHandlerOptions expected)
{
_httpHandlerOptions.ShouldNotBeNull();
_httpHandlerOptions.AllowAutoRedirect.ShouldBe(expected.AllowAutoRedirect);
_httpHandlerOptions.UseCookieContainer.ShouldBe(expected.UseCookieContainer);
_httpHandlerOptions.UseTracing.ShouldBe(expected.UseTracing);
_httpHandlerOptions.UseProxy.ShouldBe(expected.UseProxy);
_httpHandlerOptions.MaxConnectionsPerServer.ShouldBe(expected.MaxConnectionsPerServer);
}
private void GivenARealTracer()
{
var tracer = new FakeTracer();
_serviceCollection.AddSingleton<ITracer, FakeTracer>();
_serviceProvider = _serviceCollection.BuildServiceProvider();
_httpHandlerOptionsCreator = new HttpHandlerOptionsCreator(_serviceProvider);
}
private class FakeTracer : ITracer
{
public void Event(HttpContext httpContext, string @event)
{
throw new NotImplementedException();
}
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken, Action<string> addTraceIdToRepo,
Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> baseSendAsync)
{
throw new NotImplementedException();
}
}
}
}
using Microsoft.Extensions.DependencyInjection;
using Ocelot.Configuration;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Shouldly;
using System;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration
{
using Microsoft.AspNetCore.Http;
using Ocelot.Logging;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
public class HttpHandlerOptionsCreatorTests
{
private IHttpHandlerOptionsCreator _httpHandlerOptionsCreator;
private FileRoute _fileRoute;
private HttpHandlerOptions _httpHandlerOptions;
private IServiceProvider _serviceProvider;
private IServiceCollection _serviceCollection;
public HttpHandlerOptionsCreatorTests()
{
_serviceCollection = new ServiceCollection();
_serviceProvider = _serviceCollection.BuildServiceProvider();
_httpHandlerOptionsCreator = new HttpHandlerOptionsCreator(_serviceProvider);
}
[Fact]
public void should_not_use_tracing_if_fake_tracer_registered()
{
var fileRoute = new FileRoute
{
HttpHandlerOptions = new FileHttpHandlerOptions
{
UseTracing = true
}
};
var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue);
this.Given(x => GivenTheFollowing(fileRoute))
.When(x => WhenICreateHttpHandlerOptions())
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
.BDDfy();
}
[Fact]
public void should_use_tracing_if_real_tracer_registered()
{
var fileRoute = new FileRoute
{
HttpHandlerOptions = new FileHttpHandlerOptions
{
UseTracing = true
}
};
var expectedOptions = new HttpHandlerOptions(false, false, true, true, int.MaxValue);
this.Given(x => GivenTheFollowing(fileRoute))
.And(x => GivenARealTracer())
.When(x => WhenICreateHttpHandlerOptions())
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
.BDDfy();
}
[Fact]
public void should_create_options_with_useCookie_false_and_allowAutoRedirect_true_as_default()
{
var fileRoute = new FileRoute();
var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue);
this.Given(x => GivenTheFollowing(fileRoute))
.When(x => WhenICreateHttpHandlerOptions())
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
.BDDfy();
}
[Fact]
public void should_create_options_with_specified_useCookie_and_allowAutoRedirect()
{
var fileRoute = new FileRoute
{
HttpHandlerOptions = new FileHttpHandlerOptions
{
AllowAutoRedirect = false,
UseCookieContainer = false,
UseTracing = false
}
};
var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue);
this.Given(x => GivenTheFollowing(fileRoute))
.When(x => WhenICreateHttpHandlerOptions())
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
.BDDfy();
}
[Fact]
public void should_create_options_with_useproxy_true_as_default()
{
var fileRoute = new FileRoute
{
HttpHandlerOptions = new FileHttpHandlerOptions()
};
var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue);
this.Given(x => GivenTheFollowing(fileRoute))
.When(x => WhenICreateHttpHandlerOptions())
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
.BDDfy();
}
[Fact]
public void should_create_options_with_specified_useproxy()
{
var fileRoute = new FileRoute
{
HttpHandlerOptions = new FileHttpHandlerOptions
{
UseProxy = false
}
};
var expectedOptions = new HttpHandlerOptions(false, false, false, false, int.MaxValue);
this.Given(x => GivenTheFollowing(fileRoute))
.When(x => WhenICreateHttpHandlerOptions())
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
.BDDfy();
}
[Fact]
public void should_create_options_with_specified_MaxConnectionsPerServer()
{
var fileRoute = new FileRoute
{
HttpHandlerOptions = new FileHttpHandlerOptions
{
MaxConnectionsPerServer = 10
}
};
var expectedOptions = new HttpHandlerOptions(false, false, false, true, 10);
this.Given(x => GivenTheFollowing(fileRoute))
.When(x => WhenICreateHttpHandlerOptions())
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
.BDDfy();
}
[Fact]
public void should_create_options_fixing_specified_MaxConnectionsPerServer_range()
{
var fileRoute = new FileRoute
{
HttpHandlerOptions = new FileHttpHandlerOptions
{
MaxConnectionsPerServer = -1
}
};
var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue);
this.Given(x => GivenTheFollowing(fileRoute))
.When(x => WhenICreateHttpHandlerOptions())
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
.BDDfy();
}
[Fact]
public void should_create_options_fixing_specified_MaxConnectionsPerServer_range_when_zero()
{
var fileRoute = new FileRoute
{
HttpHandlerOptions = new FileHttpHandlerOptions
{
MaxConnectionsPerServer = 0
}
};
var expectedOptions = new HttpHandlerOptions(false, false, false, true, int.MaxValue);
this.Given(x => GivenTheFollowing(fileRoute))
.When(x => WhenICreateHttpHandlerOptions())
.Then(x => ThenTheFollowingOptionsReturned(expectedOptions))
.BDDfy();
}
private void GivenTheFollowing(FileRoute fileRoute)
{
_fileRoute = fileRoute;
}
private void WhenICreateHttpHandlerOptions()
{
_httpHandlerOptions = _httpHandlerOptionsCreator.Create(_fileRoute.HttpHandlerOptions);
}
private void ThenTheFollowingOptionsReturned(HttpHandlerOptions expected)
{
_httpHandlerOptions.ShouldNotBeNull();
_httpHandlerOptions.AllowAutoRedirect.ShouldBe(expected.AllowAutoRedirect);
_httpHandlerOptions.UseCookieContainer.ShouldBe(expected.UseCookieContainer);
_httpHandlerOptions.UseTracing.ShouldBe(expected.UseTracing);
_httpHandlerOptions.UseProxy.ShouldBe(expected.UseProxy);
_httpHandlerOptions.MaxConnectionsPerServer.ShouldBe(expected.MaxConnectionsPerServer);
}
private void GivenARealTracer()
{
var tracer = new FakeTracer();
_serviceCollection.AddSingleton<ITracer, FakeTracer>();
_serviceProvider = _serviceCollection.BuildServiceProvider();
_httpHandlerOptionsCreator = new HttpHandlerOptionsCreator(_serviceProvider);
}
private class FakeTracer : ITracer
{
public void Event(HttpContext httpContext, string @event)
{
throw new NotImplementedException();
}
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken, Action<string> addTraceIdToRepo,
Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> baseSendAsync)
{
throw new NotImplementedException();
}
}
}
}

View File

@ -48,7 +48,7 @@ namespace Ocelot.UnitTests.Configuration
private void ThenTheConfigurationIsReturned()
{
_getResult.Data.ReRoutes[0].DownstreamReRoute[0].DownstreamPathTemplate.Value.ShouldBe("initial");
_getResult.Data.Routes[0].DownstreamRoute[0].DownstreamPathTemplate.Value.ShouldBe("initial");
}
private void WhenIGetTheConfiguration()
@ -92,19 +92,19 @@ namespace Ocelot.UnitTests.Configuration
AdministrationPath = administrationPath;
}
public List<ReRoute> ReRoutes
public List<Route> Routes
{
get
{
var downstreamReRoute = new DownstreamReRouteBuilder()
var downstreamRoute = new DownstreamRouteBuilder()
.WithDownstreamPathTemplate(_downstreamTemplatePath)
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build();
return new List<ReRoute>
return new List<Route>
{
new ReRouteBuilder()
.WithDownstreamReRoute(downstreamReRoute)
new RouteBuilder()
.WithDownstreamRoute(downstreamRoute)
.WithUpstreamHttpMethod(new List<string> {"Get"})
.Build()
};

View File

@ -11,22 +11,22 @@ namespace Ocelot.UnitTests.Configuration
public class QoSOptionsCreatorTests
{
private QoSOptionsCreator _creator;
private FileReRoute _fileReRoute;
private FileRoute _fileRoute;
private QoSOptions _result;
public QoSOptionsCreatorTests()
{
_creator = new QoSOptionsCreator();
}
}
[Fact]
public void should_create_qos_options()
{
var reRoute = new FileReRoute
var route = new FileRoute
{
QoSOptions = new FileQoSOptions
{
ExceptionsAllowedBeforeBreaking = 1,
ExceptionsAllowedBeforeBreaking = 1,
DurationOfBreak = 1,
TimeoutValue = 1
}
@ -37,20 +37,20 @@ namespace Ocelot.UnitTests.Configuration
.WithTimeoutValue(1)
.Build();
this.Given(x => x.GivenTheFollowingReRoute(reRoute))
this.Given(x => x.GivenTheFollowingRoute(route))
.When(x => x.WhenICreate())
.Then(x => x.ThenTheFollowingIsReturned(expected))
.BDDfy();
}
private void GivenTheFollowingReRoute(FileReRoute fileReRoute)
private void GivenTheFollowingRoute(FileRoute fileRoute)
{
_fileReRoute = fileReRoute;
_fileRoute = fileRoute;
}
private void WhenICreate()
{
_result = _creator.Create(_fileReRoute.QoSOptions);
_result = _creator.Create(_fileRoute.QoSOptions);
}
private void ThenTheFollowingIsReturned(QoSOptions expected)
@ -60,4 +60,4 @@ namespace Ocelot.UnitTests.Configuration
_result.TimeoutValue.ShouldBe(expected.TimeoutValue);
}
}
}
}

View File

@ -1,106 +1,106 @@
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Shouldly;
using System;
using System.Collections.Generic;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration
{
public class RateLimitOptionsCreatorTests
{
private FileReRoute _fileReRoute;
private FileGlobalConfiguration _fileGlobalConfig;
private bool _enabled;
private RateLimitOptionsCreator _creator;
private RateLimitOptions _result;
public RateLimitOptionsCreatorTests()
{
_creator = new RateLimitOptionsCreator();
}
[Fact]
public void should_create_rate_limit_options()
{
var fileReRoute = new FileReRoute
{
RateLimitOptions = new FileRateLimitRule
{
ClientWhitelist = new List<string>(),
Period = "Period",
Limit = 1,
PeriodTimespan = 1,
EnableRateLimiting = true
}
};
var fileGlobalConfig = new FileGlobalConfiguration
{
RateLimitOptions = new FileRateLimitOptions
{
ClientIdHeader = "ClientIdHeader",
DisableRateLimitHeaders = true,
QuotaExceededMessage = "QuotaExceededMessage",
RateLimitCounterPrefix = "RateLimitCounterPrefix",
HttpStatusCode = 200
}
};
var expected = new RateLimitOptionsBuilder()
.WithClientIdHeader("ClientIdHeader")
.WithClientWhiteList(() => fileReRoute.RateLimitOptions.ClientWhitelist)
.WithDisableRateLimitHeaders(true)
.WithEnableRateLimiting(true)
.WithHttpStatusCode(200)
.WithQuotaExceededMessage("QuotaExceededMessage")
.WithRateLimitCounterPrefix("RateLimitCounterPrefix")
.WithRateLimitRule(new RateLimitRule(fileReRoute.RateLimitOptions.Period,
fileReRoute.RateLimitOptions.PeriodTimespan,
fileReRoute.RateLimitOptions.Limit))
.Build();
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.And(x => x.GivenTheFollowingFileGlobalConfig(fileGlobalConfig))
.And(x => x.GivenRateLimitingIsEnabled())
.When(x => x.WhenICreate())
.Then(x => x.ThenTheFollowingIsReturned(expected))
.BDDfy();
}
private void GivenTheFollowingFileReRoute(FileReRoute fileReRoute)
{
_fileReRoute = fileReRoute;
}
private void GivenTheFollowingFileGlobalConfig(FileGlobalConfiguration fileGlobalConfig)
{
_fileGlobalConfig = fileGlobalConfig;
}
private void GivenRateLimitingIsEnabled()
{
_enabled = true;
}
private void WhenICreate()
{
_result = _creator.Create(_fileReRoute.RateLimitOptions, _fileGlobalConfig);
}
private void ThenTheFollowingIsReturned(RateLimitOptions expected)
{
_result.ClientIdHeader.ShouldBe(expected.ClientIdHeader);
_result.ClientWhitelist.ShouldBe(expected.ClientWhitelist);
_result.DisableRateLimitHeaders.ShouldBe(expected.DisableRateLimitHeaders);
_result.EnableRateLimiting.ShouldBe(expected.EnableRateLimiting);
_result.HttpStatusCode.ShouldBe(expected.HttpStatusCode);
_result.QuotaExceededMessage.ShouldBe(expected.QuotaExceededMessage);
_result.RateLimitCounterPrefix.ShouldBe(expected.RateLimitCounterPrefix);
_result.RateLimitRule.Limit.ShouldBe(expected.RateLimitRule.Limit);
_result.RateLimitRule.Period.ShouldBe(expected.RateLimitRule.Period);
TimeSpan.FromSeconds(_result.RateLimitRule.PeriodTimespan).Ticks.ShouldBe(TimeSpan.FromSeconds(expected.RateLimitRule.PeriodTimespan).Ticks);
}
}
}
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Shouldly;
using System;
using System.Collections.Generic;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration
{
public class RateLimitOptionsCreatorTests
{
private FileRoute _fileRoute;
private FileGlobalConfiguration _fileGlobalConfig;
private bool _enabled;
private RateLimitOptionsCreator _creator;
private RateLimitOptions _result;
public RateLimitOptionsCreatorTests()
{
_creator = new RateLimitOptionsCreator();
}
[Fact]
public void should_create_rate_limit_options()
{
var fileRoute = new FileRoute
{
RateLimitOptions = new FileRateLimitRule
{
ClientWhitelist = new List<string>(),
Period = "Period",
Limit = 1,
PeriodTimespan = 1,
EnableRateLimiting = true
}
};
var fileGlobalConfig = new FileGlobalConfiguration
{
RateLimitOptions = new FileRateLimitOptions
{
ClientIdHeader = "ClientIdHeader",
DisableRateLimitHeaders = true,
QuotaExceededMessage = "QuotaExceededMessage",
RateLimitCounterPrefix = "RateLimitCounterPrefix",
HttpStatusCode = 200
}
};
var expected = new RateLimitOptionsBuilder()
.WithClientIdHeader("ClientIdHeader")
.WithClientWhiteList(() => fileRoute.RateLimitOptions.ClientWhitelist)
.WithDisableRateLimitHeaders(true)
.WithEnableRateLimiting(true)
.WithHttpStatusCode(200)
.WithQuotaExceededMessage("QuotaExceededMessage")
.WithRateLimitCounterPrefix("RateLimitCounterPrefix")
.WithRateLimitRule(new RateLimitRule(fileRoute.RateLimitOptions.Period,
fileRoute.RateLimitOptions.PeriodTimespan,
fileRoute.RateLimitOptions.Limit))
.Build();
this.Given(x => x.GivenTheFollowingFileRoute(fileRoute))
.And(x => x.GivenTheFollowingFileGlobalConfig(fileGlobalConfig))
.And(x => x.GivenRateLimitingIsEnabled())
.When(x => x.WhenICreate())
.Then(x => x.ThenTheFollowingIsReturned(expected))
.BDDfy();
}
private void GivenTheFollowingFileRoute(FileRoute fileRoute)
{
_fileRoute = fileRoute;
}
private void GivenTheFollowingFileGlobalConfig(FileGlobalConfiguration fileGlobalConfig)
{
_fileGlobalConfig = fileGlobalConfig;
}
private void GivenRateLimitingIsEnabled()
{
_enabled = true;
}
private void WhenICreate()
{
_result = _creator.Create(_fileRoute.RateLimitOptions, _fileGlobalConfig);
}
private void ThenTheFollowingIsReturned(RateLimitOptions expected)
{
_result.ClientIdHeader.ShouldBe(expected.ClientIdHeader);
_result.ClientWhitelist.ShouldBe(expected.ClientWhitelist);
_result.DisableRateLimitHeaders.ShouldBe(expected.DisableRateLimitHeaders);
_result.EnableRateLimiting.ShouldBe(expected.EnableRateLimiting);
_result.HttpStatusCode.ShouldBe(expected.HttpStatusCode);
_result.QuotaExceededMessage.ShouldBe(expected.QuotaExceededMessage);
_result.RateLimitCounterPrefix.ShouldBe(expected.RateLimitCounterPrefix);
_result.RateLimitRule.Limit.ShouldBe(expected.RateLimitRule.Limit);
_result.RateLimitRule.Period.ShouldBe(expected.RateLimitRule.Period);
TimeSpan.FromSeconds(_result.RateLimitRule.PeriodTimespan).Ticks.ShouldBe(TimeSpan.FromSeconds(expected.RateLimitRule.PeriodTimespan).Ticks);
}
}
}

View File

@ -8,7 +8,7 @@ namespace Ocelot.UnitTests.Configuration
{
public class RequestIdKeyCreatorTests
{
private FileReRoute _fileReRoute;
private FileRoute _fileRoute;
private FileGlobalConfiguration _fileGlobalConfig;
private string _result;
private RequestIdKeyCreator _creator;
@ -21,13 +21,13 @@ namespace Ocelot.UnitTests.Configuration
[Fact]
public void should_use_global_configuration()
{
var reRoute = new FileReRoute();
var route = new FileRoute();
var globalConfig = new FileGlobalConfiguration
{
RequestIdKey = "cheese"
};
this.Given(x => x.GivenTheFollowingReRoute(reRoute))
this.Given(x => x.GivenTheFollowingRoute(route))
.And(x => x.GivenTheFollowingGlobalConfig(globalConfig))
.When(x => x.WhenICreate())
.Then(x => x.ThenTheFollowingIsReturned("cheese"))
@ -37,13 +37,13 @@ namespace Ocelot.UnitTests.Configuration
[Fact]
public void should_use_re_route_specific()
{
var reRoute = new FileReRoute
var route = new FileRoute
{
RequestIdKey = "cheese"
};
var globalConfig = new FileGlobalConfiguration();
this.Given(x => x.GivenTheFollowingReRoute(reRoute))
this.Given(x => x.GivenTheFollowingRoute(route))
.And(x => x.GivenTheFollowingGlobalConfig(globalConfig))
.When(x => x.WhenICreate())
.Then(x => x.ThenTheFollowingIsReturned("cheese"))
@ -53,25 +53,25 @@ namespace Ocelot.UnitTests.Configuration
[Fact]
public void should_use_re_route_over_global_specific()
{
var reRoute = new FileReRoute
var route = new FileRoute
{
RequestIdKey = "cheese"
};
};
var globalConfig = new FileGlobalConfiguration
{
RequestIdKey = "test"
};
this.Given(x => x.GivenTheFollowingReRoute(reRoute))
this.Given(x => x.GivenTheFollowingRoute(route))
.And(x => x.GivenTheFollowingGlobalConfig(globalConfig))
.When(x => x.WhenICreate())
.Then(x => x.ThenTheFollowingIsReturned("cheese"))
.BDDfy();
}
private void GivenTheFollowingReRoute(FileReRoute fileReRoute)
private void GivenTheFollowingRoute(FileRoute fileRoute)
{
_fileReRoute = fileReRoute;
_fileRoute = fileRoute;
}
private void GivenTheFollowingGlobalConfig(FileGlobalConfiguration globalConfig)
@ -81,7 +81,7 @@ namespace Ocelot.UnitTests.Configuration
private void WhenICreate()
{
_result = _creator.Create(_fileReRoute, _fileGlobalConfig);
_result = _creator.Create(_fileRoute, _fileGlobalConfig);
}
private void ThenTheFollowingIsReturned(string expected)
@ -89,4 +89,4 @@ namespace Ocelot.UnitTests.Configuration
_result.ShouldBe(expected);
}
}
}
}

View File

@ -1,84 +1,84 @@
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Ocelot.LoadBalancer.LoadBalancers;
using Shouldly;
using System.Collections.Generic;
using System.Linq;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration
{
public class ReRouteKeyCreatorTests
{
private ReRouteKeyCreator _creator;
private FileReRoute _reRoute;
private string _result;
public ReRouteKeyCreatorTests()
{
_creator = new ReRouteKeyCreator();
}
[Fact]
public void should_return_sticky_session_key()
{
var reRoute = new FileReRoute
{
LoadBalancerOptions = new FileLoadBalancerOptions
{
Key = "testy",
Type = nameof(CookieStickySessions)
}
};
this.Given(_ => GivenThe(reRoute))
.When(_ => WhenICreate())
.Then(_ => ThenTheResultIs($"{nameof(CookieStickySessions)}:{reRoute.LoadBalancerOptions.Key}"))
.BDDfy();
}
[Fact]
public void should_return_re_route_key()
{
var reRoute = new FileReRoute
{
UpstreamPathTemplate = "/api/product",
UpstreamHttpMethod = new List<string> { "GET", "POST", "PUT" },
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 123
},
new FileHostAndPort
{
Host = "localhost",
Port = 123
}
}
};
this.Given(_ => GivenThe(reRoute))
.When(_ => WhenICreate())
.Then(_ => ThenTheResultIs($"{reRoute.UpstreamPathTemplate}|{string.Join(",", reRoute.UpstreamHttpMethod)}|{string.Join(",", reRoute.DownstreamHostAndPorts.Select(x => $"{x.Host}:{x.Port}"))}"))
.BDDfy();
}
private void GivenThe(FileReRoute reRoute)
{
_reRoute = reRoute;
}
private void WhenICreate()
{
_result = _creator.Create(_reRoute);
}
private void ThenTheResultIs(string expected)
{
_result.ShouldBe(expected);
}
}
}
namespace Ocelot.UnitTests.Configuration
{
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Ocelot.LoadBalancer.LoadBalancers;
using Shouldly;
using System.Collections.Generic;
using System.Linq;
using TestStack.BDDfy;
using Xunit;
public class RouteKeyCreatorTests
{
private RouteKeyCreator _creator;
private FileRoute _route;
private string _result;
public RouteKeyCreatorTests()
{
_creator = new RouteKeyCreator();
}
[Fact]
public void should_return_sticky_session_key()
{
var route = new FileRoute
{
LoadBalancerOptions = new FileLoadBalancerOptions
{
Key = "testy",
Type = nameof(CookieStickySessions)
}
};
this.Given(_ => GivenThe(route))
.When(_ => WhenICreate())
.Then(_ => ThenTheResultIs($"{nameof(CookieStickySessions)}:{route.LoadBalancerOptions.Key}"))
.BDDfy();
}
[Fact]
public void should_return_re_route_key()
{
var route = new FileRoute
{
UpstreamPathTemplate = "/api/product",
UpstreamHttpMethod = new List<string> { "GET", "POST", "PUT" },
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 123
},
new FileHostAndPort
{
Host = "localhost",
Port = 123
}
}
};
this.Given(_ => GivenThe(route))
.When(_ => WhenICreate())
.Then(_ => ThenTheResultIs($"{route.UpstreamPathTemplate}|{string.Join(",", route.UpstreamHttpMethod)}|{string.Join(",", route.DownstreamHostAndPorts.Select(x => $"{x.Host}:{x.Port}"))}"))
.BDDfy();
}
private void GivenThe(FileRoute route)
{
_route = route;
}
private void WhenICreate()
{
_result = _creator.Create(_route);
}
private void ThenTheResultIs(string expected)
{
_result.ShouldBe(expected);
}
}
}

View File

@ -1,80 +1,80 @@
namespace Ocelot.UnitTests.Configuration
{
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Shouldly;
using System.Collections.Generic;
using TestStack.BDDfy;
using Xunit;
public class ReRouteOptionsCreatorTests
{
private readonly ReRouteOptionsCreator _creator;
private FileReRoute _reRoute;
private ReRouteOptions _result;
public ReRouteOptionsCreatorTests()
{
_creator = new ReRouteOptionsCreator();
}
[Fact]
public void should_create_re_route_options()
{
var reRoute = new FileReRoute
{
RateLimitOptions = new FileRateLimitRule
{
EnableRateLimiting = true
},
AuthenticationOptions = new FileAuthenticationOptions()
{
AuthenticationProviderKey = "Test"
},
RouteClaimsRequirement = new Dictionary<string, string>()
{
{"",""}
},
FileCacheOptions = new FileCacheOptions
{
TtlSeconds = 1
},
ServiceName = "west"
};
var expected = new ReRouteOptionsBuilder()
.WithIsAuthenticated(true)
.WithIsAuthorised(true)
.WithIsCached(true)
.WithRateLimiting(true)
.WithUseServiceDiscovery(true)
.Build();
this.Given(x => x.GivenTheFollowing(reRoute))
.When(x => x.WhenICreate())
.Then(x => x.ThenTheFollowingIsReturned(expected))
.BDDfy();
}
private void GivenTheFollowing(FileReRoute reRoute)
{
_reRoute = reRoute;
}
private void WhenICreate()
{
_result = _creator.Create(_reRoute);
}
private void ThenTheFollowingIsReturned(ReRouteOptions expected)
{
_result.IsAuthenticated.ShouldBe(expected.IsAuthenticated);
_result.IsAuthorised.ShouldBe(expected.IsAuthorised);
_result.IsCached.ShouldBe(expected.IsCached);
_result.EnableRateLimiting.ShouldBe(expected.EnableRateLimiting);
_result.UseServiceDiscovery.ShouldBe(expected.UseServiceDiscovery);
}
}
}
namespace Ocelot.UnitTests.Configuration
{
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Shouldly;
using System.Collections.Generic;
using TestStack.BDDfy;
using Xunit;
public class RouteOptionsCreatorTests
{
private readonly RouteOptionsCreator _creator;
private FileRoute _route;
private RouteOptions _result;
public RouteOptionsCreatorTests()
{
_creator = new RouteOptionsCreator();
}
[Fact]
public void should_create_re_route_options()
{
var route = new FileRoute
{
RateLimitOptions = new FileRateLimitRule
{
EnableRateLimiting = true
},
AuthenticationOptions = new FileAuthenticationOptions()
{
AuthenticationProviderKey = "Test"
},
RouteClaimsRequirement = new Dictionary<string, string>()
{
{"",""}
},
FileCacheOptions = new FileCacheOptions
{
TtlSeconds = 1
},
ServiceName = "west"
};
var expected = new RouteOptionsBuilder()
.WithIsAuthenticated(true)
.WithIsAuthorised(true)
.WithIsCached(true)
.WithRateLimiting(true)
.WithUseServiceDiscovery(true)
.Build();
this.Given(x => x.GivenTheFollowing(route))
.When(x => x.WhenICreate())
.Then(x => x.ThenTheFollowingIsReturned(expected))
.BDDfy();
}
private void GivenTheFollowing(FileRoute route)
{
_route = route;
}
private void WhenICreate()
{
_result = _creator.Create(_route);
}
private void ThenTheFollowingIsReturned(RouteOptions expected)
{
_result.IsAuthenticated.ShouldBe(expected.IsAuthenticated);
_result.IsAuthorised.ShouldBe(expected.IsAuthorised);
_result.IsCached.ShouldBe(expected.IsCached);
_result.EnableRateLimiting.ShouldBe(expected.EnableRateLimiting);
_result.UseServiceDiscovery.ShouldBe(expected.UseServiceDiscovery);
}
}
}

View File

@ -1,283 +1,283 @@
namespace Ocelot.UnitTests.Configuration
{
using System;
using Moq;
using Ocelot.Cache;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Ocelot.Values;
using Shouldly;
using System.Collections.Generic;
using System.Linq;
using TestStack.BDDfy;
using Xunit;
public class ReRoutesCreatorTests
{
private ReRoutesCreator _creator;
private Mock<IClaimsToThingCreator> _cthCreator;
private Mock<IAuthenticationOptionsCreator> _aoCreator;
private Mock<IUpstreamTemplatePatternCreator> _utpCreator;
private Mock<IRequestIdKeyCreator> _ridkCreator;
private Mock<IQoSOptionsCreator> _qosoCreator;
private Mock<IReRouteOptionsCreator> _rroCreator;
private Mock<IRateLimitOptionsCreator> _rloCreator;
private Mock<IRegionCreator> _rCreator;
private Mock<IHttpHandlerOptionsCreator> _hhoCreator;
private Mock<IHeaderFindAndReplaceCreator> _hfarCreator;
private Mock<IDownstreamAddressesCreator> _daCreator;
private Mock<ILoadBalancerOptionsCreator> _lboCreator;
private Mock<IReRouteKeyCreator> _rrkCreator;
private Mock<ISecurityOptionsCreator> _soCreator;
private Mock<IVersionCreator> _versionCreator;
private FileConfiguration _fileConfig;
private ReRouteOptions _rro;
private string _requestId;
private string _rrk;
private UpstreamPathTemplate _upt;
private AuthenticationOptions _ao;
private List<ClaimToThing> _ctt;
private QoSOptions _qoso;
private RateLimitOptions _rlo;
private string _region;
private HttpHandlerOptions _hho;
private HeaderTransformations _ht;
private List<DownstreamHostAndPort> _dhp;
private LoadBalancerOptions _lbo;
private List<ReRoute> _result;
private SecurityOptions _securityOptions;
private Version _expectedVersion;
public ReRoutesCreatorTests()
{
_cthCreator = new Mock<IClaimsToThingCreator>();
_aoCreator = new Mock<IAuthenticationOptionsCreator>();
_utpCreator = new Mock<IUpstreamTemplatePatternCreator>();
_ridkCreator = new Mock<IRequestIdKeyCreator>();
_qosoCreator = new Mock<IQoSOptionsCreator>();
_rroCreator = new Mock<IReRouteOptionsCreator>();
_rloCreator = new Mock<IRateLimitOptionsCreator>();
_rCreator = new Mock<IRegionCreator>();
_hhoCreator = new Mock<IHttpHandlerOptionsCreator>();
_hfarCreator = new Mock<IHeaderFindAndReplaceCreator>();
_daCreator = new Mock<IDownstreamAddressesCreator>();
_lboCreator = new Mock<ILoadBalancerOptionsCreator>();
_rrkCreator = new Mock<IReRouteKeyCreator>();
_soCreator = new Mock<ISecurityOptionsCreator>();
_versionCreator = new Mock<IVersionCreator>();
_creator = new ReRoutesCreator(
_cthCreator.Object,
_aoCreator.Object,
_utpCreator.Object,
_ridkCreator.Object,
_qosoCreator.Object,
_rroCreator.Object,
_rloCreator.Object,
_rCreator.Object,
_hhoCreator.Object,
_hfarCreator.Object,
_daCreator.Object,
_lboCreator.Object,
_rrkCreator.Object,
_soCreator.Object,
_versionCreator.Object
);
}
[Fact]
public void should_return_nothing()
{
var fileConfig = new FileConfiguration();
this.Given(_ => GivenThe(fileConfig))
.When(_ => WhenICreate())
.Then(_ => ThenNoReRoutesAreReturned())
.BDDfy();
}
[Fact]
public void should_return_re_routes()
{
var fileConfig = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
ServiceName = "dave",
DangerousAcceptAnyServerCertificateValidator = true,
AddClaimsToRequest = new Dictionary<string, string>
{
{ "a","b" }
},
AddHeadersToRequest = new Dictionary<string, string>
{
{ "c","d" }
},
AddQueriesToRequest = new Dictionary<string, string>
{
{ "e","f" }
},
UpstreamHttpMethod = new List<string> { "GET", "POST" }
},
new FileReRoute
{
ServiceName = "wave",
DangerousAcceptAnyServerCertificateValidator = false,
AddClaimsToRequest = new Dictionary<string, string>
{
{ "g","h" }
},
AddHeadersToRequest = new Dictionary<string, string>
{
{ "i","j" }
},
AddQueriesToRequest = new Dictionary<string, string>
{
{ "k","l" }
},
UpstreamHttpMethod = new List<string> { "PUT", "DELETE" }
}
}
};
this.Given(_ => GivenThe(fileConfig))
.And(_ => GivenTheDependenciesAreSetUpCorrectly())
.When(_ => WhenICreate())
.Then(_ => ThenTheDependenciesAreCalledCorrectly())
.And(_ => ThenTheReRoutesAreCreated())
.BDDfy();
}
private void ThenTheDependenciesAreCalledCorrectly()
{
ThenTheDepsAreCalledFor(_fileConfig.ReRoutes[0], _fileConfig.GlobalConfiguration);
ThenTheDepsAreCalledFor(_fileConfig.ReRoutes[1], _fileConfig.GlobalConfiguration);
}
private void GivenTheDependenciesAreSetUpCorrectly()
{
_expectedVersion = new Version("1.1");
_rro = new ReRouteOptions(false, false, false, false, false);
_requestId = "testy";
_rrk = "besty";
_upt = new UpstreamPathTemplateBuilder().Build();
_ao = new AuthenticationOptionsBuilder().Build();
_ctt = new List<ClaimToThing>();
_qoso = new QoSOptionsBuilder().Build();
_rlo = new RateLimitOptionsBuilder().Build();
_region = "vesty";
_hho = new HttpHandlerOptionsBuilder().Build();
_ht = new HeaderTransformations(new List<HeaderFindAndReplace>(), new List<HeaderFindAndReplace>(), new List<AddHeader>(), new List<AddHeader>());
_dhp = new List<DownstreamHostAndPort>();
_lbo = new LoadBalancerOptionsBuilder().Build();
_rroCreator.Setup(x => x.Create(It.IsAny<FileReRoute>())).Returns(_rro);
_ridkCreator.Setup(x => x.Create(It.IsAny<FileReRoute>(), It.IsAny<FileGlobalConfiguration>())).Returns(_requestId);
_rrkCreator.Setup(x => x.Create(It.IsAny<FileReRoute>())).Returns(_rrk);
_utpCreator.Setup(x => x.Create(It.IsAny<IReRoute>())).Returns(_upt);
_aoCreator.Setup(x => x.Create(It.IsAny<FileReRoute>())).Returns(_ao);
_cthCreator.Setup(x => x.Create(It.IsAny<Dictionary<string, string>>())).Returns(_ctt);
_qosoCreator.Setup(x => x.Create(It.IsAny<FileQoSOptions>(), It.IsAny<string>(), It.IsAny<List<string>>())).Returns(_qoso);
_rloCreator.Setup(x => x.Create(It.IsAny<FileRateLimitRule>(), It.IsAny<FileGlobalConfiguration>())).Returns(_rlo);
_rCreator.Setup(x => x.Create(It.IsAny<FileReRoute>())).Returns(_region);
_hhoCreator.Setup(x => x.Create(It.IsAny<FileHttpHandlerOptions>())).Returns(_hho);
_hfarCreator.Setup(x => x.Create(It.IsAny<FileReRoute>())).Returns(_ht);
_daCreator.Setup(x => x.Create(It.IsAny<FileReRoute>())).Returns(_dhp);
_lboCreator.Setup(x => x.Create(It.IsAny<FileLoadBalancerOptions>())).Returns(_lbo);
_versionCreator.Setup(x => x.Create(It.IsAny<string>())).Returns(_expectedVersion);
}
private void ThenTheReRoutesAreCreated()
{
_result.Count.ShouldBe(2);
ThenTheReRouteIsSet(_fileConfig.ReRoutes[0], 0);
ThenTheReRouteIsSet(_fileConfig.ReRoutes[1], 1);
}
private void ThenNoReRoutesAreReturned()
{
_result.ShouldBeEmpty();
}
private void GivenThe(FileConfiguration fileConfig)
{
_fileConfig = fileConfig;
}
private void WhenICreate()
{
_result = _creator.Create(_fileConfig);
}
private void ThenTheReRouteIsSet(FileReRoute expected, int reRouteIndex)
{
_result[reRouteIndex].DownstreamReRoute[0].DownstreamHttpVersion.ShouldBe(_expectedVersion);
_result[reRouteIndex].DownstreamReRoute[0].IsAuthenticated.ShouldBe(_rro.IsAuthenticated);
_result[reRouteIndex].DownstreamReRoute[0].IsAuthorised.ShouldBe(_rro.IsAuthorised);
_result[reRouteIndex].DownstreamReRoute[0].IsCached.ShouldBe(_rro.IsCached);
_result[reRouteIndex].DownstreamReRoute[0].EnableEndpointEndpointRateLimiting.ShouldBe(_rro.EnableRateLimiting);
_result[reRouteIndex].DownstreamReRoute[0].RequestIdKey.ShouldBe(_requestId);
_result[reRouteIndex].DownstreamReRoute[0].LoadBalancerKey.ShouldBe(_rrk);
_result[reRouteIndex].DownstreamReRoute[0].UpstreamPathTemplate.ShouldBe(_upt);
_result[reRouteIndex].DownstreamReRoute[0].AuthenticationOptions.ShouldBe(_ao);
_result[reRouteIndex].DownstreamReRoute[0].ClaimsToHeaders.ShouldBe(_ctt);
_result[reRouteIndex].DownstreamReRoute[0].ClaimsToQueries.ShouldBe(_ctt);
_result[reRouteIndex].DownstreamReRoute[0].ClaimsToClaims.ShouldBe(_ctt);
_result[reRouteIndex].DownstreamReRoute[0].QosOptions.ShouldBe(_qoso);
_result[reRouteIndex].DownstreamReRoute[0].RateLimitOptions.ShouldBe(_rlo);
_result[reRouteIndex].DownstreamReRoute[0].CacheOptions.Region.ShouldBe(_region);
_result[reRouteIndex].DownstreamReRoute[0].CacheOptions.TtlSeconds.ShouldBe(expected.FileCacheOptions.TtlSeconds);
_result[reRouteIndex].DownstreamReRoute[0].HttpHandlerOptions.ShouldBe(_hho);
_result[reRouteIndex].DownstreamReRoute[0].UpstreamHeadersFindAndReplace.ShouldBe(_ht.Upstream);
_result[reRouteIndex].DownstreamReRoute[0].DownstreamHeadersFindAndReplace.ShouldBe(_ht.Downstream);
_result[reRouteIndex].DownstreamReRoute[0].AddHeadersToUpstream.ShouldBe(_ht.AddHeadersToUpstream);
_result[reRouteIndex].DownstreamReRoute[0].AddHeadersToDownstream.ShouldBe(_ht.AddHeadersToDownstream);
_result[reRouteIndex].DownstreamReRoute[0].DownstreamAddresses.ShouldBe(_dhp);
_result[reRouteIndex].DownstreamReRoute[0].LoadBalancerOptions.ShouldBe(_lbo);
_result[reRouteIndex].DownstreamReRoute[0].UseServiceDiscovery.ShouldBe(_rro.UseServiceDiscovery);
_result[reRouteIndex].DownstreamReRoute[0].DangerousAcceptAnyServerCertificateValidator.ShouldBe(expected.DangerousAcceptAnyServerCertificateValidator);
_result[reRouteIndex].DownstreamReRoute[0].DelegatingHandlers.ShouldBe(expected.DelegatingHandlers);
_result[reRouteIndex].DownstreamReRoute[0].ServiceName.ShouldBe(expected.ServiceName);
_result[reRouteIndex].DownstreamReRoute[0].DownstreamScheme.ShouldBe(expected.DownstreamScheme);
_result[reRouteIndex].DownstreamReRoute[0].RouteClaimsRequirement.ShouldBe(expected.RouteClaimsRequirement);
_result[reRouteIndex].DownstreamReRoute[0].DownstreamPathTemplate.Value.ShouldBe(expected.DownstreamPathTemplate);
_result[reRouteIndex].DownstreamReRoute[0].Key.ShouldBe(expected.Key);
_result[reRouteIndex].UpstreamHttpMethod
.Select(x => x.Method)
.ToList()
.ShouldContain(x => x == expected.UpstreamHttpMethod[0]);
_result[reRouteIndex].UpstreamHttpMethod
.Select(x => x.Method)
.ToList()
.ShouldContain(x => x == expected.UpstreamHttpMethod[1]);
_result[reRouteIndex].UpstreamHost.ShouldBe(expected.UpstreamHost);
_result[reRouteIndex].DownstreamReRoute.Count.ShouldBe(1);
_result[reRouteIndex].UpstreamTemplatePattern.ShouldBe(_upt);
}
private void ThenTheDepsAreCalledFor(FileReRoute fileReRoute, FileGlobalConfiguration globalConfig)
{
_rroCreator.Verify(x => x.Create(fileReRoute), Times.Once);
_ridkCreator.Verify(x => x.Create(fileReRoute, globalConfig), Times.Once);
_rrkCreator.Verify(x => x.Create(fileReRoute), Times.Once);
_utpCreator.Verify(x => x.Create(fileReRoute), Times.Exactly(2));
_aoCreator.Verify(x => x.Create(fileReRoute), Times.Once);
_cthCreator.Verify(x => x.Create(fileReRoute.AddHeadersToRequest), Times.Once);
_cthCreator.Verify(x => x.Create(fileReRoute.AddClaimsToRequest), Times.Once);
_cthCreator.Verify(x => x.Create(fileReRoute.AddQueriesToRequest), Times.Once);
_qosoCreator.Verify(x => x.Create(fileReRoute.QoSOptions, fileReRoute.UpstreamPathTemplate, fileReRoute.UpstreamHttpMethod));
_rloCreator.Verify(x => x.Create(fileReRoute.RateLimitOptions, globalConfig), Times.Once);
_rCreator.Verify(x => x.Create(fileReRoute), Times.Once);
_hhoCreator.Verify(x => x.Create(fileReRoute.HttpHandlerOptions), Times.Once);
_hfarCreator.Verify(x => x.Create(fileReRoute), Times.Once);
_daCreator.Verify(x => x.Create(fileReRoute), Times.Once);
_lboCreator.Verify(x => x.Create(fileReRoute.LoadBalancerOptions), Times.Once);
_soCreator.Verify(x => x.Create(fileReRoute.SecurityOptions), Times.Once);
}
}
}
namespace Ocelot.UnitTests.Configuration
{
using System;
using Moq;
using Ocelot.Cache;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Ocelot.Values;
using Shouldly;
using System.Collections.Generic;
using System.Linq;
using TestStack.BDDfy;
using Xunit;
public class RoutesCreatorTests
{
private RoutesCreator _creator;
private Mock<IClaimsToThingCreator> _cthCreator;
private Mock<IAuthenticationOptionsCreator> _aoCreator;
private Mock<IUpstreamTemplatePatternCreator> _utpCreator;
private Mock<IRequestIdKeyCreator> _ridkCreator;
private Mock<IQoSOptionsCreator> _qosoCreator;
private Mock<IRouteOptionsCreator> _rroCreator;
private Mock<IRateLimitOptionsCreator> _rloCreator;
private Mock<IRegionCreator> _rCreator;
private Mock<IHttpHandlerOptionsCreator> _hhoCreator;
private Mock<IHeaderFindAndReplaceCreator> _hfarCreator;
private Mock<IDownstreamAddressesCreator> _daCreator;
private Mock<ILoadBalancerOptionsCreator> _lboCreator;
private Mock<IRouteKeyCreator> _rrkCreator;
private Mock<ISecurityOptionsCreator> _soCreator;
private Mock<IVersionCreator> _versionCreator;
private FileConfiguration _fileConfig;
private RouteOptions _rro;
private string _requestId;
private string _rrk;
private UpstreamPathTemplate _upt;
private AuthenticationOptions _ao;
private List<ClaimToThing> _ctt;
private QoSOptions _qoso;
private RateLimitOptions _rlo;
private string _region;
private HttpHandlerOptions _hho;
private HeaderTransformations _ht;
private List<DownstreamHostAndPort> _dhp;
private LoadBalancerOptions _lbo;
private List<Route> _result;
private SecurityOptions _securityOptions;
private Version _expectedVersion;
public RoutesCreatorTests()
{
_cthCreator = new Mock<IClaimsToThingCreator>();
_aoCreator = new Mock<IAuthenticationOptionsCreator>();
_utpCreator = new Mock<IUpstreamTemplatePatternCreator>();
_ridkCreator = new Mock<IRequestIdKeyCreator>();
_qosoCreator = new Mock<IQoSOptionsCreator>();
_rroCreator = new Mock<IRouteOptionsCreator>();
_rloCreator = new Mock<IRateLimitOptionsCreator>();
_rCreator = new Mock<IRegionCreator>();
_hhoCreator = new Mock<IHttpHandlerOptionsCreator>();
_hfarCreator = new Mock<IHeaderFindAndReplaceCreator>();
_daCreator = new Mock<IDownstreamAddressesCreator>();
_lboCreator = new Mock<ILoadBalancerOptionsCreator>();
_rrkCreator = new Mock<IRouteKeyCreator>();
_soCreator = new Mock<ISecurityOptionsCreator>();
_versionCreator = new Mock<IVersionCreator>();
_creator = new RoutesCreator(
_cthCreator.Object,
_aoCreator.Object,
_utpCreator.Object,
_ridkCreator.Object,
_qosoCreator.Object,
_rroCreator.Object,
_rloCreator.Object,
_rCreator.Object,
_hhoCreator.Object,
_hfarCreator.Object,
_daCreator.Object,
_lboCreator.Object,
_rrkCreator.Object,
_soCreator.Object,
_versionCreator.Object
);
}
[Fact]
public void should_return_nothing()
{
var fileConfig = new FileConfiguration();
this.Given(_ => GivenThe(fileConfig))
.When(_ => WhenICreate())
.Then(_ => ThenNoRoutesAreReturned())
.BDDfy();
}
[Fact]
public void should_return_re_routes()
{
var fileConfig = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
ServiceName = "dave",
DangerousAcceptAnyServerCertificateValidator = true,
AddClaimsToRequest = new Dictionary<string, string>
{
{ "a","b" }
},
AddHeadersToRequest = new Dictionary<string, string>
{
{ "c","d" }
},
AddQueriesToRequest = new Dictionary<string, string>
{
{ "e","f" }
},
UpstreamHttpMethod = new List<string> { "GET", "POST" }
},
new FileRoute
{
ServiceName = "wave",
DangerousAcceptAnyServerCertificateValidator = false,
AddClaimsToRequest = new Dictionary<string, string>
{
{ "g","h" }
},
AddHeadersToRequest = new Dictionary<string, string>
{
{ "i","j" }
},
AddQueriesToRequest = new Dictionary<string, string>
{
{ "k","l" }
},
UpstreamHttpMethod = new List<string> { "PUT", "DELETE" }
}
}
};
this.Given(_ => GivenThe(fileConfig))
.And(_ => GivenTheDependenciesAreSetUpCorrectly())
.When(_ => WhenICreate())
.Then(_ => ThenTheDependenciesAreCalledCorrectly())
.And(_ => ThenTheRoutesAreCreated())
.BDDfy();
}
private void ThenTheDependenciesAreCalledCorrectly()
{
ThenTheDepsAreCalledFor(_fileConfig.Routes[0], _fileConfig.GlobalConfiguration);
ThenTheDepsAreCalledFor(_fileConfig.Routes[1], _fileConfig.GlobalConfiguration);
}
private void GivenTheDependenciesAreSetUpCorrectly()
{
_expectedVersion = new Version("1.1");
_rro = new RouteOptions(false, false, false, false, false);
_requestId = "testy";
_rrk = "besty";
_upt = new UpstreamPathTemplateBuilder().Build();
_ao = new AuthenticationOptionsBuilder().Build();
_ctt = new List<ClaimToThing>();
_qoso = new QoSOptionsBuilder().Build();
_rlo = new RateLimitOptionsBuilder().Build();
_region = "vesty";
_hho = new HttpHandlerOptionsBuilder().Build();
_ht = new HeaderTransformations(new List<HeaderFindAndReplace>(), new List<HeaderFindAndReplace>(), new List<AddHeader>(), new List<AddHeader>());
_dhp = new List<DownstreamHostAndPort>();
_lbo = new LoadBalancerOptionsBuilder().Build();
_rroCreator.Setup(x => x.Create(It.IsAny<FileRoute>())).Returns(_rro);
_ridkCreator.Setup(x => x.Create(It.IsAny<FileRoute>(), It.IsAny<FileGlobalConfiguration>())).Returns(_requestId);
_rrkCreator.Setup(x => x.Create(It.IsAny<FileRoute>())).Returns(_rrk);
_utpCreator.Setup(x => x.Create(It.IsAny<IRoute>())).Returns(_upt);
_aoCreator.Setup(x => x.Create(It.IsAny<FileRoute>())).Returns(_ao);
_cthCreator.Setup(x => x.Create(It.IsAny<Dictionary<string, string>>())).Returns(_ctt);
_qosoCreator.Setup(x => x.Create(It.IsAny<FileQoSOptions>(), It.IsAny<string>(), It.IsAny<List<string>>())).Returns(_qoso);
_rloCreator.Setup(x => x.Create(It.IsAny<FileRateLimitRule>(), It.IsAny<FileGlobalConfiguration>())).Returns(_rlo);
_rCreator.Setup(x => x.Create(It.IsAny<FileRoute>())).Returns(_region);
_hhoCreator.Setup(x => x.Create(It.IsAny<FileHttpHandlerOptions>())).Returns(_hho);
_hfarCreator.Setup(x => x.Create(It.IsAny<FileRoute>())).Returns(_ht);
_daCreator.Setup(x => x.Create(It.IsAny<FileRoute>())).Returns(_dhp);
_lboCreator.Setup(x => x.Create(It.IsAny<FileLoadBalancerOptions>())).Returns(_lbo);
_versionCreator.Setup(x => x.Create(It.IsAny<string>())).Returns(_expectedVersion);
}
private void ThenTheRoutesAreCreated()
{
_result.Count.ShouldBe(2);
ThenTheRouteIsSet(_fileConfig.Routes[0], 0);
ThenTheRouteIsSet(_fileConfig.Routes[1], 1);
}
private void ThenNoRoutesAreReturned()
{
_result.ShouldBeEmpty();
}
private void GivenThe(FileConfiguration fileConfig)
{
_fileConfig = fileConfig;
}
private void WhenICreate()
{
_result = _creator.Create(_fileConfig);
}
private void ThenTheRouteIsSet(FileRoute expected, int routeIndex)
{
_result[routeIndex].DownstreamRoute[0].DownstreamHttpVersion.ShouldBe(_expectedVersion);
_result[routeIndex].DownstreamRoute[0].IsAuthenticated.ShouldBe(_rro.IsAuthenticated);
_result[routeIndex].DownstreamRoute[0].IsAuthorised.ShouldBe(_rro.IsAuthorised);
_result[routeIndex].DownstreamRoute[0].IsCached.ShouldBe(_rro.IsCached);
_result[routeIndex].DownstreamRoute[0].EnableEndpointEndpointRateLimiting.ShouldBe(_rro.EnableRateLimiting);
_result[routeIndex].DownstreamRoute[0].RequestIdKey.ShouldBe(_requestId);
_result[routeIndex].DownstreamRoute[0].LoadBalancerKey.ShouldBe(_rrk);
_result[routeIndex].DownstreamRoute[0].UpstreamPathTemplate.ShouldBe(_upt);
_result[routeIndex].DownstreamRoute[0].AuthenticationOptions.ShouldBe(_ao);
_result[routeIndex].DownstreamRoute[0].ClaimsToHeaders.ShouldBe(_ctt);
_result[routeIndex].DownstreamRoute[0].ClaimsToQueries.ShouldBe(_ctt);
_result[routeIndex].DownstreamRoute[0].ClaimsToClaims.ShouldBe(_ctt);
_result[routeIndex].DownstreamRoute[0].QosOptions.ShouldBe(_qoso);
_result[routeIndex].DownstreamRoute[0].RateLimitOptions.ShouldBe(_rlo);
_result[routeIndex].DownstreamRoute[0].CacheOptions.Region.ShouldBe(_region);
_result[routeIndex].DownstreamRoute[0].CacheOptions.TtlSeconds.ShouldBe(expected.FileCacheOptions.TtlSeconds);
_result[routeIndex].DownstreamRoute[0].HttpHandlerOptions.ShouldBe(_hho);
_result[routeIndex].DownstreamRoute[0].UpstreamHeadersFindAndReplace.ShouldBe(_ht.Upstream);
_result[routeIndex].DownstreamRoute[0].DownstreamHeadersFindAndReplace.ShouldBe(_ht.Downstream);
_result[routeIndex].DownstreamRoute[0].AddHeadersToUpstream.ShouldBe(_ht.AddHeadersToUpstream);
_result[routeIndex].DownstreamRoute[0].AddHeadersToDownstream.ShouldBe(_ht.AddHeadersToDownstream);
_result[routeIndex].DownstreamRoute[0].DownstreamAddresses.ShouldBe(_dhp);
_result[routeIndex].DownstreamRoute[0].LoadBalancerOptions.ShouldBe(_lbo);
_result[routeIndex].DownstreamRoute[0].UseServiceDiscovery.ShouldBe(_rro.UseServiceDiscovery);
_result[routeIndex].DownstreamRoute[0].DangerousAcceptAnyServerCertificateValidator.ShouldBe(expected.DangerousAcceptAnyServerCertificateValidator);
_result[routeIndex].DownstreamRoute[0].DelegatingHandlers.ShouldBe(expected.DelegatingHandlers);
_result[routeIndex].DownstreamRoute[0].ServiceName.ShouldBe(expected.ServiceName);
_result[routeIndex].DownstreamRoute[0].DownstreamScheme.ShouldBe(expected.DownstreamScheme);
_result[routeIndex].DownstreamRoute[0].RouteClaimsRequirement.ShouldBe(expected.RouteClaimsRequirement);
_result[routeIndex].DownstreamRoute[0].DownstreamPathTemplate.Value.ShouldBe(expected.DownstreamPathTemplate);
_result[routeIndex].DownstreamRoute[0].Key.ShouldBe(expected.Key);
_result[routeIndex].UpstreamHttpMethod
.Select(x => x.Method)
.ToList()
.ShouldContain(x => x == expected.UpstreamHttpMethod[0]);
_result[routeIndex].UpstreamHttpMethod
.Select(x => x.Method)
.ToList()
.ShouldContain(x => x == expected.UpstreamHttpMethod[1]);
_result[routeIndex].UpstreamHost.ShouldBe(expected.UpstreamHost);
_result[routeIndex].DownstreamRoute.Count.ShouldBe(1);
_result[routeIndex].UpstreamTemplatePattern.ShouldBe(_upt);
}
private void ThenTheDepsAreCalledFor(FileRoute fileRoute, FileGlobalConfiguration globalConfig)
{
_rroCreator.Verify(x => x.Create(fileRoute), Times.Once);
_ridkCreator.Verify(x => x.Create(fileRoute, globalConfig), Times.Once);
_rrkCreator.Verify(x => x.Create(fileRoute), Times.Once);
_utpCreator.Verify(x => x.Create(fileRoute), Times.Exactly(2));
_aoCreator.Verify(x => x.Create(fileRoute), Times.Once);
_cthCreator.Verify(x => x.Create(fileRoute.AddHeadersToRequest), Times.Once);
_cthCreator.Verify(x => x.Create(fileRoute.AddClaimsToRequest), Times.Once);
_cthCreator.Verify(x => x.Create(fileRoute.AddQueriesToRequest), Times.Once);
_qosoCreator.Verify(x => x.Create(fileRoute.QoSOptions, fileRoute.UpstreamPathTemplate, fileRoute.UpstreamHttpMethod));
_rloCreator.Verify(x => x.Create(fileRoute.RateLimitOptions, globalConfig), Times.Once);
_rCreator.Verify(x => x.Create(fileRoute), Times.Once);
_hhoCreator.Verify(x => x.Create(fileRoute.HttpHandlerOptions), Times.Once);
_hfarCreator.Verify(x => x.Create(fileRoute), Times.Once);
_daCreator.Verify(x => x.Create(fileRoute), Times.Once);
_lboCreator.Verify(x => x.Create(fileRoute.LoadBalancerOptions), Times.Once);
_soCreator.Verify(x => x.Create(fileRoute.SecurityOptions), Times.Once);
}
}
}

View File

@ -1,68 +1,68 @@
using Ocelot.Configuration;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Shouldly;
using System.Collections.Generic;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration
{
public class SecurityOptionsCreatorTests
{
private FileReRoute _fileReRoute;
private FileGlobalConfiguration _fileGlobalConfig;
private SecurityOptions _result;
private ISecurityOptionsCreator _creator;
public SecurityOptionsCreatorTests()
{
_creator = new SecurityOptionsCreator();
}
[Fact]
public void should_create_security_config()
{
var ipAllowedList = new List<string>() { "127.0.0.1", "192.168.1.1" };
var ipBlockedList = new List<string>() { "127.0.0.1", "192.168.1.1" };
var fileReRoute = new FileReRoute
{
SecurityOptions = new FileSecurityOptions()
{
IPAllowedList = ipAllowedList,
IPBlockedList = ipBlockedList
}
};
var expected = new SecurityOptions(ipAllowedList, ipBlockedList);
this.Given(x => x.GivenThe(fileReRoute))
.When(x => x.WhenICreate())
.Then(x => x.ThenTheResultIs(expected))
.BDDfy();
}
private void GivenThe(FileReRoute reRoute)
{
_fileReRoute = reRoute;
}
private void WhenICreate()
{
_result = _creator.Create(_fileReRoute.SecurityOptions);
}
private void ThenTheResultIs(SecurityOptions expected)
{
for (int i = 0; i < expected.IPAllowedList.Count; i++)
{
_result.IPAllowedList[i].ShouldBe(expected.IPAllowedList[i]);
}
for (int i = 0; i < expected.IPBlockedList.Count; i++)
{
_result.IPBlockedList[i].ShouldBe(expected.IPBlockedList[i]);
}
}
}
}
using Ocelot.Configuration;
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Shouldly;
using System.Collections.Generic;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration
{
public class SecurityOptionsCreatorTests
{
private FileRoute _fileRoute;
private FileGlobalConfiguration _fileGlobalConfig;
private SecurityOptions _result;
private ISecurityOptionsCreator _creator;
public SecurityOptionsCreatorTests()
{
_creator = new SecurityOptionsCreator();
}
[Fact]
public void should_create_security_config()
{
var ipAllowedList = new List<string>() { "127.0.0.1", "192.168.1.1" };
var ipBlockedList = new List<string>() { "127.0.0.1", "192.168.1.1" };
var fileRoute = new FileRoute
{
SecurityOptions = new FileSecurityOptions()
{
IPAllowedList = ipAllowedList,
IPBlockedList = ipBlockedList
}
};
var expected = new SecurityOptions(ipAllowedList, ipBlockedList);
this.Given(x => x.GivenThe(fileRoute))
.When(x => x.WhenICreate())
.Then(x => x.ThenTheResultIs(expected))
.BDDfy();
}
private void GivenThe(FileRoute route)
{
_fileRoute = route;
}
private void WhenICreate()
{
_result = _creator.Create(_fileRoute.SecurityOptions);
}
private void ThenTheResultIs(SecurityOptions expected)
{
for (int i = 0; i < expected.IPAllowedList.Count; i++)
{
_result.IPAllowedList[i].ShouldBe(expected.IPAllowedList[i]);
}
for (int i = 0; i < expected.IPBlockedList.Count; i++)
{
_result.IPBlockedList[i].ShouldBe(expected.IPBlockedList[i]);
}
}
}
}

View File

@ -1,260 +1,260 @@
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Ocelot.Values;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration
{
public class UpstreamTemplatePatternCreatorTests
{
private FileReRoute _fileReRoute;
private readonly UpstreamTemplatePatternCreator _creator;
private UpstreamPathTemplate _result;
public UpstreamTemplatePatternCreatorTests()
{
_creator = new UpstreamTemplatePatternCreator();
}
[Fact]
public void should_match_up_to_next_slash()
{
var fileReRoute = new FileReRoute
{
UpstreamPathTemplate = "/api/v{apiVersion}/cards",
Priority = 0
};
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^(?i)/api/v[^/]+/cards$"))
.And(x => ThenThePriorityIs(0))
.BDDfy();
}
[Fact]
public void should_use_re_route_priority()
{
var fileReRoute = new FileReRoute
{
UpstreamPathTemplate = "/orders/{catchAll}",
Priority = 0
};
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^(?i)/orders/.+$"))
.And(x => ThenThePriorityIs(0))
.BDDfy();
}
[Fact]
public void should_use_zero_priority()
{
var fileReRoute = new FileReRoute
{
UpstreamPathTemplate = "/{catchAll}",
Priority = 1
};
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^/.*"))
.And(x => ThenThePriorityIs(0))
.BDDfy();
}
[Fact]
public void should_set_upstream_template_pattern_to_ignore_case_sensitivity()
{
var fileReRoute = new FileReRoute
{
UpstreamPathTemplate = "/PRODUCTS/{productId}",
ReRouteIsCaseSensitive = false
};
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^(?i)/PRODUCTS/.+$"))
.And(x => ThenThePriorityIs(1))
.BDDfy();
}
[Fact]
public void should_match_forward_slash_or_no_forward_slash_if_template_end_with_forward_slash()
{
var fileReRoute = new FileReRoute
{
UpstreamPathTemplate = "/PRODUCTS/",
ReRouteIsCaseSensitive = false
};
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^(?i)/PRODUCTS(/|)$"))
.And(x => ThenThePriorityIs(1))
.BDDfy();
}
[Fact]
public void should_set_upstream_template_pattern_to_respect_case_sensitivity()
{
var fileReRoute = new FileReRoute
{
UpstreamPathTemplate = "/PRODUCTS/{productId}",
ReRouteIsCaseSensitive = true
};
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^/PRODUCTS/.+$"))
.And(x => ThenThePriorityIs(1))
.BDDfy();
}
[Fact]
public void should_create_template_pattern_that_matches_anything_to_end_of_string()
{
var fileReRoute = new FileReRoute
{
UpstreamPathTemplate = "/api/products/{productId}",
ReRouteIsCaseSensitive = true
};
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^/api/products/.+$"))
.And(x => ThenThePriorityIs(1))
.BDDfy();
}
[Fact]
public void should_create_template_pattern_that_matches_more_than_one_placeholder()
{
var fileReRoute = new FileReRoute
{
UpstreamPathTemplate = "/api/products/{productId}/variants/{variantId}",
ReRouteIsCaseSensitive = true
};
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^/api/products/[^/]+/variants/.+$"))
.And(x => ThenThePriorityIs(1))
.BDDfy();
}
[Fact]
public void should_create_template_pattern_that_matches_more_than_one_placeholder_with_trailing_slash()
{
var fileReRoute = new FileReRoute
{
UpstreamPathTemplate = "/api/products/{productId}/variants/{variantId}/",
ReRouteIsCaseSensitive = true
};
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^/api/products/[^/]+/variants/[^/]+(/|)$"))
.And(x => ThenThePriorityIs(1))
.BDDfy();
}
[Fact]
public void should_create_template_pattern_that_matches_to_end_of_string()
{
var fileReRoute = new FileReRoute
{
UpstreamPathTemplate = "/"
};
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^/$"))
.And(x => ThenThePriorityIs(1))
.BDDfy();
}
[Fact]
public void should_create_template_pattern_that_matches_to_end_of_string_when_slash_and_placeholder()
{
var fileReRoute = new FileReRoute
{
UpstreamPathTemplate = "/{url}"
};
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^/.*"))
.And(x => ThenThePriorityIs(0))
.BDDfy();
}
[Fact]
public void should_create_template_pattern_that_starts_with_placeholder_then_has_another_later()
{
var fileReRoute = new FileReRoute
{
UpstreamPathTemplate = "/{productId}/products/variants/{variantId}/",
ReRouteIsCaseSensitive = true
};
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^/[^/]+/products/variants/[^/]+(/|)$"))
.And(x => ThenThePriorityIs(1))
.BDDfy();
}
[Fact]
public void should_create_template_pattern_that_matches_query_string()
{
var fileReRoute = new FileReRoute
{
UpstreamPathTemplate = "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}"
};
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^(?i)/api/subscriptions/[^/]+/updates\\?unitId=.+$"))
.And(x => ThenThePriorityIs(1))
.BDDfy();
}
[Fact]
public void should_create_template_pattern_that_matches_query_string_with_multiple_params()
{
var fileReRoute = new FileReRoute
{
UpstreamPathTemplate = "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}&productId={productId}"
};
this.Given(x => x.GivenTheFollowingFileReRoute(fileReRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^(?i)/api/subscriptions/[^/]+/updates\\?unitId=.+&productId=.+$"))
.And(x => ThenThePriorityIs(1))
.BDDfy();
}
private void GivenTheFollowingFileReRoute(FileReRoute fileReRoute)
{
_fileReRoute = fileReRoute;
}
private void WhenICreateTheTemplatePattern()
{
_result = _creator.Create(_fileReRoute);
}
private void ThenTheFollowingIsReturned(string expected)
{
_result.Template.ShouldBe(expected);
}
private void ThenThePriorityIs(int v)
{
_result.Priority.ShouldBe(v);
}
}
}
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.File;
using Ocelot.Values;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration
{
public class UpstreamTemplatePatternCreatorTests
{
private FileRoute _fileRoute;
private readonly UpstreamTemplatePatternCreator _creator;
private UpstreamPathTemplate _result;
public UpstreamTemplatePatternCreatorTests()
{
_creator = new UpstreamTemplatePatternCreator();
}
[Fact]
public void should_match_up_to_next_slash()
{
var fileRoute = new FileRoute
{
UpstreamPathTemplate = "/api/v{apiVersion}/cards",
Priority = 0
};
this.Given(x => x.GivenTheFollowingFileRoute(fileRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^(?i)/api/v[^/]+/cards$"))
.And(x => ThenThePriorityIs(0))
.BDDfy();
}
[Fact]
public void should_use_re_route_priority()
{
var fileRoute = new FileRoute
{
UpstreamPathTemplate = "/orders/{catchAll}",
Priority = 0
};
this.Given(x => x.GivenTheFollowingFileRoute(fileRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^(?i)/orders/.+$"))
.And(x => ThenThePriorityIs(0))
.BDDfy();
}
[Fact]
public void should_use_zero_priority()
{
var fileRoute = new FileRoute
{
UpstreamPathTemplate = "/{catchAll}",
Priority = 1
};
this.Given(x => x.GivenTheFollowingFileRoute(fileRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^/.*"))
.And(x => ThenThePriorityIs(0))
.BDDfy();
}
[Fact]
public void should_set_upstream_template_pattern_to_ignore_case_sensitivity()
{
var fileRoute = new FileRoute
{
UpstreamPathTemplate = "/PRODUCTS/{productId}",
RouteIsCaseSensitive = false
};
this.Given(x => x.GivenTheFollowingFileRoute(fileRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^(?i)/PRODUCTS/.+$"))
.And(x => ThenThePriorityIs(1))
.BDDfy();
}
[Fact]
public void should_match_forward_slash_or_no_forward_slash_if_template_end_with_forward_slash()
{
var fileRoute = new FileRoute
{
UpstreamPathTemplate = "/PRODUCTS/",
RouteIsCaseSensitive = false
};
this.Given(x => x.GivenTheFollowingFileRoute(fileRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^(?i)/PRODUCTS(/|)$"))
.And(x => ThenThePriorityIs(1))
.BDDfy();
}
[Fact]
public void should_set_upstream_template_pattern_to_respect_case_sensitivity()
{
var fileRoute = new FileRoute
{
UpstreamPathTemplate = "/PRODUCTS/{productId}",
RouteIsCaseSensitive = true
};
this.Given(x => x.GivenTheFollowingFileRoute(fileRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^/PRODUCTS/.+$"))
.And(x => ThenThePriorityIs(1))
.BDDfy();
}
[Fact]
public void should_create_template_pattern_that_matches_anything_to_end_of_string()
{
var fileRoute = new FileRoute
{
UpstreamPathTemplate = "/api/products/{productId}",
RouteIsCaseSensitive = true
};
this.Given(x => x.GivenTheFollowingFileRoute(fileRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^/api/products/.+$"))
.And(x => ThenThePriorityIs(1))
.BDDfy();
}
[Fact]
public void should_create_template_pattern_that_matches_more_than_one_placeholder()
{
var fileRoute = new FileRoute
{
UpstreamPathTemplate = "/api/products/{productId}/variants/{variantId}",
RouteIsCaseSensitive = true
};
this.Given(x => x.GivenTheFollowingFileRoute(fileRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^/api/products/[^/]+/variants/.+$"))
.And(x => ThenThePriorityIs(1))
.BDDfy();
}
[Fact]
public void should_create_template_pattern_that_matches_more_than_one_placeholder_with_trailing_slash()
{
var fileRoute = new FileRoute
{
UpstreamPathTemplate = "/api/products/{productId}/variants/{variantId}/",
RouteIsCaseSensitive = true
};
this.Given(x => x.GivenTheFollowingFileRoute(fileRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^/api/products/[^/]+/variants/[^/]+(/|)$"))
.And(x => ThenThePriorityIs(1))
.BDDfy();
}
[Fact]
public void should_create_template_pattern_that_matches_to_end_of_string()
{
var fileRoute = new FileRoute
{
UpstreamPathTemplate = "/"
};
this.Given(x => x.GivenTheFollowingFileRoute(fileRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^/$"))
.And(x => ThenThePriorityIs(1))
.BDDfy();
}
[Fact]
public void should_create_template_pattern_that_matches_to_end_of_string_when_slash_and_placeholder()
{
var fileRoute = new FileRoute
{
UpstreamPathTemplate = "/{url}"
};
this.Given(x => x.GivenTheFollowingFileRoute(fileRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^/.*"))
.And(x => ThenThePriorityIs(0))
.BDDfy();
}
[Fact]
public void should_create_template_pattern_that_starts_with_placeholder_then_has_another_later()
{
var fileRoute = new FileRoute
{
UpstreamPathTemplate = "/{productId}/products/variants/{variantId}/",
RouteIsCaseSensitive = true
};
this.Given(x => x.GivenTheFollowingFileRoute(fileRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^/[^/]+/products/variants/[^/]+(/|)$"))
.And(x => ThenThePriorityIs(1))
.BDDfy();
}
[Fact]
public void should_create_template_pattern_that_matches_query_string()
{
var fileRoute = new FileRoute
{
UpstreamPathTemplate = "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}"
};
this.Given(x => x.GivenTheFollowingFileRoute(fileRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^(?i)/api/subscriptions/[^/]+/updates\\?unitId=.+$"))
.And(x => ThenThePriorityIs(1))
.BDDfy();
}
[Fact]
public void should_create_template_pattern_that_matches_query_string_with_multiple_params()
{
var fileRoute = new FileRoute
{
UpstreamPathTemplate = "/api/subscriptions/{subscriptionId}/updates?unitId={unitId}&productId={productId}"
};
this.Given(x => x.GivenTheFollowingFileRoute(fileRoute))
.When(x => x.WhenICreateTheTemplatePattern())
.Then(x => x.ThenTheFollowingIsReturned("^(?i)/api/subscriptions/[^/]+/updates\\?unitId=.+&productId=.+$"))
.And(x => ThenThePriorityIs(1))
.BDDfy();
}
private void GivenTheFollowingFileRoute(FileRoute fileRoute)
{
_fileRoute = fileRoute;
}
private void WhenICreateTheTemplatePattern()
{
_result = _creator.Create(_fileRoute);
}
private void ThenTheFollowingIsReturned(string expected)
{
_result.Template.ShouldBe(expected);
}
private void ThenThePriorityIs(int v)
{
_result.Priority.ShouldBe(v);
}
}
}

View File

@ -1,103 +1,103 @@
using FluentValidation.Results;
using Microsoft.Extensions.DependencyInjection;
using Ocelot.Configuration.File;
using Ocelot.Configuration.Validator;
using Ocelot.Requester;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration.Validation
{
public class FileQoSOptionsFluentValidatorTests
{
private FileQoSOptionsFluentValidator _validator;
private ServiceCollection _services;
private ValidationResult _result;
private FileQoSOptions _qosOptions;
public FileQoSOptionsFluentValidatorTests()
{
_services = new ServiceCollection();
var provider = _services.BuildServiceProvider();
_validator = new FileQoSOptionsFluentValidator(provider);
}
[Fact]
public void should_be_valid_as_nothing_set()
{
this.Given(_ => GivenThe(new FileQoSOptions()))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsValid())
.BDDfy();
}
[Fact]
public void should_be_valid_as_qos_delegate_set()
{
var qosOptions = new FileQoSOptions
{
TimeoutValue = 1,
ExceptionsAllowedBeforeBreaking = 1
};
this.Given(_ => GivenThe(qosOptions))
.And(_ => GivenAQosDelegate())
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsValid())
.BDDfy();
}
[Fact]
public void should_be_invalid_as_no_qos_delegate()
{
var qosOptions = new FileQoSOptions
{
TimeoutValue = 1,
ExceptionsAllowedBeforeBreaking = 1
};
this.Given(_ => GivenThe(qosOptions))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInValid())
.And(_ => ThenTheErrorIs())
.BDDfy();
}
private void ThenTheErrorIs()
{
_result.Errors[0].ErrorMessage.ShouldBe("Unable to start Ocelot because either a ReRoute or GlobalConfiguration are using QoSOptions but no QosDelegatingHandlerDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Polly and services.AddPolly()?");
}
private void ThenTheResultIsInValid()
{
_result.IsValid.ShouldBeFalse();
}
private void GivenAQosDelegate()
{
QosDelegatingHandlerDelegate fake = (a, b) =>
{
return null;
};
_services.AddSingleton<QosDelegatingHandlerDelegate>(fake);
var provider = _services.BuildServiceProvider();
_validator = new FileQoSOptionsFluentValidator(provider);
}
private void GivenThe(FileQoSOptions qosOptions)
{
_qosOptions = qosOptions;
}
private void WhenIValidate()
{
_result = _validator.Validate(_qosOptions);
}
private void ThenTheResultIsValid()
{
_result.IsValid.ShouldBeTrue();
}
}
}
using FluentValidation.Results;
using Microsoft.Extensions.DependencyInjection;
using Ocelot.Configuration.File;
using Ocelot.Configuration.Validator;
using Ocelot.Requester;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration.Validation
{
public class FileQoSOptionsFluentValidatorTests
{
private FileQoSOptionsFluentValidator _validator;
private ServiceCollection _services;
private ValidationResult _result;
private FileQoSOptions _qosOptions;
public FileQoSOptionsFluentValidatorTests()
{
_services = new ServiceCollection();
var provider = _services.BuildServiceProvider();
_validator = new FileQoSOptionsFluentValidator(provider);
}
[Fact]
public void should_be_valid_as_nothing_set()
{
this.Given(_ => GivenThe(new FileQoSOptions()))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsValid())
.BDDfy();
}
[Fact]
public void should_be_valid_as_qos_delegate_set()
{
var qosOptions = new FileQoSOptions
{
TimeoutValue = 1,
ExceptionsAllowedBeforeBreaking = 1
};
this.Given(_ => GivenThe(qosOptions))
.And(_ => GivenAQosDelegate())
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsValid())
.BDDfy();
}
[Fact]
public void should_be_invalid_as_no_qos_delegate()
{
var qosOptions = new FileQoSOptions
{
TimeoutValue = 1,
ExceptionsAllowedBeforeBreaking = 1
};
this.Given(_ => GivenThe(qosOptions))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInValid())
.And(_ => ThenTheErrorIs())
.BDDfy();
}
private void ThenTheErrorIs()
{
_result.Errors[0].ErrorMessage.ShouldBe("Unable to start Ocelot because either a Route or GlobalConfiguration are using QoSOptions but no QosDelegatingHandlerDelegate has been registered in dependency injection container. Are you missing a package like Ocelot.Provider.Polly and services.AddPolly()?");
}
private void ThenTheResultIsInValid()
{
_result.IsValid.ShouldBeFalse();
}
private void GivenAQosDelegate()
{
QosDelegatingHandlerDelegate fake = (a, b) =>
{
return null;
};
_services.AddSingleton<QosDelegatingHandlerDelegate>(fake);
var provider = _services.BuildServiceProvider();
_validator = new FileQoSOptionsFluentValidator(provider);
}
private void GivenThe(FileQoSOptions qosOptions)
{
_qosOptions = qosOptions;
}
private void WhenIValidate()
{
_result = _validator.Validate(_qosOptions);
}
private void ThenTheResultIsValid()
{
_result.IsValid.ShouldBeTrue();
}
}
}

View File

@ -1,77 +1,77 @@
using FluentValidation.Results;
using Ocelot.Configuration.File;
using Ocelot.Configuration.Validator;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration.Validation
{
public class HostAndPortValidatorTests
{
private HostAndPortValidator _validator;
private ValidationResult _result;
private FileHostAndPort _hostAndPort;
public HostAndPortValidatorTests()
{
_validator = new HostAndPortValidator();
}
[Theory]
[InlineData(null)]
[InlineData("")]
public void should_be_invalid_because_host_empty(string host)
{
var fileHostAndPort = new FileHostAndPort
{
Host = host
};
this.Given(_ => GivenThe(fileHostAndPort))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInValid())
.And(_ => ThenTheErorrIs())
.BDDfy();
}
[Fact]
public void should_be_valid_because_host_set()
{
var fileHostAndPort = new FileHostAndPort
{
Host = "test"
};
this.Given(_ => GivenThe(fileHostAndPort))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsValid())
.BDDfy();
}
private void GivenThe(FileHostAndPort hostAndPort)
{
_hostAndPort = hostAndPort;
}
private void WhenIValidate()
{
_result = _validator.Validate(_hostAndPort);
}
private void ThenTheResultIsValid()
{
_result.IsValid.ShouldBeTrue();
}
private void ThenTheErorrIs()
{
_result.Errors[0].ErrorMessage.ShouldBe("When not using service discovery Host must be set on DownstreamHostAndPorts if you are not using ReRoute.Host or Ocelot cannot find your service!");
}
private void ThenTheResultIsInValid()
{
_result.IsValid.ShouldBeFalse();
}
}
}
using FluentValidation.Results;
using Ocelot.Configuration.File;
using Ocelot.Configuration.Validator;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.Configuration.Validation
{
public class HostAndPortValidatorTests
{
private HostAndPortValidator _validator;
private ValidationResult _result;
private FileHostAndPort _hostAndPort;
public HostAndPortValidatorTests()
{
_validator = new HostAndPortValidator();
}
[Theory]
[InlineData(null)]
[InlineData("")]
public void should_be_invalid_because_host_empty(string host)
{
var fileHostAndPort = new FileHostAndPort
{
Host = host
};
this.Given(_ => GivenThe(fileHostAndPort))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInValid())
.And(_ => ThenTheErorrIs())
.BDDfy();
}
[Fact]
public void should_be_valid_because_host_set()
{
var fileHostAndPort = new FileHostAndPort
{
Host = "test"
};
this.Given(_ => GivenThe(fileHostAndPort))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsValid())
.BDDfy();
}
private void GivenThe(FileHostAndPort hostAndPort)
{
_hostAndPort = hostAndPort;
}
private void WhenIValidate()
{
_result = _validator.Validate(_hostAndPort);
}
private void ThenTheResultIsValid()
{
_result.IsValid.ShouldBeTrue();
}
private void ThenTheErorrIs()
{
_result.Errors[0].ErrorMessage.ShouldBe("When not using service discovery Host must be set on DownstreamHostAndPorts if you are not using Route.Host or Ocelot cannot find your service!");
}
private void ThenTheResultIsInValid()
{
_result.IsValid.ShouldBeFalse();
}
}
}

View File

@ -1,433 +1,433 @@
namespace Ocelot.UnitTests.Configuration.Validation
{
using FluentValidation.Results;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Moq;
using Ocelot.Configuration.File;
using Ocelot.Configuration.Validator;
using Ocelot.Requester;
using Shouldly;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using TestStack.BDDfy;
using Xunit;
public class ReRouteFluentValidatorTests
{
private readonly ReRouteFluentValidator _validator;
private readonly Mock<IAuthenticationSchemeProvider> _authProvider;
private QosDelegatingHandlerDelegate _qosDelegatingHandler;
private Mock<IServiceProvider> _serviceProvider;
private FileReRoute _reRoute;
private ValidationResult _result;
public ReRouteFluentValidatorTests()
{
_authProvider = new Mock<IAuthenticationSchemeProvider>();
_serviceProvider = new Mock<IServiceProvider>();
// Todo - replace with mocks
_validator = new ReRouteFluentValidator(_authProvider.Object, new HostAndPortValidator(), new FileQoSOptionsFluentValidator(_serviceProvider.Object));
}
[Fact]
public void downstream_path_template_should_not_be_empty()
{
var fileReRoute = new FileReRoute();
this.Given(_ => GivenThe(fileReRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInvalid())
.And(_ => ThenTheErrorsContains("Downstream Path Template cannot be empty"))
.BDDfy();
}
[Fact]
public void upstream_path_template_should_not_be_empty()
{
var fileReRoute = new FileReRoute
{
DownstreamPathTemplate = "test"
};
this.Given(_ => GivenThe(fileReRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInvalid())
.And(_ => ThenTheErrorsContains("Upstream Path Template cannot be empty"))
.BDDfy();
}
[Fact]
public void downstream_path_template_should_start_with_forward_slash()
{
var fileReRoute = new FileReRoute
{
DownstreamPathTemplate = "test"
};
this.Given(_ => GivenThe(fileReRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInvalid())
.And(_ => ThenTheErrorsContains("Downstream Path Template test doesnt start with forward slash"))
.BDDfy();
}
[Fact]
public void downstream_path_template_should_not_contain_double_forward_slash()
{
var fileReRoute = new FileReRoute
{
DownstreamPathTemplate = "//test"
};
this.Given(_ => GivenThe(fileReRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInvalid())
.And(_ => ThenTheErrorsContains("Downstream Path Template //test contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature."))
.BDDfy();
}
[Theory]
[InlineData("https://test")]
[InlineData("http://test")]
[InlineData("/test/http://")]
[InlineData("/test/https://")]
public void downstream_path_template_should_not_contain_scheme(string downstreamPathTemplate)
{
var fileReRoute = new FileReRoute
{
DownstreamPathTemplate = downstreamPathTemplate
};
this.Given(_ => GivenThe(fileReRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInvalid())
.And(_ => ThenTheErrorsContains($"Downstream Path Template {downstreamPathTemplate} contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature."))
.BDDfy();
}
[Fact]
public void upstream_path_template_should_start_with_forward_slash()
{
var fileReRoute = new FileReRoute
{
DownstreamPathTemplate = "/test",
UpstreamPathTemplate = "test"
};
this.Given(_ => GivenThe(fileReRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInvalid())
.And(_ => ThenTheErrorsContains("Upstream Path Template test doesnt start with forward slash"))
.BDDfy();
}
[Fact]
public void upstream_path_template_should_not_contain_double_forward_slash()
{
var fileReRoute = new FileReRoute
{
DownstreamPathTemplate = "/test",
UpstreamPathTemplate = "//test"
};
this.Given(_ => GivenThe(fileReRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInvalid())
.And(_ => ThenTheErrorsContains("Upstream Path Template //test contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature."))
.BDDfy();
}
[Theory]
[InlineData("https://test")]
[InlineData("http://test")]
[InlineData("/test/http://")]
[InlineData("/test/https://")]
public void upstream_path_template_should_not_contain_scheme(string upstreamPathTemplate)
{
var fileReRoute = new FileReRoute
{
DownstreamPathTemplate = "/test",
UpstreamPathTemplate = upstreamPathTemplate
};
this.Given(_ => GivenThe(fileReRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInvalid())
.And(_ => ThenTheErrorsContains($"Upstream Path Template {upstreamPathTemplate} contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature."))
.BDDfy();
}
[Fact]
public void should_not_be_valid_if_enable_rate_limiting_true_and_period_is_empty()
{
var fileReRoute = new FileReRoute
{
DownstreamPathTemplate = "/test",
UpstreamPathTemplate = "/test",
RateLimitOptions = new FileRateLimitRule
{
EnableRateLimiting = true
}
};
this.Given(_ => GivenThe(fileReRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInvalid())
.And(_ => ThenTheErrorsContains("RateLimitOptions.Period is empty"))
.BDDfy();
}
[Fact]
public void should_not_be_valid_if_enable_rate_limiting_true_and_period_has_value()
{
var fileReRoute = new FileReRoute
{
DownstreamPathTemplate = "/test",
UpstreamPathTemplate = "/test",
RateLimitOptions = new FileRateLimitRule
{
EnableRateLimiting = true,
Period = "test"
}
};
this.Given(_ => GivenThe(fileReRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInvalid())
.And(_ => ThenTheErrorsContains("RateLimitOptions.Period does not contain integer then s (second), m (minute), h (hour), d (day) e.g. 1m for 1 minute period"))
.BDDfy();
}
[Fact]
public void should_not_be_valid_if_specified_authentication_provider_isnt_registered()
{
var fileReRoute = new FileReRoute
{
DownstreamPathTemplate = "/test",
UpstreamPathTemplate = "/test",
AuthenticationOptions = new FileAuthenticationOptions
{
AuthenticationProviderKey = "JwtLads"
}
};
this.Given(_ => GivenThe(fileReRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInvalid())
.And(_ => ThenTheErrorsContains($"Authentication Options AuthenticationProviderKey:JwtLads,AllowedScopes:[] is unsupported authentication provider"))
.BDDfy();
}
[Fact]
public void should_not_be_valid_if_not_using_service_discovery_and_no_host_and_ports()
{
var fileReRoute = new FileReRoute
{
DownstreamPathTemplate = "/test",
UpstreamPathTemplate = "/test",
};
this.Given(_ => GivenThe(fileReRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInvalid())
.And(_ => ThenTheErrorsContains("When not using service discovery DownstreamHostAndPorts must be set and not empty or Ocelot cannot find your service!"))
.BDDfy();
}
[Fact]
public void should_be_valid_if_using_service_discovery_and_no_host_and_ports()
{
var fileReRoute = new FileReRoute
{
DownstreamPathTemplate = "/test",
UpstreamPathTemplate = "/test",
ServiceName = "Lads"
};
this.Given(_ => GivenThe(fileReRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsValid())
.BDDfy();
}
[Fact]
public void should_be_valid_re_route_using_host_and_port_and_paths()
{
var fileReRoute = new FileReRoute
{
DownstreamPathTemplate = "/test",
UpstreamPathTemplate = "/test",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 5000
}
}
};
this.Given(_ => GivenThe(fileReRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsValid())
.BDDfy();
}
[Fact]
public void should_be_valid_if_specified_authentication_provider_is_registered()
{
const string key = "JwtLads";
var fileReRoute = new FileReRoute
{
DownstreamPathTemplate = "/test",
UpstreamPathTemplate = "/test",
AuthenticationOptions = new FileAuthenticationOptions
{
AuthenticationProviderKey = key
},
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 5000
}
}
};
this.Given(_ => GivenThe(fileReRoute))
.And(_ => GivenAnAuthProvider(key))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsValid())
.BDDfy();
}
[Theory]
[InlineData("1.0")]
[InlineData("1.1")]
[InlineData("2.0")]
[InlineData("1,0")]
[InlineData("1,1")]
[InlineData("2,0")]
[InlineData("1")]
[InlineData("2")]
[InlineData("")]
[InlineData(null)]
public void should_be_valid_re_route_using_downstream_http_version(string version)
{
var fileReRoute = new FileReRoute
{
DownstreamPathTemplate = "/test",
UpstreamPathTemplate = "/test",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 5000,
},
},
DownstreamHttpVersion = version,
};
this.Given(_ => GivenThe(fileReRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsValid())
.BDDfy();
}
[Theory]
[InlineData("retg1.1")]
[InlineData("re2.0")]
[InlineData("1,0a")]
[InlineData("a1,1")]
[InlineData("12,0")]
[InlineData("asdf")]
public void should_be_invalid_re_route_using_downstream_http_version(string version)
{
var fileReRoute = new FileReRoute
{
DownstreamPathTemplate = "/test",
UpstreamPathTemplate = "/test",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 5000,
},
},
DownstreamHttpVersion = version,
};
this.Given(_ => GivenThe(fileReRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInvalid())
.And(_ => ThenTheErrorsContains("'Downstream Http Version' is not in the correct format."))
.BDDfy();
}
private void GivenAnAuthProvider(string key)
{
var schemes = new List<AuthenticationScheme>
{
new AuthenticationScheme(key, key, typeof(FakeAutheHandler))
};
_authProvider
.Setup(x => x.GetAllSchemesAsync())
.ReturnsAsync(schemes);
}
private void ThenTheResultIsValid()
{
_result.IsValid.ShouldBeTrue();
}
private void GivenThe(FileReRoute reRoute)
{
_reRoute = reRoute;
}
private void WhenIValidate()
{
_result = _validator.Validate(_reRoute);
}
private void ThenTheResultIsInvalid()
{
_result.IsValid.ShouldBeFalse();
}
private void ThenTheErrorsContains(string expected)
{
_result.Errors.ShouldContain(x => x.ErrorMessage == expected);
}
private class FakeAutheHandler : IAuthenticationHandler
{
public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
{
throw new System.NotImplementedException();
}
public Task<AuthenticateResult> AuthenticateAsync()
{
throw new System.NotImplementedException();
}
public Task ChallengeAsync(AuthenticationProperties properties)
{
throw new System.NotImplementedException();
}
public Task ForbidAsync(AuthenticationProperties properties)
{
throw new System.NotImplementedException();
}
}
}
}
namespace Ocelot.UnitTests.Configuration.Validation
{
using FluentValidation.Results;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Moq;
using Ocelot.Configuration.File;
using Ocelot.Configuration.Validator;
using Ocelot.Requester;
using Shouldly;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using TestStack.BDDfy;
using Xunit;
public class RouteFluentValidatorTests
{
private readonly RouteFluentValidator _validator;
private readonly Mock<IAuthenticationSchemeProvider> _authProvider;
private QosDelegatingHandlerDelegate _qosDelegatingHandler;
private Mock<IServiceProvider> _serviceProvider;
private FileRoute _route;
private ValidationResult _result;
public RouteFluentValidatorTests()
{
_authProvider = new Mock<IAuthenticationSchemeProvider>();
_serviceProvider = new Mock<IServiceProvider>();
// Todo - replace with mocks
_validator = new RouteFluentValidator(_authProvider.Object, new HostAndPortValidator(), new FileQoSOptionsFluentValidator(_serviceProvider.Object));
}
[Fact]
public void downstream_path_template_should_not_be_empty()
{
var fileRoute = new FileRoute();
this.Given(_ => GivenThe(fileRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInvalid())
.And(_ => ThenTheErrorsContains("Downstream Path Template cannot be empty"))
.BDDfy();
}
[Fact]
public void upstream_path_template_should_not_be_empty()
{
var fileRoute = new FileRoute
{
DownstreamPathTemplate = "test"
};
this.Given(_ => GivenThe(fileRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInvalid())
.And(_ => ThenTheErrorsContains("Upstream Path Template cannot be empty"))
.BDDfy();
}
[Fact]
public void downstream_path_template_should_start_with_forward_slash()
{
var fileRoute = new FileRoute
{
DownstreamPathTemplate = "test"
};
this.Given(_ => GivenThe(fileRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInvalid())
.And(_ => ThenTheErrorsContains("Downstream Path Template test doesnt start with forward slash"))
.BDDfy();
}
[Fact]
public void downstream_path_template_should_not_contain_double_forward_slash()
{
var fileRoute = new FileRoute
{
DownstreamPathTemplate = "//test"
};
this.Given(_ => GivenThe(fileRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInvalid())
.And(_ => ThenTheErrorsContains("Downstream Path Template //test contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature."))
.BDDfy();
}
[Theory]
[InlineData("https://test")]
[InlineData("http://test")]
[InlineData("/test/http://")]
[InlineData("/test/https://")]
public void downstream_path_template_should_not_contain_scheme(string downstreamPathTemplate)
{
var fileRoute = new FileRoute
{
DownstreamPathTemplate = downstreamPathTemplate
};
this.Given(_ => GivenThe(fileRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInvalid())
.And(_ => ThenTheErrorsContains($"Downstream Path Template {downstreamPathTemplate} contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature."))
.BDDfy();
}
[Fact]
public void upstream_path_template_should_start_with_forward_slash()
{
var fileRoute = new FileRoute
{
DownstreamPathTemplate = "/test",
UpstreamPathTemplate = "test"
};
this.Given(_ => GivenThe(fileRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInvalid())
.And(_ => ThenTheErrorsContains("Upstream Path Template test doesnt start with forward slash"))
.BDDfy();
}
[Fact]
public void upstream_path_template_should_not_contain_double_forward_slash()
{
var fileRoute = new FileRoute
{
DownstreamPathTemplate = "/test",
UpstreamPathTemplate = "//test"
};
this.Given(_ => GivenThe(fileRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInvalid())
.And(_ => ThenTheErrorsContains("Upstream Path Template //test contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature."))
.BDDfy();
}
[Theory]
[InlineData("https://test")]
[InlineData("http://test")]
[InlineData("/test/http://")]
[InlineData("/test/https://")]
public void upstream_path_template_should_not_contain_scheme(string upstreamPathTemplate)
{
var fileRoute = new FileRoute
{
DownstreamPathTemplate = "/test",
UpstreamPathTemplate = upstreamPathTemplate
};
this.Given(_ => GivenThe(fileRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInvalid())
.And(_ => ThenTheErrorsContains($"Upstream Path Template {upstreamPathTemplate} contains double forward slash, Ocelot does not support this at the moment. Please raise an issue in GitHib if you need this feature."))
.BDDfy();
}
[Fact]
public void should_not_be_valid_if_enable_rate_limiting_true_and_period_is_empty()
{
var fileRoute = new FileRoute
{
DownstreamPathTemplate = "/test",
UpstreamPathTemplate = "/test",
RateLimitOptions = new FileRateLimitRule
{
EnableRateLimiting = true
}
};
this.Given(_ => GivenThe(fileRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInvalid())
.And(_ => ThenTheErrorsContains("RateLimitOptions.Period is empty"))
.BDDfy();
}
[Fact]
public void should_not_be_valid_if_enable_rate_limiting_true_and_period_has_value()
{
var fileRoute = new FileRoute
{
DownstreamPathTemplate = "/test",
UpstreamPathTemplate = "/test",
RateLimitOptions = new FileRateLimitRule
{
EnableRateLimiting = true,
Period = "test"
}
};
this.Given(_ => GivenThe(fileRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInvalid())
.And(_ => ThenTheErrorsContains("RateLimitOptions.Period does not contain integer then s (second), m (minute), h (hour), d (day) e.g. 1m for 1 minute period"))
.BDDfy();
}
[Fact]
public void should_not_be_valid_if_specified_authentication_provider_isnt_registered()
{
var fileRoute = new FileRoute
{
DownstreamPathTemplate = "/test",
UpstreamPathTemplate = "/test",
AuthenticationOptions = new FileAuthenticationOptions
{
AuthenticationProviderKey = "JwtLads"
}
};
this.Given(_ => GivenThe(fileRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInvalid())
.And(_ => ThenTheErrorsContains($"Authentication Options AuthenticationProviderKey:JwtLads,AllowedScopes:[] is unsupported authentication provider"))
.BDDfy();
}
[Fact]
public void should_not_be_valid_if_not_using_service_discovery_and_no_host_and_ports()
{
var fileRoute = new FileRoute
{
DownstreamPathTemplate = "/test",
UpstreamPathTemplate = "/test",
};
this.Given(_ => GivenThe(fileRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInvalid())
.And(_ => ThenTheErrorsContains("When not using service discovery DownstreamHostAndPorts must be set and not empty or Ocelot cannot find your service!"))
.BDDfy();
}
[Fact]
public void should_be_valid_if_using_service_discovery_and_no_host_and_ports()
{
var fileRoute = new FileRoute
{
DownstreamPathTemplate = "/test",
UpstreamPathTemplate = "/test",
ServiceName = "Lads"
};
this.Given(_ => GivenThe(fileRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsValid())
.BDDfy();
}
[Fact]
public void should_be_valid_re_route_using_host_and_port_and_paths()
{
var fileRoute = new FileRoute
{
DownstreamPathTemplate = "/test",
UpstreamPathTemplate = "/test",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 5000
}
}
};
this.Given(_ => GivenThe(fileRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsValid())
.BDDfy();
}
[Fact]
public void should_be_valid_if_specified_authentication_provider_is_registered()
{
const string key = "JwtLads";
var fileRoute = new FileRoute
{
DownstreamPathTemplate = "/test",
UpstreamPathTemplate = "/test",
AuthenticationOptions = new FileAuthenticationOptions
{
AuthenticationProviderKey = key
},
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 5000
}
}
};
this.Given(_ => GivenThe(fileRoute))
.And(_ => GivenAnAuthProvider(key))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsValid())
.BDDfy();
}
[Theory]
[InlineData("1.0")]
[InlineData("1.1")]
[InlineData("2.0")]
[InlineData("1,0")]
[InlineData("1,1")]
[InlineData("2,0")]
[InlineData("1")]
[InlineData("2")]
[InlineData("")]
[InlineData(null)]
public void should_be_valid_re_route_using_downstream_http_version(string version)
{
var fileRoute = new FileRoute
{
DownstreamPathTemplate = "/test",
UpstreamPathTemplate = "/test",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 5000,
},
},
DownstreamHttpVersion = version,
};
this.Given(_ => GivenThe(fileRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsValid())
.BDDfy();
}
[Theory]
[InlineData("retg1.1")]
[InlineData("re2.0")]
[InlineData("1,0a")]
[InlineData("a1,1")]
[InlineData("12,0")]
[InlineData("asdf")]
public void should_be_invalid_re_route_using_downstream_http_version(string version)
{
var fileRoute = new FileRoute
{
DownstreamPathTemplate = "/test",
UpstreamPathTemplate = "/test",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 5000,
},
},
DownstreamHttpVersion = version,
};
this.Given(_ => GivenThe(fileRoute))
.When(_ => WhenIValidate())
.Then(_ => ThenTheResultIsInvalid())
.And(_ => ThenTheErrorsContains("'Downstream Http Version' is not in the correct format."))
.BDDfy();
}
private void GivenAnAuthProvider(string key)
{
var schemes = new List<AuthenticationScheme>
{
new AuthenticationScheme(key, key, typeof(FakeAutheHandler))
};
_authProvider
.Setup(x => x.GetAllSchemesAsync())
.ReturnsAsync(schemes);
}
private void ThenTheResultIsValid()
{
_result.IsValid.ShouldBeTrue();
}
private void GivenThe(FileRoute route)
{
_route = route;
}
private void WhenIValidate()
{
_result = _validator.Validate(_route);
}
private void ThenTheResultIsInvalid()
{
_result.IsValid.ShouldBeFalse();
}
private void ThenTheErrorsContains(string expected)
{
_result.Errors.ShouldContain(x => x.ErrorMessage == expected);
}
private class FakeAutheHandler : IAuthenticationHandler
{
public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
{
throw new System.NotImplementedException();
}
public Task<AuthenticateResult> AuthenticateAsync()
{
throw new System.NotImplementedException();
}
public Task ChallengeAsync(AuthenticationProperties properties)
{
throw new System.NotImplementedException();
}
public Task ForbidAsync(AuthenticationProperties properties)
{
throw new System.NotImplementedException();
}
}
}
}

View File

@ -1,260 +1,260 @@
namespace Ocelot.UnitTests.Consul
{
using global::Consul;
using Microsoft.Extensions.Options;
using Moq;
using Newtonsoft.Json;
using Ocelot.Cache;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.File;
using Ocelot.Configuration.Repository;
using Ocelot.Logging;
using Provider.Consul;
using Responses;
using Shouldly;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using TestStack.BDDfy;
using Xunit;
public class ConsulFileConfigurationRepositoryTests
{
private ConsulFileConfigurationRepository _repo;
private Mock<IOptions<FileConfiguration>> _options;
private Mock<IOcelotCache<FileConfiguration>> _cache;
private Mock<IConsulClientFactory> _factory;
private Mock<IOcelotLoggerFactory> _loggerFactory;
private Mock<IConsulClient> _client;
private Mock<IKVEndpoint> _kvEndpoint;
private FileConfiguration _fileConfiguration;
private Response _setResult;
private Response<FileConfiguration> _getResult;
public ConsulFileConfigurationRepositoryTests()
{
_cache = new Mock<IOcelotCache<FileConfiguration>>();
_loggerFactory = new Mock<IOcelotLoggerFactory>();
_options = new Mock<IOptions<FileConfiguration>>();
_factory = new Mock<IConsulClientFactory>();
_client = new Mock<IConsulClient>();
_kvEndpoint = new Mock<IKVEndpoint>();
_client
.Setup(x => x.KV)
.Returns(_kvEndpoint.Object);
_factory
.Setup(x => x.Get(It.IsAny<ConsulRegistryConfiguration>()))
.Returns(_client.Object);
_options
.SetupGet(x => x.Value)
.Returns(() => _fileConfiguration);
}
[Fact]
public void should_set_config()
{
var config = FakeFileConfiguration();
this.Given(_ => GivenIHaveAConfiguration(config))
.And(_ => GivenWritingToConsulSucceeds())
.When(_ => WhenISetTheConfiguration())
.Then(_ => ThenTheConfigurationIsStoredAs(config))
.BDDfy();
}
[Fact]
public void should_get_config()
{
var config = FakeFileConfiguration();
this.Given(_ => GivenIHaveAConfiguration(config))
.And(_ => GivenFetchFromConsulSucceeds())
.When(_ => WhenIGetTheConfiguration())
.Then(_ => ThenTheConfigurationIs(config))
.BDDfy();
}
[Fact]
public void should_get_null_config()
{
var config = FakeFileConfiguration();
this.Given(_ => GivenIHaveAConfiguration(config))
.Given(_ => GivenFetchFromConsulReturnsNull())
.When(_ => WhenIGetTheConfiguration())
.Then(_ => ThenTheConfigurationIsNull())
.BDDfy();
}
[Fact]
public void should_get_config_from_cache()
{
var config = FakeFileConfiguration();
this.Given(_ => GivenIHaveAConfiguration(config))
.And(_ => GivenFetchFromCacheSucceeds())
.When(_ => WhenIGetTheConfiguration())
.Then(_ => ThenTheConfigurationIs(config))
.BDDfy();
}
[Fact]
public void should_set_config_key()
{
var config = FakeFileConfiguration();
this.Given(_ => GivenIHaveAConfiguration(config))
.And(_ => GivenTheConfigKeyComesFromFileConfig("Tom"))
.And(_ => GivenFetchFromConsulSucceeds())
.When(_ => WhenIGetTheConfiguration())
.And(_ => ThenTheConfigKeyIs("Tom"))
.BDDfy();
}
[Fact]
public void should_set_default_config_key()
{
var config = FakeFileConfiguration();
this.Given(_ => GivenIHaveAConfiguration(config))
.And(_ => GivenFetchFromConsulSucceeds())
.When(_ => WhenIGetTheConfiguration())
.And(_ => ThenTheConfigKeyIs("InternalConfiguration"))
.BDDfy();
}
private void ThenTheConfigKeyIs(string expected)
{
_kvEndpoint
.Verify(x => x.Get(expected, It.IsAny<CancellationToken>()), Times.Once);
}
private void GivenTheConfigKeyComesFromFileConfig(string key)
{
_fileConfiguration.GlobalConfiguration.ServiceDiscoveryProvider.ConfigurationKey = key;
_repo = new ConsulFileConfigurationRepository(_options.Object, _cache.Object, _factory.Object, _loggerFactory.Object);
}
private void ThenTheConfigurationIsNull()
{
_getResult.Data.ShouldBeNull();
}
private void ThenTheConfigurationIs(FileConfiguration config)
{
var expected = JsonConvert.SerializeObject(config, Formatting.Indented);
var result = JsonConvert.SerializeObject(_getResult.Data, Formatting.Indented);
result.ShouldBe(expected);
}
private async Task WhenIGetTheConfiguration()
{
_getResult = await _repo.Get();
}
private void GivenWritingToConsulSucceeds()
{
var response = new WriteResult<bool>();
response.Response = true;
_kvEndpoint
.Setup(x => x.Put(It.IsAny<KVPair>(), It.IsAny<CancellationToken>())).ReturnsAsync(response);
}
private void GivenFetchFromCacheSucceeds()
{
_cache.Setup(x => x.Get(It.IsAny<string>(), It.IsAny<string>())).Returns(_fileConfiguration);
}
private void GivenFetchFromConsulReturnsNull()
{
QueryResult<KVPair> result = new QueryResult<KVPair>();
_kvEndpoint
.Setup(x => x.Get(It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(result);
}
private void GivenFetchFromConsulSucceeds()
{
var json = JsonConvert.SerializeObject(_fileConfiguration, Formatting.Indented);
var bytes = Encoding.UTF8.GetBytes(json);
var kvp = new KVPair("OcelotConfiguration");
kvp.Value = bytes;
var query = new QueryResult<KVPair>();
query.Response = kvp;
_kvEndpoint
.Setup(x => x.Get(It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(query);
}
private void ThenTheConfigurationIsStoredAs(FileConfiguration config)
{
var json = JsonConvert.SerializeObject(config, Formatting.Indented);
var bytes = Encoding.UTF8.GetBytes(json);
_kvEndpoint
.Verify(x => x.Put(It.Is<KVPair>(k => k.Value.SequenceEqual(bytes)), It.IsAny<CancellationToken>()), Times.Once);
}
private async Task WhenISetTheConfiguration()
{
_setResult = await _repo.Set(_fileConfiguration);
}
private void GivenIHaveAConfiguration(FileConfiguration config)
{
_fileConfiguration = config;
_repo = new ConsulFileConfigurationRepository(_options.Object, _cache.Object, _factory.Object, _loggerFactory.Object);
}
private FileConfiguration FakeFileConfiguration()
{
var reRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "123.12.12.12",
Port = 80,
}
},
DownstreamScheme = "https",
DownstreamPathTemplate = "/asdfs/test/{test}"
}
};
var globalConfiguration = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{
Scheme = "https",
Port = 198,
Host = "blah"
}
};
return new FileConfiguration
{
GlobalConfiguration = globalConfiguration,
ReRoutes = reRoutes
};
}
}
}
namespace Ocelot.UnitTests.Consul
{
using global::Consul;
using Microsoft.Extensions.Options;
using Moq;
using Newtonsoft.Json;
using Ocelot.Cache;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.File;
using Ocelot.Configuration.Repository;
using Ocelot.Logging;
using Provider.Consul;
using Responses;
using Shouldly;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using TestStack.BDDfy;
using Xunit;
public class ConsulFileConfigurationRepositoryTests
{
private ConsulFileConfigurationRepository _repo;
private Mock<IOptions<FileConfiguration>> _options;
private Mock<IOcelotCache<FileConfiguration>> _cache;
private Mock<IConsulClientFactory> _factory;
private Mock<IOcelotLoggerFactory> _loggerFactory;
private Mock<IConsulClient> _client;
private Mock<IKVEndpoint> _kvEndpoint;
private FileConfiguration _fileConfiguration;
private Response _setResult;
private Response<FileConfiguration> _getResult;
public ConsulFileConfigurationRepositoryTests()
{
_cache = new Mock<IOcelotCache<FileConfiguration>>();
_loggerFactory = new Mock<IOcelotLoggerFactory>();
_options = new Mock<IOptions<FileConfiguration>>();
_factory = new Mock<IConsulClientFactory>();
_client = new Mock<IConsulClient>();
_kvEndpoint = new Mock<IKVEndpoint>();
_client
.Setup(x => x.KV)
.Returns(_kvEndpoint.Object);
_factory
.Setup(x => x.Get(It.IsAny<ConsulRegistryConfiguration>()))
.Returns(_client.Object);
_options
.SetupGet(x => x.Value)
.Returns(() => _fileConfiguration);
}
[Fact]
public void should_set_config()
{
var config = FakeFileConfiguration();
this.Given(_ => GivenIHaveAConfiguration(config))
.And(_ => GivenWritingToConsulSucceeds())
.When(_ => WhenISetTheConfiguration())
.Then(_ => ThenTheConfigurationIsStoredAs(config))
.BDDfy();
}
[Fact]
public void should_get_config()
{
var config = FakeFileConfiguration();
this.Given(_ => GivenIHaveAConfiguration(config))
.And(_ => GivenFetchFromConsulSucceeds())
.When(_ => WhenIGetTheConfiguration())
.Then(_ => ThenTheConfigurationIs(config))
.BDDfy();
}
[Fact]
public void should_get_null_config()
{
var config = FakeFileConfiguration();
this.Given(_ => GivenIHaveAConfiguration(config))
.Given(_ => GivenFetchFromConsulReturnsNull())
.When(_ => WhenIGetTheConfiguration())
.Then(_ => ThenTheConfigurationIsNull())
.BDDfy();
}
[Fact]
public void should_get_config_from_cache()
{
var config = FakeFileConfiguration();
this.Given(_ => GivenIHaveAConfiguration(config))
.And(_ => GivenFetchFromCacheSucceeds())
.When(_ => WhenIGetTheConfiguration())
.Then(_ => ThenTheConfigurationIs(config))
.BDDfy();
}
[Fact]
public void should_set_config_key()
{
var config = FakeFileConfiguration();
this.Given(_ => GivenIHaveAConfiguration(config))
.And(_ => GivenTheConfigKeyComesFromFileConfig("Tom"))
.And(_ => GivenFetchFromConsulSucceeds())
.When(_ => WhenIGetTheConfiguration())
.And(_ => ThenTheConfigKeyIs("Tom"))
.BDDfy();
}
[Fact]
public void should_set_default_config_key()
{
var config = FakeFileConfiguration();
this.Given(_ => GivenIHaveAConfiguration(config))
.And(_ => GivenFetchFromConsulSucceeds())
.When(_ => WhenIGetTheConfiguration())
.And(_ => ThenTheConfigKeyIs("InternalConfiguration"))
.BDDfy();
}
private void ThenTheConfigKeyIs(string expected)
{
_kvEndpoint
.Verify(x => x.Get(expected, It.IsAny<CancellationToken>()), Times.Once);
}
private void GivenTheConfigKeyComesFromFileConfig(string key)
{
_fileConfiguration.GlobalConfiguration.ServiceDiscoveryProvider.ConfigurationKey = key;
_repo = new ConsulFileConfigurationRepository(_options.Object, _cache.Object, _factory.Object, _loggerFactory.Object);
}
private void ThenTheConfigurationIsNull()
{
_getResult.Data.ShouldBeNull();
}
private void ThenTheConfigurationIs(FileConfiguration config)
{
var expected = JsonConvert.SerializeObject(config, Formatting.Indented);
var result = JsonConvert.SerializeObject(_getResult.Data, Formatting.Indented);
result.ShouldBe(expected);
}
private async Task WhenIGetTheConfiguration()
{
_getResult = await _repo.Get();
}
private void GivenWritingToConsulSucceeds()
{
var response = new WriteResult<bool>();
response.Response = true;
_kvEndpoint
.Setup(x => x.Put(It.IsAny<KVPair>(), It.IsAny<CancellationToken>())).ReturnsAsync(response);
}
private void GivenFetchFromCacheSucceeds()
{
_cache.Setup(x => x.Get(It.IsAny<string>(), It.IsAny<string>())).Returns(_fileConfiguration);
}
private void GivenFetchFromConsulReturnsNull()
{
QueryResult<KVPair> result = new QueryResult<KVPair>();
_kvEndpoint
.Setup(x => x.Get(It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(result);
}
private void GivenFetchFromConsulSucceeds()
{
var json = JsonConvert.SerializeObject(_fileConfiguration, Formatting.Indented);
var bytes = Encoding.UTF8.GetBytes(json);
var kvp = new KVPair("OcelotConfiguration");
kvp.Value = bytes;
var query = new QueryResult<KVPair>();
query.Response = kvp;
_kvEndpoint
.Setup(x => x.Get(It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(query);
}
private void ThenTheConfigurationIsStoredAs(FileConfiguration config)
{
var json = JsonConvert.SerializeObject(config, Formatting.Indented);
var bytes = Encoding.UTF8.GetBytes(json);
_kvEndpoint
.Verify(x => x.Put(It.Is<KVPair>(k => k.Value.SequenceEqual(bytes)), It.IsAny<CancellationToken>()), Times.Once);
}
private async Task WhenISetTheConfiguration()
{
_setResult = await _repo.Set(_fileConfiguration);
}
private void GivenIHaveAConfiguration(FileConfiguration config)
{
_fileConfiguration = config;
_repo = new ConsulFileConfigurationRepository(_options.Object, _cache.Object, _factory.Object, _loggerFactory.Object);
}
private FileConfiguration FakeFileConfiguration()
{
var routes = new List<FileRoute>
{
new FileRoute
{
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "123.12.12.12",
Port = 80,
}
},
DownstreamScheme = "https",
DownstreamPathTemplate = "/asdfs/test/{test}"
}
};
var globalConfiguration = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{
Scheme = "https",
Port = 198,
Host = "blah"
}
};
return new FileConfiguration
{
GlobalConfiguration = globalConfiguration,
Routes = routes
};
}
}
}

View File

@ -1,57 +1,57 @@
using Ocelot.Configuration.Builder;
namespace Ocelot.UnitTests.Consul
{
using Microsoft.Extensions.DependencyInjection;
using Moq;
using Ocelot.Configuration;
using Ocelot.Logging;
using Provider.Consul;
using Shouldly;
using System;
using Xunit;
public class ProviderFactoryTests
{
private readonly IServiceProvider _provider;
public ProviderFactoryTests()
{
var services = new ServiceCollection();
var loggerFactory = new Mock<IOcelotLoggerFactory>();
var logger = new Mock<IOcelotLogger>();
loggerFactory.Setup(x => x.CreateLogger<Consul>()).Returns(logger.Object);
loggerFactory.Setup(x => x.CreateLogger<PollConsul>()).Returns(logger.Object);
var consulFactory = new Mock<IConsulClientFactory>();
services.AddSingleton<IConsulClientFactory>(consulFactory.Object);
services.AddSingleton<IOcelotLoggerFactory>(loggerFactory.Object);
_provider = services.BuildServiceProvider();
}
[Fact]
public void should_return_ConsulServiceDiscoveryProvider()
{
var reRoute = new DownstreamReRouteBuilder()
.WithServiceName("")
.Build();
var provider = ConsulProviderFactory.Get(_provider, new ServiceProviderConfiguration("", "", "", 1, "", "", 1), reRoute);
provider.ShouldBeOfType<Consul>();
}
[Fact]
public void should_return_PollingConsulServiceDiscoveryProvider()
{
var stopsPollerFromPolling = 10000;
var reRoute = new DownstreamReRouteBuilder()
.WithServiceName("")
.Build();
var provider = ConsulProviderFactory.Get(_provider, new ServiceProviderConfiguration("pollconsul", "http", "", 1, "", "", stopsPollerFromPolling), reRoute);
var pollProvider = provider as PollConsul;
pollProvider.ShouldNotBeNull();
pollProvider.Dispose();
}
}
}
using Ocelot.Configuration.Builder;
namespace Ocelot.UnitTests.Consul
{
using Microsoft.Extensions.DependencyInjection;
using Moq;
using Ocelot.Configuration;
using Ocelot.Logging;
using Provider.Consul;
using Shouldly;
using System;
using Xunit;
public class ProviderFactoryTests
{
private readonly IServiceProvider _provider;
public ProviderFactoryTests()
{
var services = new ServiceCollection();
var loggerFactory = new Mock<IOcelotLoggerFactory>();
var logger = new Mock<IOcelotLogger>();
loggerFactory.Setup(x => x.CreateLogger<Consul>()).Returns(logger.Object);
loggerFactory.Setup(x => x.CreateLogger<PollConsul>()).Returns(logger.Object);
var consulFactory = new Mock<IConsulClientFactory>();
services.AddSingleton<IConsulClientFactory>(consulFactory.Object);
services.AddSingleton<IOcelotLoggerFactory>(loggerFactory.Object);
_provider = services.BuildServiceProvider();
}
[Fact]
public void should_return_ConsulServiceDiscoveryProvider()
{
var route = new DownstreamRouteBuilder()
.WithServiceName("")
.Build();
var provider = ConsulProviderFactory.Get(_provider, new ServiceProviderConfiguration("", "", "", 1, "", "", 1), route);
provider.ShouldBeOfType<Consul>();
}
[Fact]
public void should_return_PollingConsulServiceDiscoveryProvider()
{
var stopsPollerFromPolling = 10000;
var route = new DownstreamRouteBuilder()
.WithServiceName("")
.Build();
var provider = ConsulProviderFactory.Get(_provider, new ServiceProviderConfiguration("pollconsul", "http", "", 1, "", "", stopsPollerFromPolling), route);
var pollProvider = provider as PollConsul;
pollProvider.ShouldNotBeNull();
pollProvider.Dispose();
}
}
}

View File

@ -1,334 +1,334 @@
namespace Ocelot.UnitTests.DependencyInjection
{
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Moq;
using Newtonsoft.Json;
using Ocelot.Configuration.File;
using Ocelot.DependencyInjection;
using Shouldly;
using System.Collections.Generic;
using System.IO;
using TestStack.BDDfy;
using Xunit;
public class ConfigurationBuilderExtensionsTests
{
private IConfigurationRoot _configuration;
private string _result;
private IConfigurationRoot _configRoot;
private FileConfiguration _globalConfig;
private FileConfiguration _reRouteA;
private FileConfiguration _reRouteB;
private FileConfiguration _aggregate;
private FileConfiguration _envSpecific;
private Mock<IWebHostEnvironment> _hostingEnvironment;
public ConfigurationBuilderExtensionsTests()
{
_hostingEnvironment = new Mock<IWebHostEnvironment>();
// Clean up config files before each test
var subConfigFiles = new DirectoryInfo(".").GetFiles("ocelot.*.json");
foreach (var config in subConfigFiles)
{
config.Delete();
}
}
[Fact]
public void should_add_base_url_to_config()
{
this.Given(_ => GivenTheBaseUrl("test"))
.When(_ => WhenIGet("BaseUrl"))
.Then(_ => ThenTheResultIs("test"))
.BDDfy();
}
[Fact]
public void should_merge_files()
{
this.Given(_ => GivenMultipleConfigurationFiles("", false))
.And(_ => GivenTheEnvironmentIs(null))
.When(_ => WhenIAddOcelotConfiguration())
.Then(_ => ThenTheConfigsAreMerged())
.BDDfy();
}
[Fact]
public void should_merge_files_except_env()
{
this.Given(_ => GivenMultipleConfigurationFiles("", true))
.And(_ => GivenTheEnvironmentIs("Env"))
.When(_ => WhenIAddOcelotConfiguration())
.Then(_ => ThenTheConfigsAreMerged())
.And(_ => NotContainsEnvSpecificConfig())
.BDDfy();
}
[Fact]
public void should_merge_files_in_specific_folder()
{
string configFolder = "ConfigFiles";
this.Given(_ => GivenMultipleConfigurationFiles(configFolder, false))
.When(_ => WhenIAddOcelotConfigurationWithSpecificFolder(configFolder))
.Then(_ => ThenTheConfigsAreMerged())
.BDDfy();
}
private void GivenMultipleConfigurationFiles(string folder, bool addEnvSpecificConfig)
{
if (!string.IsNullOrEmpty(folder))
{
Directory.CreateDirectory(folder);
}
_globalConfig = new FileConfiguration
{
GlobalConfiguration = new FileGlobalConfiguration
{
BaseUrl = "BaseUrl",
RateLimitOptions = new FileRateLimitOptions
{
HttpStatusCode = 500,
ClientIdHeader = "ClientIdHeader",
DisableRateLimitHeaders = true,
QuotaExceededMessage = "QuotaExceededMessage",
RateLimitCounterPrefix = "RateLimitCounterPrefix"
},
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{
Scheme = "https",
Host = "Host",
Port = 80,
Type = "Type"
},
RequestIdKey = "RequestIdKey"
}
};
_reRouteA = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamScheme = "DownstreamScheme",
DownstreamPathTemplate = "DownstreamPathTemplate",
Key = "Key",
UpstreamHost = "UpstreamHost",
UpstreamHttpMethod = new List<string>
{
"UpstreamHttpMethod"
},
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "Host",
Port = 80
}
}
}
}
};
_reRouteB = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamScheme = "DownstreamSchemeB",
DownstreamPathTemplate = "DownstreamPathTemplateB",
Key = "KeyB",
UpstreamHost = "UpstreamHostB",
UpstreamHttpMethod = new List<string>
{
"UpstreamHttpMethodB"
},
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "HostB",
Port = 80
}
}
},
new FileReRoute
{
DownstreamScheme = "DownstreamSchemeBB",
DownstreamPathTemplate = "DownstreamPathTemplateBB",
Key = "KeyBB",
UpstreamHost = "UpstreamHostBB",
UpstreamHttpMethod = new List<string>
{
"UpstreamHttpMethodBB"
},
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "HostBB",
Port = 80
}
}
}
}
};
_aggregate = new FileConfiguration
{
Aggregates = new List<FileAggregateReRoute>
{
new FileAggregateReRoute
{
ReRouteKeys = new List<string>
{
"KeyB",
"KeyBB"
},
UpstreamPathTemplate = "UpstreamPathTemplate",
},
new FileAggregateReRoute
{
ReRouteKeys = new List<string>
{
"KeyB",
"KeyBB"
},
UpstreamPathTemplate = "UpstreamPathTemplate",
}
}
};
_envSpecific = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamScheme = "DownstreamSchemeSpec",
DownstreamPathTemplate = "DownstreamPathTemplateSpec",
Key = "KeySpec",
UpstreamHost = "UpstreamHostSpec",
UpstreamHttpMethod = new List<string>
{
"UpstreamHttpMethodSpec"
},
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "HostSpec",
Port = 80
}
}
}
}
};
string globalFilename = Path.Combine(folder, "ocelot.global.json");
string reroutesAFilename = Path.Combine(folder, "ocelot.reRoutesA.json");
string reroutesBFilename = Path.Combine(folder, "ocelot.reRoutesB.json");
string aggregatesFilename = Path.Combine(folder, "ocelot.aggregates.json");
File.WriteAllText(globalFilename, JsonConvert.SerializeObject(_globalConfig));
File.WriteAllText(reroutesAFilename, JsonConvert.SerializeObject(_reRouteA));
File.WriteAllText(reroutesBFilename, JsonConvert.SerializeObject(_reRouteB));
File.WriteAllText(aggregatesFilename, JsonConvert.SerializeObject(_aggregate));
if (addEnvSpecificConfig)
{
string envSpecificFilename = Path.Combine(folder, "ocelot.Env.json");
File.WriteAllText(envSpecificFilename, JsonConvert.SerializeObject(_envSpecific));
}
}
private void GivenTheEnvironmentIs(string env)
{
_hostingEnvironment.SetupGet(x => x.EnvironmentName).Returns(env);
}
private void WhenIAddOcelotConfiguration()
{
IConfigurationBuilder builder = new ConfigurationBuilder();
builder.AddOcelot(_hostingEnvironment.Object);
_configRoot = builder.Build();
}
private void WhenIAddOcelotConfigurationWithSpecificFolder(string folder)
{
IConfigurationBuilder builder = new ConfigurationBuilder();
builder.AddOcelot(folder, _hostingEnvironment.Object);
_configRoot = builder.Build();
}
private void ThenTheConfigsAreMerged()
{
var fc = (FileConfiguration)_configRoot.Get(typeof(FileConfiguration));
fc.GlobalConfiguration.BaseUrl.ShouldBe(_globalConfig.GlobalConfiguration.BaseUrl);
fc.GlobalConfiguration.RateLimitOptions.ClientIdHeader.ShouldBe(_globalConfig.GlobalConfiguration.RateLimitOptions.ClientIdHeader);
fc.GlobalConfiguration.RateLimitOptions.DisableRateLimitHeaders.ShouldBe(_globalConfig.GlobalConfiguration.RateLimitOptions.DisableRateLimitHeaders);
fc.GlobalConfiguration.RateLimitOptions.HttpStatusCode.ShouldBe(_globalConfig.GlobalConfiguration.RateLimitOptions.HttpStatusCode);
fc.GlobalConfiguration.RateLimitOptions.QuotaExceededMessage.ShouldBe(_globalConfig.GlobalConfiguration.RateLimitOptions.QuotaExceededMessage);
fc.GlobalConfiguration.RateLimitOptions.RateLimitCounterPrefix.ShouldBe(_globalConfig.GlobalConfiguration.RateLimitOptions.RateLimitCounterPrefix);
fc.GlobalConfiguration.RequestIdKey.ShouldBe(_globalConfig.GlobalConfiguration.RequestIdKey);
fc.GlobalConfiguration.ServiceDiscoveryProvider.Scheme.ShouldBe(_globalConfig.GlobalConfiguration.ServiceDiscoveryProvider.Scheme);
fc.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(_globalConfig.GlobalConfiguration.ServiceDiscoveryProvider.Host);
fc.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(_globalConfig.GlobalConfiguration.ServiceDiscoveryProvider.Port);
fc.GlobalConfiguration.ServiceDiscoveryProvider.Type.ShouldBe(_globalConfig.GlobalConfiguration.ServiceDiscoveryProvider.Type);
fc.ReRoutes.Count.ShouldBe(_reRouteA.ReRoutes.Count + _reRouteB.ReRoutes.Count);
fc.ReRoutes.ShouldContain(x => x.DownstreamPathTemplate == _reRouteA.ReRoutes[0].DownstreamPathTemplate);
fc.ReRoutes.ShouldContain(x => x.DownstreamPathTemplate == _reRouteB.ReRoutes[0].DownstreamPathTemplate);
fc.ReRoutes.ShouldContain(x => x.DownstreamPathTemplate == _reRouteB.ReRoutes[1].DownstreamPathTemplate);
fc.ReRoutes.ShouldContain(x => x.DownstreamScheme == _reRouteA.ReRoutes[0].DownstreamScheme);
fc.ReRoutes.ShouldContain(x => x.DownstreamScheme == _reRouteB.ReRoutes[0].DownstreamScheme);
fc.ReRoutes.ShouldContain(x => x.DownstreamScheme == _reRouteB.ReRoutes[1].DownstreamScheme);
fc.ReRoutes.ShouldContain(x => x.Key == _reRouteA.ReRoutes[0].Key);
fc.ReRoutes.ShouldContain(x => x.Key == _reRouteB.ReRoutes[0].Key);
fc.ReRoutes.ShouldContain(x => x.Key == _reRouteB.ReRoutes[1].Key);
fc.ReRoutes.ShouldContain(x => x.UpstreamHost == _reRouteA.ReRoutes[0].UpstreamHost);
fc.ReRoutes.ShouldContain(x => x.UpstreamHost == _reRouteB.ReRoutes[0].UpstreamHost);
fc.ReRoutes.ShouldContain(x => x.UpstreamHost == _reRouteB.ReRoutes[1].UpstreamHost);
fc.Aggregates.Count.ShouldBe(_aggregate.Aggregates.Count);
}
private void NotContainsEnvSpecificConfig()
{
var fc = (FileConfiguration)_configRoot.Get(typeof(FileConfiguration));
fc.ReRoutes.ShouldNotContain(x => x.DownstreamScheme == _envSpecific.ReRoutes[0].DownstreamScheme);
fc.ReRoutes.ShouldNotContain(x => x.DownstreamPathTemplate == _envSpecific.ReRoutes[0].DownstreamPathTemplate);
fc.ReRoutes.ShouldNotContain(x => x.Key == _envSpecific.ReRoutes[0].Key);
}
private void GivenTheBaseUrl(string baseUrl)
{
#pragma warning disable CS0618
var builder = new ConfigurationBuilder()
.AddOcelotBaseUrl(baseUrl);
#pragma warning restore CS0618
_configuration = builder.Build();
}
private void WhenIGet(string key)
{
_result = _configuration.GetValue(key, "");
}
private void ThenTheResultIs(string expected)
{
_result.ShouldBe(expected);
}
}
}
namespace Ocelot.UnitTests.DependencyInjection
{
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Moq;
using Newtonsoft.Json;
using Ocelot.Configuration.File;
using Ocelot.DependencyInjection;
using Shouldly;
using System.Collections.Generic;
using System.IO;
using TestStack.BDDfy;
using Xunit;
public class ConfigurationBuilderExtensionsTests
{
private IConfigurationRoot _configuration;
private string _result;
private IConfigurationRoot _configRoot;
private FileConfiguration _globalConfig;
private FileConfiguration _routeA;
private FileConfiguration _routeB;
private FileConfiguration _aggregate;
private FileConfiguration _envSpecific;
private Mock<IWebHostEnvironment> _hostingEnvironment;
public ConfigurationBuilderExtensionsTests()
{
_hostingEnvironment = new Mock<IWebHostEnvironment>();
// Clean up config files before each test
var subConfigFiles = new DirectoryInfo(".").GetFiles("ocelot.*.json");
foreach (var config in subConfigFiles)
{
config.Delete();
}
}
[Fact]
public void should_add_base_url_to_config()
{
this.Given(_ => GivenTheBaseUrl("test"))
.When(_ => WhenIGet("BaseUrl"))
.Then(_ => ThenTheResultIs("test"))
.BDDfy();
}
[Fact]
public void should_merge_files()
{
this.Given(_ => GivenMultipleConfigurationFiles("", false))
.And(_ => GivenTheEnvironmentIs(null))
.When(_ => WhenIAddOcelotConfiguration())
.Then(_ => ThenTheConfigsAreMerged())
.BDDfy();
}
[Fact]
public void should_merge_files_except_env()
{
this.Given(_ => GivenMultipleConfigurationFiles("", true))
.And(_ => GivenTheEnvironmentIs("Env"))
.When(_ => WhenIAddOcelotConfiguration())
.Then(_ => ThenTheConfigsAreMerged())
.And(_ => NotContainsEnvSpecificConfig())
.BDDfy();
}
[Fact]
public void should_merge_files_in_specific_folder()
{
string configFolder = "ConfigFiles";
this.Given(_ => GivenMultipleConfigurationFiles(configFolder, false))
.When(_ => WhenIAddOcelotConfigurationWithSpecificFolder(configFolder))
.Then(_ => ThenTheConfigsAreMerged())
.BDDfy();
}
private void GivenMultipleConfigurationFiles(string folder, bool addEnvSpecificConfig)
{
if (!string.IsNullOrEmpty(folder))
{
Directory.CreateDirectory(folder);
}
_globalConfig = new FileConfiguration
{
GlobalConfiguration = new FileGlobalConfiguration
{
BaseUrl = "BaseUrl",
RateLimitOptions = new FileRateLimitOptions
{
HttpStatusCode = 500,
ClientIdHeader = "ClientIdHeader",
DisableRateLimitHeaders = true,
QuotaExceededMessage = "QuotaExceededMessage",
RateLimitCounterPrefix = "RateLimitCounterPrefix"
},
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{
Scheme = "https",
Host = "Host",
Port = 80,
Type = "Type"
},
RequestIdKey = "RequestIdKey"
}
};
_routeA = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamScheme = "DownstreamScheme",
DownstreamPathTemplate = "DownstreamPathTemplate",
Key = "Key",
UpstreamHost = "UpstreamHost",
UpstreamHttpMethod = new List<string>
{
"UpstreamHttpMethod"
},
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "Host",
Port = 80
}
}
}
}
};
_routeB = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamScheme = "DownstreamSchemeB",
DownstreamPathTemplate = "DownstreamPathTemplateB",
Key = "KeyB",
UpstreamHost = "UpstreamHostB",
UpstreamHttpMethod = new List<string>
{
"UpstreamHttpMethodB"
},
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "HostB",
Port = 80
}
}
},
new FileRoute
{
DownstreamScheme = "DownstreamSchemeBB",
DownstreamPathTemplate = "DownstreamPathTemplateBB",
Key = "KeyBB",
UpstreamHost = "UpstreamHostBB",
UpstreamHttpMethod = new List<string>
{
"UpstreamHttpMethodBB"
},
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "HostBB",
Port = 80
}
}
}
}
};
_aggregate = new FileConfiguration
{
Aggregates = new List<FileAggregateRoute>
{
new FileAggregateRoute
{
RouteKeys = new List<string>
{
"KeyB",
"KeyBB"
},
UpstreamPathTemplate = "UpstreamPathTemplate",
},
new FileAggregateRoute
{
RouteKeys = new List<string>
{
"KeyB",
"KeyBB"
},
UpstreamPathTemplate = "UpstreamPathTemplate",
}
}
};
_envSpecific = new FileConfiguration
{
Routes = new List<FileRoute>
{
new FileRoute
{
DownstreamScheme = "DownstreamSchemeSpec",
DownstreamPathTemplate = "DownstreamPathTemplateSpec",
Key = "KeySpec",
UpstreamHost = "UpstreamHostSpec",
UpstreamHttpMethod = new List<string>
{
"UpstreamHttpMethodSpec"
},
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "HostSpec",
Port = 80
}
}
}
}
};
string globalFilename = Path.Combine(folder, "ocelot.global.json");
string routesAFilename = Path.Combine(folder, "ocelot.routesA.json");
string routesBFilename = Path.Combine(folder, "ocelot.routesB.json");
string aggregatesFilename = Path.Combine(folder, "ocelot.aggregates.json");
File.WriteAllText(globalFilename, JsonConvert.SerializeObject(_globalConfig));
File.WriteAllText(routesAFilename, JsonConvert.SerializeObject(_routeA));
File.WriteAllText(routesBFilename, JsonConvert.SerializeObject(_routeB));
File.WriteAllText(aggregatesFilename, JsonConvert.SerializeObject(_aggregate));
if (addEnvSpecificConfig)
{
string envSpecificFilename = Path.Combine(folder, "ocelot.Env.json");
File.WriteAllText(envSpecificFilename, JsonConvert.SerializeObject(_envSpecific));
}
}
private void GivenTheEnvironmentIs(string env)
{
_hostingEnvironment.SetupGet(x => x.EnvironmentName).Returns(env);
}
private void WhenIAddOcelotConfiguration()
{
IConfigurationBuilder builder = new ConfigurationBuilder();
builder.AddOcelot(_hostingEnvironment.Object);
_configRoot = builder.Build();
}
private void WhenIAddOcelotConfigurationWithSpecificFolder(string folder)
{
IConfigurationBuilder builder = new ConfigurationBuilder();
builder.AddOcelot(folder, _hostingEnvironment.Object);
_configRoot = builder.Build();
}
private void ThenTheConfigsAreMerged()
{
var fc = (FileConfiguration)_configRoot.Get(typeof(FileConfiguration));
fc.GlobalConfiguration.BaseUrl.ShouldBe(_globalConfig.GlobalConfiguration.BaseUrl);
fc.GlobalConfiguration.RateLimitOptions.ClientIdHeader.ShouldBe(_globalConfig.GlobalConfiguration.RateLimitOptions.ClientIdHeader);
fc.GlobalConfiguration.RateLimitOptions.DisableRateLimitHeaders.ShouldBe(_globalConfig.GlobalConfiguration.RateLimitOptions.DisableRateLimitHeaders);
fc.GlobalConfiguration.RateLimitOptions.HttpStatusCode.ShouldBe(_globalConfig.GlobalConfiguration.RateLimitOptions.HttpStatusCode);
fc.GlobalConfiguration.RateLimitOptions.QuotaExceededMessage.ShouldBe(_globalConfig.GlobalConfiguration.RateLimitOptions.QuotaExceededMessage);
fc.GlobalConfiguration.RateLimitOptions.RateLimitCounterPrefix.ShouldBe(_globalConfig.GlobalConfiguration.RateLimitOptions.RateLimitCounterPrefix);
fc.GlobalConfiguration.RequestIdKey.ShouldBe(_globalConfig.GlobalConfiguration.RequestIdKey);
fc.GlobalConfiguration.ServiceDiscoveryProvider.Scheme.ShouldBe(_globalConfig.GlobalConfiguration.ServiceDiscoveryProvider.Scheme);
fc.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(_globalConfig.GlobalConfiguration.ServiceDiscoveryProvider.Host);
fc.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(_globalConfig.GlobalConfiguration.ServiceDiscoveryProvider.Port);
fc.GlobalConfiguration.ServiceDiscoveryProvider.Type.ShouldBe(_globalConfig.GlobalConfiguration.ServiceDiscoveryProvider.Type);
fc.Routes.Count.ShouldBe(_routeA.Routes.Count + _routeB.Routes.Count);
fc.Routes.ShouldContain(x => x.DownstreamPathTemplate == _routeA.Routes[0].DownstreamPathTemplate);
fc.Routes.ShouldContain(x => x.DownstreamPathTemplate == _routeB.Routes[0].DownstreamPathTemplate);
fc.Routes.ShouldContain(x => x.DownstreamPathTemplate == _routeB.Routes[1].DownstreamPathTemplate);
fc.Routes.ShouldContain(x => x.DownstreamScheme == _routeA.Routes[0].DownstreamScheme);
fc.Routes.ShouldContain(x => x.DownstreamScheme == _routeB.Routes[0].DownstreamScheme);
fc.Routes.ShouldContain(x => x.DownstreamScheme == _routeB.Routes[1].DownstreamScheme);
fc.Routes.ShouldContain(x => x.Key == _routeA.Routes[0].Key);
fc.Routes.ShouldContain(x => x.Key == _routeB.Routes[0].Key);
fc.Routes.ShouldContain(x => x.Key == _routeB.Routes[1].Key);
fc.Routes.ShouldContain(x => x.UpstreamHost == _routeA.Routes[0].UpstreamHost);
fc.Routes.ShouldContain(x => x.UpstreamHost == _routeB.Routes[0].UpstreamHost);
fc.Routes.ShouldContain(x => x.UpstreamHost == _routeB.Routes[1].UpstreamHost);
fc.Aggregates.Count.ShouldBe(_aggregate.Aggregates.Count);
}
private void NotContainsEnvSpecificConfig()
{
var fc = (FileConfiguration)_configRoot.Get(typeof(FileConfiguration));
fc.Routes.ShouldNotContain(x => x.DownstreamScheme == _envSpecific.Routes[0].DownstreamScheme);
fc.Routes.ShouldNotContain(x => x.DownstreamPathTemplate == _envSpecific.Routes[0].DownstreamPathTemplate);
fc.Routes.ShouldNotContain(x => x.Key == _envSpecific.Routes[0].Key);
}
private void GivenTheBaseUrl(string baseUrl)
{
#pragma warning disable CS0618
var builder = new ConfigurationBuilder()
.AddOcelotBaseUrl(baseUrl);
#pragma warning restore CS0618
_configuration = builder.Build();
}
private void WhenIGet(string key)
{
_result = _configuration.GetValue(key, "");
}
private void ThenTheResultIs(string expected)
{
_result.ShouldBe(expected);
}
}
}

View File

@ -1,403 +1,403 @@
namespace Ocelot.UnitTests.DependencyInjection
{
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using Ocelot.Configuration.Setter;
using Ocelot.DependencyInjection;
using Ocelot.Infrastructure;
using Ocelot.Multiplexer;
using Ocelot.Requester;
using Ocelot.UnitTests.Requester;
using Shouldly;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using Microsoft.AspNetCore.Http;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.DependencyInjection
{
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using Ocelot.Configuration.Setter;
using Ocelot.DependencyInjection;
using Ocelot.Infrastructure;
using Ocelot.Multiplexer;
using Ocelot.Requester;
using Ocelot.UnitTests.Requester;
using Shouldly;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using Microsoft.AspNetCore.Http;
using TestStack.BDDfy;
using Xunit;
using System.Threading.Tasks;
using Ocelot.LoadBalancer.LoadBalancers;
using Ocelot.Responses;
using Ocelot.Values;
using static Ocelot.UnitTests.Multiplexing.UserDefinedResponseAggregatorTests;
public class OcelotBuilderTests
{
private readonly IServiceCollection _services;
private IServiceProvider _serviceProvider;
private readonly IConfiguration _configRoot;
private IOcelotBuilder _ocelotBuilder;
private readonly int _maxRetries;
private Exception _ex;
public OcelotBuilderTests()
{
_configRoot = new ConfigurationRoot(new List<IConfigurationProvider>());
_services = new ServiceCollection();
_services.AddSingleton<IWebHostEnvironment>(GetHostingEnvironment());
_services.AddSingleton(_configRoot);
_maxRetries = 100;
}
private IWebHostEnvironment GetHostingEnvironment()
{
var environment = new Mock<IWebHostEnvironment>();
environment
.Setup(e => e.ApplicationName)
.Returns(typeof(OcelotBuilderTests).GetTypeInfo().Assembly.GetName().Name);
return environment.Object;
}
[Fact]
public void should_add_specific_delegating_handlers_transient()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => AddSpecificTransientDelegatingHandler<FakeDelegatingHandler>())
.And(x => AddSpecificTransientDelegatingHandler<FakeDelegatingHandlerTwo>())
.Then(x => ThenTheProviderIsRegisteredAndReturnsSpecificHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
.And(x => ThenTheSpecificHandlersAreTransient())
.BDDfy();
}
[Fact]
public void should_add_type_specific_delegating_handlers_transient()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => AddTypeSpecificTransientDelegatingHandler(typeof(FakeDelegatingHandler)))
.And(x => AddTypeSpecificTransientDelegatingHandler(typeof(FakeDelegatingHandlerTwo)))
.Then(x => ThenTheProviderIsRegisteredAndReturnsSpecificHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
.And(x => ThenTheSpecificHandlersAreTransient())
.BDDfy();
}
[Fact]
public void should_add_global_delegating_handlers_transient()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => AddTransientGlobalDelegatingHandler<FakeDelegatingHandler>())
.And(x => AddTransientGlobalDelegatingHandler<FakeDelegatingHandlerTwo>())
.Then(x => ThenTheProviderIsRegisteredAndReturnsHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
.And(x => ThenTheGlobalHandlersAreTransient())
.BDDfy();
}
[Fact]
public void should_add_global_type_delegating_handlers_transient()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => AddTransientGlobalDelegatingHandler<FakeDelegatingHandler>())
.And(x => AddTransientGlobalDelegatingHandler<FakeDelegatingHandlerTwo>())
.Then(x => ThenTheProviderIsRegisteredAndReturnsHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
.And(x => ThenTheGlobalHandlersAreTransient())
.BDDfy();
}
[Fact]
public void should_set_up_services()
{
this.When(x => WhenISetUpOcelotServices())
.Then(x => ThenAnExceptionIsntThrown())
.BDDfy();
}
[Fact]
public void should_return_ocelot_builder()
{
this.When(x => WhenISetUpOcelotServices())
.Then(x => ThenAnOcelotBuilderIsReturned())
.BDDfy();
}
[Fact]
public void should_use_logger_factory()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => WhenIValidateScopes())
.When(x => WhenIAccessLoggerFactory())
.Then(x => ThenAnExceptionIsntThrown())
.BDDfy();
}
[Fact]
public void should_set_up_without_passing_in_config()
{
this.When(x => WhenISetUpOcelotServicesWithoutConfig())
.Then(x => ThenAnExceptionIsntThrown())
.BDDfy();
}
[Fact]
public void should_add_singleton_defined_aggregators()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => AddSingletonDefinedAggregator<TestDefinedAggregator>())
.When(x => AddSingletonDefinedAggregator<TestDefinedAggregator>())
.Then(x => ThenTheProviderIsRegisteredAndReturnsSpecificAggregators<TestDefinedAggregator, TestDefinedAggregator>())
.And(x => ThenTheAggregatorsAreSingleton<TestDefinedAggregator, TestDefinedAggregator>())
.BDDfy();
}
[Fact]
public void should_add_transient_defined_aggregators()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => AddTransientDefinedAggregator<TestDefinedAggregator>())
.When(x => AddTransientDefinedAggregator<TestDefinedAggregator>())
.Then(x => ThenTheProviderIsRegisteredAndReturnsSpecificAggregators<TestDefinedAggregator, TestDefinedAggregator>())
.And(x => ThenTheAggregatorsAreTransient<TestDefinedAggregator, TestDefinedAggregator>())
.BDDfy();
}
[Fact]
public void should_add_custom_load_balancer_creators_by_default_ctor()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => _ocelotBuilder.AddCustomLoadBalancer<FakeCustomLoadBalancer>())
.Then(x => ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators())
.BDDfy();
}
[Fact]
public void should_add_custom_load_balancer_creators_by_factory_method()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => _ocelotBuilder.AddCustomLoadBalancer(() => new FakeCustomLoadBalancer()))
.Then(x => ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators())
.BDDfy();
}
[Fact]
public void should_add_custom_load_balancer_creators_by_di_factory_method()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => _ocelotBuilder.AddCustomLoadBalancer(provider => new FakeCustomLoadBalancer()))
.Then(x => ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators())
.BDDfy();
}
[Fact]
public void should_add_custom_load_balancer_creators_by_factory_method_with_arguments()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => _ocelotBuilder.AddCustomLoadBalancer((reroute, discoveryProvider) => new FakeCustomLoadBalancer()))
.Then(x => ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators())
.BDDfy();
}
[Fact]
public void should_replace_iplaceholder()
{
this.Given(x => x.WhenISetUpOcelotServices())
.When(x => AddConfigPlaceholders())
.Then(x => ThenAnExceptionIsntThrown())
.And(x => ThenTheIPlaceholderInstanceIsReplaced())
.BDDfy();
}
[Fact]
public void should_add_custom_load_balancer_creators()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => _ocelotBuilder.AddCustomLoadBalancer((provider, reroute, discoveryProvider) => new FakeCustomLoadBalancer()))
.Then(x => ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators())
.BDDfy();
}
private void AddSingletonDefinedAggregator<T>()
where T : class, IDefinedAggregator
{
_ocelotBuilder.AddSingletonDefinedAggregator<T>();
}
private void AddTransientDefinedAggregator<T>()
where T : class, IDefinedAggregator
{
_ocelotBuilder.AddTransientDefinedAggregator<T>();
}
private void AddConfigPlaceholders()
{
_ocelotBuilder.AddConfigPlaceholders();
}
private void ThenTheSpecificHandlersAreTransient()
{
var handlers = _serviceProvider.GetServices<DelegatingHandler>().ToList();
var first = handlers[0];
handlers = _serviceProvider.GetServices<DelegatingHandler>().ToList();
var second = handlers[0];
first.ShouldNotBe(second);
}
private void ThenTheGlobalHandlersAreTransient()
{
var handlers = _serviceProvider.GetServices<GlobalDelegatingHandler>().ToList();
var first = handlers[0].DelegatingHandler;
handlers = _serviceProvider.GetServices<GlobalDelegatingHandler>().ToList();
var second = handlers[0].DelegatingHandler;
first.ShouldNotBe(second);
}
private void AddTransientGlobalDelegatingHandler<T>()
where T : DelegatingHandler
{
_ocelotBuilder.AddDelegatingHandler<T>(true);
}
private void AddSpecificTransientDelegatingHandler<T>()
where T : DelegatingHandler
{
_ocelotBuilder.AddDelegatingHandler<T>();
}
private void AddTypeTransientGlobalDelegatingHandler(Type type)
{
_ocelotBuilder.AddDelegatingHandler(type, true);
}
private void AddTypeSpecificTransientDelegatingHandler(Type type)
{
_ocelotBuilder.AddDelegatingHandler(type);
}
private void ThenTheProviderIsRegisteredAndReturnsHandlers<TOne, TWo>()
{
_serviceProvider = _services.BuildServiceProvider();
var handlers = _serviceProvider.GetServices<GlobalDelegatingHandler>().ToList();
handlers[0].DelegatingHandler.ShouldBeOfType<TOne>();
handlers[1].DelegatingHandler.ShouldBeOfType<TWo>();
}
private void ThenTheProviderIsRegisteredAndReturnsSpecificHandlers<TOne, TWo>()
{
_serviceProvider = _services.BuildServiceProvider();
var handlers = _serviceProvider.GetServices<DelegatingHandler>().ToList();
handlers[0].ShouldBeOfType<TOne>();
handlers[1].ShouldBeOfType<TWo>();
}
private void ThenTheProviderIsRegisteredAndReturnsSpecificAggregators<TOne, TWo>()
{
_serviceProvider = _services.BuildServiceProvider();
var handlers = _serviceProvider.GetServices<IDefinedAggregator>().ToList();
handlers[0].ShouldBeOfType<TOne>();
handlers[1].ShouldBeOfType<TWo>();
}
private void ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators()
{
_serviceProvider = _services.BuildServiceProvider();
var creators = _serviceProvider.GetServices<ILoadBalancerCreator>().ToList();
creators.Count(c => c.GetType() == typeof(NoLoadBalancerCreator)).ShouldBe(1);
creators.Count(c => c.GetType() == typeof(RoundRobinCreator)).ShouldBe(1);
creators.Count(c => c.GetType() == typeof(CookieStickySessionsCreator)).ShouldBe(1);
creators.Count(c => c.GetType() == typeof(LeastConnectionCreator)).ShouldBe(1);
creators.Count(c => c.GetType() == typeof(DelegateInvokingLoadBalancerCreator<FakeCustomLoadBalancer>)).ShouldBe(1);
}
private void ThenTheAggregatorsAreTransient<TOne, TWo>()
{
var aggregators = _serviceProvider.GetServices<IDefinedAggregator>().ToList();
var first = aggregators[0];
aggregators = _serviceProvider.GetServices<IDefinedAggregator>().ToList();
var second = aggregators[0];
first.ShouldNotBe(second);
}
private void ThenTheAggregatorsAreSingleton<TOne, TWo>()
{
var aggregators = _serviceProvider.GetServices<IDefinedAggregator>().ToList();
var first = aggregators[0];
aggregators = _serviceProvider.GetServices<IDefinedAggregator>().ToList();
var second = aggregators[0];
first.ShouldBe(second);
}
private void ThenAnOcelotBuilderIsReturned()
{
_ocelotBuilder.ShouldBeOfType<OcelotBuilder>();
}
private void ThenTheIPlaceholderInstanceIsReplaced()
{
_serviceProvider = _services.BuildServiceProvider();
var placeholders = _serviceProvider.GetService<IPlaceholders>();
placeholders.ShouldBeOfType<ConfigAwarePlaceholders>();
}
private void WhenISetUpOcelotServices()
{
try
{
_ocelotBuilder = _services.AddOcelot(_configRoot);
}
catch (Exception e)
{
_ex = e;
}
}
private void WhenISetUpOcelotServicesWithoutConfig()
{
try
{
_ocelotBuilder = _services.AddOcelot();
}
catch (Exception e)
{
_ex = e;
}
}
private void WhenIAccessLoggerFactory()
{
try
{
_serviceProvider = _services.BuildServiceProvider();
var logger = _serviceProvider.GetService<IFileConfigurationSetter>();
logger.ShouldNotBeNull();
}
catch (Exception e)
{
_ex = e;
}
}
private void WhenIValidateScopes()
{
try
{
_serviceProvider = _services.BuildServiceProvider(new ServiceProviderOptions { ValidateScopes = true });
}
catch (Exception e)
{
_ex = e;
}
}
private void ThenAnExceptionIsntThrown()
{
_ex.ShouldBeNull();
}
private class FakeCustomLoadBalancer : ILoadBalancer
{
public Task<Response<ServiceHostAndPort>> Lease(HttpContext httpContext)
{
// Not relevant for these tests
throw new NotImplementedException();
}
public void Release(ServiceHostAndPort hostAndPort)
{
// Not relevant for these tests
throw new NotImplementedException();
}
}
}
}
public class OcelotBuilderTests
{
private readonly IServiceCollection _services;
private IServiceProvider _serviceProvider;
private readonly IConfiguration _configRoot;
private IOcelotBuilder _ocelotBuilder;
private readonly int _maxRetries;
private Exception _ex;
public OcelotBuilderTests()
{
_configRoot = new ConfigurationRoot(new List<IConfigurationProvider>());
_services = new ServiceCollection();
_services.AddSingleton<IWebHostEnvironment>(GetHostingEnvironment());
_services.AddSingleton(_configRoot);
_maxRetries = 100;
}
private IWebHostEnvironment GetHostingEnvironment()
{
var environment = new Mock<IWebHostEnvironment>();
environment
.Setup(e => e.ApplicationName)
.Returns(typeof(OcelotBuilderTests).GetTypeInfo().Assembly.GetName().Name);
return environment.Object;
}
[Fact]
public void should_add_specific_delegating_handlers_transient()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => AddSpecificTransientDelegatingHandler<FakeDelegatingHandler>())
.And(x => AddSpecificTransientDelegatingHandler<FakeDelegatingHandlerTwo>())
.Then(x => ThenTheProviderIsRegisteredAndReturnsSpecificHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
.And(x => ThenTheSpecificHandlersAreTransient())
.BDDfy();
}
[Fact]
public void should_add_type_specific_delegating_handlers_transient()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => AddTypeSpecificTransientDelegatingHandler(typeof(FakeDelegatingHandler)))
.And(x => AddTypeSpecificTransientDelegatingHandler(typeof(FakeDelegatingHandlerTwo)))
.Then(x => ThenTheProviderIsRegisteredAndReturnsSpecificHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
.And(x => ThenTheSpecificHandlersAreTransient())
.BDDfy();
}
[Fact]
public void should_add_global_delegating_handlers_transient()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => AddTransientGlobalDelegatingHandler<FakeDelegatingHandler>())
.And(x => AddTransientGlobalDelegatingHandler<FakeDelegatingHandlerTwo>())
.Then(x => ThenTheProviderIsRegisteredAndReturnsHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
.And(x => ThenTheGlobalHandlersAreTransient())
.BDDfy();
}
[Fact]
public void should_add_global_type_delegating_handlers_transient()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => AddTransientGlobalDelegatingHandler<FakeDelegatingHandler>())
.And(x => AddTransientGlobalDelegatingHandler<FakeDelegatingHandlerTwo>())
.Then(x => ThenTheProviderIsRegisteredAndReturnsHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
.And(x => ThenTheGlobalHandlersAreTransient())
.BDDfy();
}
[Fact]
public void should_set_up_services()
{
this.When(x => WhenISetUpOcelotServices())
.Then(x => ThenAnExceptionIsntThrown())
.BDDfy();
}
[Fact]
public void should_return_ocelot_builder()
{
this.When(x => WhenISetUpOcelotServices())
.Then(x => ThenAnOcelotBuilderIsReturned())
.BDDfy();
}
[Fact]
public void should_use_logger_factory()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => WhenIValidateScopes())
.When(x => WhenIAccessLoggerFactory())
.Then(x => ThenAnExceptionIsntThrown())
.BDDfy();
}
[Fact]
public void should_set_up_without_passing_in_config()
{
this.When(x => WhenISetUpOcelotServicesWithoutConfig())
.Then(x => ThenAnExceptionIsntThrown())
.BDDfy();
}
[Fact]
public void should_add_singleton_defined_aggregators()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => AddSingletonDefinedAggregator<TestDefinedAggregator>())
.When(x => AddSingletonDefinedAggregator<TestDefinedAggregator>())
.Then(x => ThenTheProviderIsRegisteredAndReturnsSpecificAggregators<TestDefinedAggregator, TestDefinedAggregator>())
.And(x => ThenTheAggregatorsAreSingleton<TestDefinedAggregator, TestDefinedAggregator>())
.BDDfy();
}
[Fact]
public void should_add_transient_defined_aggregators()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => AddTransientDefinedAggregator<TestDefinedAggregator>())
.When(x => AddTransientDefinedAggregator<TestDefinedAggregator>())
.Then(x => ThenTheProviderIsRegisteredAndReturnsSpecificAggregators<TestDefinedAggregator, TestDefinedAggregator>())
.And(x => ThenTheAggregatorsAreTransient<TestDefinedAggregator, TestDefinedAggregator>())
.BDDfy();
}
[Fact]
public void should_add_custom_load_balancer_creators_by_default_ctor()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => _ocelotBuilder.AddCustomLoadBalancer<FakeCustomLoadBalancer>())
.Then(x => ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators())
.BDDfy();
}
[Fact]
public void should_add_custom_load_balancer_creators_by_factory_method()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => _ocelotBuilder.AddCustomLoadBalancer(() => new FakeCustomLoadBalancer()))
.Then(x => ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators())
.BDDfy();
}
[Fact]
public void should_add_custom_load_balancer_creators_by_di_factory_method()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => _ocelotBuilder.AddCustomLoadBalancer(provider => new FakeCustomLoadBalancer()))
.Then(x => ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators())
.BDDfy();
}
[Fact]
public void should_add_custom_load_balancer_creators_by_factory_method_with_arguments()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => _ocelotBuilder.AddCustomLoadBalancer((route, discoveryProvider) => new FakeCustomLoadBalancer()))
.Then(x => ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators())
.BDDfy();
}
[Fact]
public void should_replace_iplaceholder()
{
this.Given(x => x.WhenISetUpOcelotServices())
.When(x => AddConfigPlaceholders())
.Then(x => ThenAnExceptionIsntThrown())
.And(x => ThenTheIPlaceholderInstanceIsReplaced())
.BDDfy();
}
[Fact]
public void should_add_custom_load_balancer_creators()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => _ocelotBuilder.AddCustomLoadBalancer((provider, route, discoveryProvider) => new FakeCustomLoadBalancer()))
.Then(x => ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators())
.BDDfy();
}
private void AddSingletonDefinedAggregator<T>()
where T : class, IDefinedAggregator
{
_ocelotBuilder.AddSingletonDefinedAggregator<T>();
}
private void AddTransientDefinedAggregator<T>()
where T : class, IDefinedAggregator
{
_ocelotBuilder.AddTransientDefinedAggregator<T>();
}
private void AddConfigPlaceholders()
{
_ocelotBuilder.AddConfigPlaceholders();
}
private void ThenTheSpecificHandlersAreTransient()
{
var handlers = _serviceProvider.GetServices<DelegatingHandler>().ToList();
var first = handlers[0];
handlers = _serviceProvider.GetServices<DelegatingHandler>().ToList();
var second = handlers[0];
first.ShouldNotBe(second);
}
private void ThenTheGlobalHandlersAreTransient()
{
var handlers = _serviceProvider.GetServices<GlobalDelegatingHandler>().ToList();
var first = handlers[0].DelegatingHandler;
handlers = _serviceProvider.GetServices<GlobalDelegatingHandler>().ToList();
var second = handlers[0].DelegatingHandler;
first.ShouldNotBe(second);
}
private void AddTransientGlobalDelegatingHandler<T>()
where T : DelegatingHandler
{
_ocelotBuilder.AddDelegatingHandler<T>(true);
}
private void AddSpecificTransientDelegatingHandler<T>()
where T : DelegatingHandler
{
_ocelotBuilder.AddDelegatingHandler<T>();
}
private void AddTypeTransientGlobalDelegatingHandler(Type type)
{
_ocelotBuilder.AddDelegatingHandler(type, true);
}
private void AddTypeSpecificTransientDelegatingHandler(Type type)
{
_ocelotBuilder.AddDelegatingHandler(type);
}
private void ThenTheProviderIsRegisteredAndReturnsHandlers<TOne, TWo>()
{
_serviceProvider = _services.BuildServiceProvider();
var handlers = _serviceProvider.GetServices<GlobalDelegatingHandler>().ToList();
handlers[0].DelegatingHandler.ShouldBeOfType<TOne>();
handlers[1].DelegatingHandler.ShouldBeOfType<TWo>();
}
private void ThenTheProviderIsRegisteredAndReturnsSpecificHandlers<TOne, TWo>()
{
_serviceProvider = _services.BuildServiceProvider();
var handlers = _serviceProvider.GetServices<DelegatingHandler>().ToList();
handlers[0].ShouldBeOfType<TOne>();
handlers[1].ShouldBeOfType<TWo>();
}
private void ThenTheProviderIsRegisteredAndReturnsSpecificAggregators<TOne, TWo>()
{
_serviceProvider = _services.BuildServiceProvider();
var handlers = _serviceProvider.GetServices<IDefinedAggregator>().ToList();
handlers[0].ShouldBeOfType<TOne>();
handlers[1].ShouldBeOfType<TWo>();
}
private void ThenTheProviderIsRegisteredAndReturnsBothBuiltInAndCustomLoadBalancerCreators()
{
_serviceProvider = _services.BuildServiceProvider();
var creators = _serviceProvider.GetServices<ILoadBalancerCreator>().ToList();
creators.Count(c => c.GetType() == typeof(NoLoadBalancerCreator)).ShouldBe(1);
creators.Count(c => c.GetType() == typeof(RoundRobinCreator)).ShouldBe(1);
creators.Count(c => c.GetType() == typeof(CookieStickySessionsCreator)).ShouldBe(1);
creators.Count(c => c.GetType() == typeof(LeastConnectionCreator)).ShouldBe(1);
creators.Count(c => c.GetType() == typeof(DelegateInvokingLoadBalancerCreator<FakeCustomLoadBalancer>)).ShouldBe(1);
}
private void ThenTheAggregatorsAreTransient<TOne, TWo>()
{
var aggregators = _serviceProvider.GetServices<IDefinedAggregator>().ToList();
var first = aggregators[0];
aggregators = _serviceProvider.GetServices<IDefinedAggregator>().ToList();
var second = aggregators[0];
first.ShouldNotBe(second);
}
private void ThenTheAggregatorsAreSingleton<TOne, TWo>()
{
var aggregators = _serviceProvider.GetServices<IDefinedAggregator>().ToList();
var first = aggregators[0];
aggregators = _serviceProvider.GetServices<IDefinedAggregator>().ToList();
var second = aggregators[0];
first.ShouldBe(second);
}
private void ThenAnOcelotBuilderIsReturned()
{
_ocelotBuilder.ShouldBeOfType<OcelotBuilder>();
}
private void ThenTheIPlaceholderInstanceIsReplaced()
{
_serviceProvider = _services.BuildServiceProvider();
var placeholders = _serviceProvider.GetService<IPlaceholders>();
placeholders.ShouldBeOfType<ConfigAwarePlaceholders>();
}
private void WhenISetUpOcelotServices()
{
try
{
_ocelotBuilder = _services.AddOcelot(_configRoot);
}
catch (Exception e)
{
_ex = e;
}
}
private void WhenISetUpOcelotServicesWithoutConfig()
{
try
{
_ocelotBuilder = _services.AddOcelot();
}
catch (Exception e)
{
_ex = e;
}
}
private void WhenIAccessLoggerFactory()
{
try
{
_serviceProvider = _services.BuildServiceProvider();
var logger = _serviceProvider.GetService<IFileConfigurationSetter>();
logger.ShouldNotBeNull();
}
catch (Exception e)
{
_ex = e;
}
}
private void WhenIValidateScopes()
{
try
{
_serviceProvider = _services.BuildServiceProvider(new ServiceProviderOptions { ValidateScopes = true });
}
catch (Exception e)
{
_ex = e;
}
}
private void ThenAnExceptionIsntThrown()
{
_ex.ShouldBeNull();
}
private class FakeCustomLoadBalancer : ILoadBalancer
{
public Task<Response<ServiceHostAndPort>> Lease(HttpContext httpContext)
{
// Not relevant for these tests
throw new NotImplementedException();
}
public void Release(ServiceHostAndPort hostAndPort)
{
// Not relevant for these tests
throw new NotImplementedException();
}
}
}
}

View File

@ -1,104 +1,104 @@
using Microsoft.AspNetCore.Http;
namespace Ocelot.UnitTests.DownstreamPathManipulation
{
using Ocelot.DownstreamPathManipulation.Middleware;
using Ocelot.Infrastructure.RequestData;
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.DownstreamRouteFinder;
using Ocelot.DownstreamRouteFinder.UrlMatcher;
using Ocelot.Logging;
using Ocelot.Middleware;
using Ocelot.PathManipulation;
using Ocelot.Request.Middleware;
using Ocelot.Responses;
using Ocelot.Values;
using System.Collections.Generic;
using System.Net.Http;
using System.Security.Claims;
using System.Threading.Tasks;
using TestStack.BDDfy;
using Microsoft.AspNetCore.Http;
namespace Ocelot.UnitTests.DownstreamPathManipulation
{
using Ocelot.DownstreamPathManipulation.Middleware;
using Ocelot.Infrastructure.RequestData;
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.DownstreamRouteFinder;
using Ocelot.DownstreamRouteFinder.UrlMatcher;
using Ocelot.Logging;
using Ocelot.Middleware;
using Ocelot.PathManipulation;
using Ocelot.Request.Middleware;
using Ocelot.Responses;
using Ocelot.Values;
using System.Collections.Generic;
using System.Net.Http;
using System.Security.Claims;
using System.Threading.Tasks;
using TestStack.BDDfy;
using Xunit;
using Ocelot.DownstreamRouteFinder.Middleware;
public class ClaimsToDownstreamPathMiddlewareTests
{
private readonly Mock<IChangeDownstreamPathTemplate> _changePath;
private Mock<IOcelotLoggerFactory> _loggerFactory;
private Mock<IOcelotLogger> _logger;
private ClaimsToDownstreamPathMiddleware _middleware;
private RequestDelegate _next;
private HttpContext _httpContext;
public ClaimsToDownstreamPathMiddlewareTests()
{
_httpContext = new DefaultHttpContext();
_loggerFactory = new Mock<IOcelotLoggerFactory>();
_logger = new Mock<IOcelotLogger>();
_loggerFactory.Setup(x => x.CreateLogger<ClaimsToDownstreamPathMiddleware>()).Returns(_logger.Object);
_next = context => Task.CompletedTask;
public class ClaimsToDownstreamPathMiddlewareTests
{
private readonly Mock<IChangeDownstreamPathTemplate> _changePath;
private Mock<IOcelotLoggerFactory> _loggerFactory;
private Mock<IOcelotLogger> _logger;
private ClaimsToDownstreamPathMiddleware _middleware;
private RequestDelegate _next;
private HttpContext _httpContext;
public ClaimsToDownstreamPathMiddlewareTests()
{
_httpContext = new DefaultHttpContext();
_loggerFactory = new Mock<IOcelotLoggerFactory>();
_logger = new Mock<IOcelotLogger>();
_loggerFactory.Setup(x => x.CreateLogger<ClaimsToDownstreamPathMiddleware>()).Returns(_logger.Object);
_next = context => Task.CompletedTask;
_changePath = new Mock<IChangeDownstreamPathTemplate>();
_httpContext.Items.UpsertDownstreamRequest(new DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "http://test.com")));
_middleware = new ClaimsToDownstreamPathMiddleware(_next, _loggerFactory.Object, _changePath.Object);
}
[Fact]
public void should_call_add_queries_correctly()
{
var downstreamRoute = new DownstreamRoute(new List<PlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("any old string")
.WithClaimsToDownstreamPath(new List<ClaimToThing>
{
new ClaimToThing("UserId", "Subject", "", 0),
})
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build());
this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
.And(x => x.GivenTheChangeDownstreamPathReturnsOk())
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenChangeDownstreamPathIsCalledCorrectly())
.BDDfy();
}
private void WhenICallTheMiddleware()
{
_middleware.Invoke(_httpContext).GetAwaiter().GetResult();
}
private void GivenTheChangeDownstreamPathReturnsOk()
{
_changePath
.Setup(x => x.ChangeDownstreamPath(
It.IsAny<List<ClaimToThing>>(),
It.IsAny<IEnumerable<Claim>>(),
It.IsAny<DownstreamPathTemplate>(),
It.IsAny<List<PlaceholderNameAndValue>>()))
.Returns(new OkResponse());
}
private void ThenChangeDownstreamPathIsCalledCorrectly()
{
_changePath
.Verify(x => x.ChangeDownstreamPath(
It.IsAny<List<ClaimToThing>>(),
It.IsAny<IEnumerable<Claim>>(),
_httpContext.Items.DownstreamReRoute().DownstreamPathTemplate,
_httpContext.Items.TemplatePlaceholderNameAndValues()), Times.Once);
}
private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute)
{
_httpContext.Items.UpsertDownstreamRequest(new DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "http://test.com")));
_middleware = new ClaimsToDownstreamPathMiddleware(_next, _loggerFactory.Object, _changePath.Object);
}
[Fact]
public void should_call_add_queries_correctly()
{
var downstreamRoute = new Ocelot.DownstreamRouteFinder.DownstreamRouteHolder(new List<PlaceholderNameAndValue>(),
new RouteBuilder()
.WithDownstreamRoute(new DownstreamRouteBuilder()
.WithDownstreamPathTemplate("any old string")
.WithClaimsToDownstreamPath(new List<ClaimToThing>
{
new ClaimToThing("UserId", "Subject", "", 0),
})
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build());
this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
.And(x => x.GivenTheChangeDownstreamPathReturnsOk())
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenChangeDownstreamPathIsCalledCorrectly())
.BDDfy();
}
private void WhenICallTheMiddleware()
{
_middleware.Invoke(_httpContext).GetAwaiter().GetResult();
}
private void GivenTheChangeDownstreamPathReturnsOk()
{
_changePath
.Setup(x => x.ChangeDownstreamPath(
It.IsAny<List<ClaimToThing>>(),
It.IsAny<IEnumerable<Claim>>(),
It.IsAny<DownstreamPathTemplate>(),
It.IsAny<List<PlaceholderNameAndValue>>()))
.Returns(new OkResponse());
}
private void ThenChangeDownstreamPathIsCalledCorrectly()
{
_changePath
.Verify(x => x.ChangeDownstreamPath(
It.IsAny<List<ClaimToThing>>(),
It.IsAny<IEnumerable<Claim>>(),
_httpContext.Items.DownstreamRoute().DownstreamPathTemplate,
_httpContext.Items.TemplatePlaceholderNameAndValues()), Times.Once);
}
private void GivenTheDownStreamRouteIs(Ocelot.DownstreamRouteFinder.DownstreamRouteHolder downstreamRoute)
{
_httpContext.Items.UpsertTemplatePlaceholderNameAndValues(downstreamRoute.TemplatePlaceholderNameAndValues);
_httpContext.Items.UpsertDownstreamReRoute(downstreamRoute.ReRoute.DownstreamReRoute[0]);
}
}
}
_httpContext.Items.UpsertDownstreamRoute(downstreamRoute.Route.DownstreamRoute[0]);
}
}
}

View File

@ -1,306 +1,306 @@
namespace Ocelot.UnitTests.DownstreamRouteFinder
{
using System;
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.DownstreamRouteFinder;
using Ocelot.DownstreamRouteFinder.Finder;
using Ocelot.LoadBalancer.LoadBalancers;
using Responses;
using Shouldly;
using System.Collections.Generic;
using System.Net.Http;
using TestStack.BDDfy;
using Xunit;
public class DownstreamRouteCreatorTests
{
private readonly DownstreamRouteCreator _creator;
private readonly QoSOptions _qoSOptions;
private readonly HttpHandlerOptions _handlerOptions;
private readonly LoadBalancerOptions _loadBalancerOptions;
private Response<DownstreamRoute> _result;
private string _upstreamHost;
private string _upstreamUrlPath;
private string _upstreamHttpMethod;
private IInternalConfiguration _configuration;
private Mock<IQoSOptionsCreator> _qosOptionsCreator;
private Response<DownstreamRoute> _resultTwo;
private string _upstreamQuery;
public DownstreamRouteCreatorTests()
{
_qosOptionsCreator = new Mock<IQoSOptionsCreator>();
_qoSOptions = new QoSOptionsBuilder().Build();
_handlerOptions = new HttpHandlerOptionsBuilder().Build();
_loadBalancerOptions = new LoadBalancerOptionsBuilder().WithType(nameof(NoLoadBalancer)).Build();
_qosOptionsCreator
.Setup(x => x.Create(It.IsAny<QoSOptions>(), It.IsAny<string>(), It.IsAny<List<string>>()))
.Returns(_qoSOptions);
_creator = new DownstreamRouteCreator(_qosOptionsCreator.Object);
}
[Fact]
public void should_create_downstream_route()
{
var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1"));
this.Given(_ => GivenTheConfiguration(configuration))
.When(_ => WhenICreate())
.Then(_ => ThenTheDownstreamRouteIsCreated())
.BDDfy();
}
[Fact]
public void should_create_downstream_route_with_rate_limit_options()
{
var rateLimitOptions = new RateLimitOptionsBuilder()
.WithEnableRateLimiting(true)
.WithClientIdHeader("test")
.Build();
var downstreamReRoute = new DownstreamReRouteBuilder()
.WithServiceName("auth")
.WithRateLimitOptions(rateLimitOptions)
.Build();
var reRoute = new ReRouteBuilder()
.WithDownstreamReRoute(downstreamReRoute)
.Build();
var reRoutes = new List<ReRoute> { reRoute };
var configuration = new InternalConfiguration(reRoutes, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1"));
this.Given(_ => GivenTheConfiguration(configuration))
.When(_ => WhenICreate())
.Then(_ => ThenTheDownstreamRouteIsCreated())
.And(_ => WithRateLimitOptions(rateLimitOptions))
.BDDfy();
}
[Fact]
public void should_cache_downstream_route()
{
var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1"));
this.Given(_ => GivenTheConfiguration(configuration, "/geoffisthebest/"))
.When(_ => WhenICreate())
.And(_ => GivenTheConfiguration(configuration, "/geoffisthebest/"))
.When(_ => WhenICreateAgain())
.Then(_ => ThenTheDownstreamRoutesAreTheSameReference())
.BDDfy();
}
[Fact]
public void should_not_cache_downstream_route()
{
var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1"));
this.Given(_ => GivenTheConfiguration(configuration, "/geoffistheworst/"))
.When(_ => WhenICreate())
.And(_ => GivenTheConfiguration(configuration, "/geoffisthebest/"))
.When(_ => WhenICreateAgain())
.Then(_ => ThenTheDownstreamRoutesAreTheNotSameReference())
.BDDfy();
}
[Fact]
public void should_create_downstream_route_with_no_path()
{
var upstreamUrlPath = "/auth/";
var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1"));
this.Given(_ => GivenTheConfiguration(configuration, upstreamUrlPath))
.When(_ => WhenICreate())
.Then(_ => ThenTheDownstreamPathIsForwardSlash())
.BDDfy();
}
[Fact]
public void should_create_downstream_route_with_only_first_segment_no_traling_slash()
{
var upstreamUrlPath = "/auth";
var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1"));
this.Given(_ => GivenTheConfiguration(configuration, upstreamUrlPath))
.When(_ => WhenICreate())
.Then(_ => ThenTheDownstreamPathIsForwardSlash())
.BDDfy();
}
[Fact]
public void should_create_downstream_route_with_segments_no_traling_slash()
{
var upstreamUrlPath = "/auth/test";
var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1"));
this.Given(_ => GivenTheConfiguration(configuration, upstreamUrlPath))
.When(_ => WhenICreate())
.Then(_ => ThenThePathDoesNotHaveTrailingSlash())
.BDDfy();
}
[Fact]
public void should_create_downstream_route_and_remove_query_string()
{
var upstreamUrlPath = "/auth/test?test=1&best=2";
var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1"));
this.Given(_ => GivenTheConfiguration(configuration, upstreamUrlPath))
.When(_ => WhenICreate())
.Then(_ => ThenTheQueryStringIsRemoved())
.BDDfy();
}
[Fact]
public void should_create_downstream_route_for_sticky_sessions()
{
var loadBalancerOptions = new LoadBalancerOptionsBuilder().WithType(nameof(CookieStickySessions)).WithKey("boom").WithExpiryInMs(1).Build();
var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1"));
this.Given(_ => GivenTheConfiguration(configuration))
.When(_ => WhenICreate())
.Then(_ => ThenTheStickySessionLoadBalancerIsUsed(loadBalancerOptions))
.BDDfy();
}
[Fact]
public void should_create_downstream_route_with_qos()
{
var qoSOptions = new QoSOptionsBuilder()
.WithExceptionsAllowedBeforeBreaking(1)
.WithTimeoutValue(1)
.Build();
var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", qoSOptions, _handlerOptions, new Version("1.1"));
this.Given(_ => GivenTheConfiguration(configuration))
.And(_ => GivenTheQosCreatorReturns(qoSOptions))
.When(_ => WhenICreate())
.Then(_ => ThenTheQosOptionsAreSet(qoSOptions))
.BDDfy();
}
[Fact]
public void should_create_downstream_route_with_handler_options()
{
var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1"));
this.Given(_ => GivenTheConfiguration(configuration))
.When(_ => WhenICreate())
.Then(_ => ThenTheHandlerOptionsAreSet())
.BDDfy();
}
private void GivenTheQosCreatorReturns(QoSOptions options)
{
_qosOptionsCreator
.Setup(x => x.Create(It.IsAny<QoSOptions>(), It.IsAny<string>(), It.IsAny<List<string>>()))
.Returns(options);
}
private void WithRateLimitOptions(RateLimitOptions expected)
{
_result.Data.ReRoute.DownstreamReRoute[0].EnableEndpointEndpointRateLimiting.ShouldBeTrue();
_result.Data.ReRoute.DownstreamReRoute[0].RateLimitOptions.EnableRateLimiting.ShouldBe(expected.EnableRateLimiting);
_result.Data.ReRoute.DownstreamReRoute[0].RateLimitOptions.ClientIdHeader.ShouldBe(expected.ClientIdHeader);
}
private void ThenTheDownstreamRouteIsCreated()
{
_result.Data.ReRoute.DownstreamReRoute[0].DownstreamPathTemplate.Value.ShouldBe("/test");
_result.Data.ReRoute.UpstreamHttpMethod[0].ShouldBe(HttpMethod.Get);
_result.Data.ReRoute.DownstreamReRoute[0].ServiceName.ShouldBe("auth");
_result.Data.ReRoute.DownstreamReRoute[0].LoadBalancerKey.ShouldBe("/auth/test|GET");
_result.Data.ReRoute.DownstreamReRoute[0].UseServiceDiscovery.ShouldBeTrue();
_result.Data.ReRoute.DownstreamReRoute[0].HttpHandlerOptions.ShouldNotBeNull();
_result.Data.ReRoute.DownstreamReRoute[0].QosOptions.ShouldNotBeNull();
_result.Data.ReRoute.DownstreamReRoute[0].DownstreamScheme.ShouldBe("http");
_result.Data.ReRoute.DownstreamReRoute[0].LoadBalancerOptions.Type.ShouldBe(nameof(NoLoadBalancer));
_result.Data.ReRoute.DownstreamReRoute[0].HttpHandlerOptions.ShouldBe(_handlerOptions);
_result.Data.ReRoute.DownstreamReRoute[0].QosOptions.ShouldBe(_qoSOptions);
_result.Data.ReRoute.UpstreamTemplatePattern.ShouldNotBeNull();
_result.Data.ReRoute.DownstreamReRoute[0].UpstreamPathTemplate.ShouldNotBeNull();
}
private void ThenTheDownstreamPathIsForwardSlash()
{
_result.Data.ReRoute.DownstreamReRoute[0].DownstreamPathTemplate.Value.ShouldBe("/");
_result.Data.ReRoute.DownstreamReRoute[0].ServiceName.ShouldBe("auth");
_result.Data.ReRoute.DownstreamReRoute[0].LoadBalancerKey.ShouldBe("/auth/|GET");
}
private void ThenThePathDoesNotHaveTrailingSlash()
{
_result.Data.ReRoute.DownstreamReRoute[0].DownstreamPathTemplate.Value.ShouldBe("/test");
_result.Data.ReRoute.DownstreamReRoute[0].ServiceName.ShouldBe("auth");
_result.Data.ReRoute.DownstreamReRoute[0].LoadBalancerKey.ShouldBe("/auth/test|GET");
}
private void ThenTheQueryStringIsRemoved()
{
_result.Data.ReRoute.DownstreamReRoute[0].DownstreamPathTemplate.Value.ShouldBe("/test");
_result.Data.ReRoute.DownstreamReRoute[0].ServiceName.ShouldBe("auth");
_result.Data.ReRoute.DownstreamReRoute[0].LoadBalancerKey.ShouldBe("/auth/test|GET");
}
private void ThenTheStickySessionLoadBalancerIsUsed(LoadBalancerOptions expected)
{
_result.Data.ReRoute.DownstreamReRoute[0].LoadBalancerKey.ShouldBe($"{nameof(CookieStickySessions)}:boom");
_result.Data.ReRoute.DownstreamReRoute[0].LoadBalancerOptions.Type.ShouldBe(nameof(CookieStickySessions));
_result.Data.ReRoute.DownstreamReRoute[0].LoadBalancerOptions.ShouldBe(expected);
}
private void ThenTheQosOptionsAreSet(QoSOptions expected)
{
_result.Data.ReRoute.DownstreamReRoute[0].QosOptions.ShouldBe(expected);
_result.Data.ReRoute.DownstreamReRoute[0].QosOptions.UseQos.ShouldBeTrue();
_qosOptionsCreator
.Verify(x => x.Create(expected, _upstreamUrlPath, It.IsAny<List<string>>()), Times.Once);
}
private void GivenTheConfiguration(IInternalConfiguration config)
{
_upstreamHost = "doesnt matter";
_upstreamUrlPath = "/auth/test";
_upstreamHttpMethod = "GET";
_configuration = config;
}
private void GivenTheConfiguration(IInternalConfiguration config, string upstreamUrlPath)
{
_upstreamHost = "doesnt matter";
_upstreamUrlPath = upstreamUrlPath;
_upstreamHttpMethod = "GET";
_configuration = config;
}
private void ThenTheHandlerOptionsAreSet()
{
_result.Data.ReRoute.DownstreamReRoute[0].HttpHandlerOptions.ShouldBe(_handlerOptions);
}
private void WhenICreate()
{
_result = _creator.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _configuration, _upstreamHost);
}
private void WhenICreateAgain()
{
_resultTwo = _creator.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _configuration, _upstreamHost);
}
private void ThenTheDownstreamRoutesAreTheSameReference()
{
_result.ShouldBe(_resultTwo);
}
private void ThenTheDownstreamRoutesAreTheNotSameReference()
{
_result.ShouldNotBe(_resultTwo);
}
}
}
namespace Ocelot.UnitTests.DownstreamRouteFinder
{
using System;
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.DownstreamRouteFinder;
using Ocelot.DownstreamRouteFinder.Finder;
using Ocelot.LoadBalancer.LoadBalancers;
using Responses;
using Shouldly;
using System.Collections.Generic;
using System.Net.Http;
using TestStack.BDDfy;
using Xunit;
public class DownstreamRouteCreatorTests
{
private readonly DownstreamRouteCreator _creator;
private readonly QoSOptions _qoSOptions;
private readonly HttpHandlerOptions _handlerOptions;
private readonly LoadBalancerOptions _loadBalancerOptions;
private Response<Ocelot.DownstreamRouteFinder.DownstreamRouteHolder> _result;
private string _upstreamHost;
private string _upstreamUrlPath;
private string _upstreamHttpMethod;
private IInternalConfiguration _configuration;
private Mock<IQoSOptionsCreator> _qosOptionsCreator;
private Response<Ocelot.DownstreamRouteFinder.DownstreamRouteHolder> _resultTwo;
private string _upstreamQuery;
public DownstreamRouteCreatorTests()
{
_qosOptionsCreator = new Mock<IQoSOptionsCreator>();
_qoSOptions = new QoSOptionsBuilder().Build();
_handlerOptions = new HttpHandlerOptionsBuilder().Build();
_loadBalancerOptions = new LoadBalancerOptionsBuilder().WithType(nameof(NoLoadBalancer)).Build();
_qosOptionsCreator
.Setup(x => x.Create(It.IsAny<QoSOptions>(), It.IsAny<string>(), It.IsAny<List<string>>()))
.Returns(_qoSOptions);
_creator = new DownstreamRouteCreator(_qosOptionsCreator.Object);
}
[Fact]
public void should_create_downstream_route()
{
var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1"));
this.Given(_ => GivenTheConfiguration(configuration))
.When(_ => WhenICreate())
.Then(_ => ThenTheDownstreamRouteIsCreated())
.BDDfy();
}
[Fact]
public void should_create_downstream_route_with_rate_limit_options()
{
var rateLimitOptions = new RateLimitOptionsBuilder()
.WithEnableRateLimiting(true)
.WithClientIdHeader("test")
.Build();
var downstreamRoute = new DownstreamRouteBuilder()
.WithServiceName("auth")
.WithRateLimitOptions(rateLimitOptions)
.Build();
var route = new RouteBuilder()
.WithDownstreamRoute(downstreamRoute)
.Build();
var routes = new List<Route> { route };
var configuration = new InternalConfiguration(routes, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1"));
this.Given(_ => GivenTheConfiguration(configuration))
.When(_ => WhenICreate())
.Then(_ => ThenTheDownstreamRouteIsCreated())
.And(_ => WithRateLimitOptions(rateLimitOptions))
.BDDfy();
}
[Fact]
public void should_cache_downstream_route()
{
var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1"));
this.Given(_ => GivenTheConfiguration(configuration, "/geoffisthebest/"))
.When(_ => WhenICreate())
.And(_ => GivenTheConfiguration(configuration, "/geoffisthebest/"))
.When(_ => WhenICreateAgain())
.Then(_ => ThenTheDownstreamRoutesAreTheSameReference())
.BDDfy();
}
[Fact]
public void should_not_cache_downstream_route()
{
var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1"));
this.Given(_ => GivenTheConfiguration(configuration, "/geoffistheworst/"))
.When(_ => WhenICreate())
.And(_ => GivenTheConfiguration(configuration, "/geoffisthebest/"))
.When(_ => WhenICreateAgain())
.Then(_ => ThenTheDownstreamRoutesAreTheNotSameReference())
.BDDfy();
}
[Fact]
public void should_create_downstream_route_with_no_path()
{
var upstreamUrlPath = "/auth/";
var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1"));
this.Given(_ => GivenTheConfiguration(configuration, upstreamUrlPath))
.When(_ => WhenICreate())
.Then(_ => ThenTheDownstreamPathIsForwardSlash())
.BDDfy();
}
[Fact]
public void should_create_downstream_route_with_only_first_segment_no_traling_slash()
{
var upstreamUrlPath = "/auth";
var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1"));
this.Given(_ => GivenTheConfiguration(configuration, upstreamUrlPath))
.When(_ => WhenICreate())
.Then(_ => ThenTheDownstreamPathIsForwardSlash())
.BDDfy();
}
[Fact]
public void should_create_downstream_route_with_segments_no_traling_slash()
{
var upstreamUrlPath = "/auth/test";
var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1"));
this.Given(_ => GivenTheConfiguration(configuration, upstreamUrlPath))
.When(_ => WhenICreate())
.Then(_ => ThenThePathDoesNotHaveTrailingSlash())
.BDDfy();
}
[Fact]
public void should_create_downstream_route_and_remove_query_string()
{
var upstreamUrlPath = "/auth/test?test=1&best=2";
var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1"));
this.Given(_ => GivenTheConfiguration(configuration, upstreamUrlPath))
.When(_ => WhenICreate())
.Then(_ => ThenTheQueryStringIsRemoved())
.BDDfy();
}
[Fact]
public void should_create_downstream_route_for_sticky_sessions()
{
var loadBalancerOptions = new LoadBalancerOptionsBuilder().WithType(nameof(CookieStickySessions)).WithKey("boom").WithExpiryInMs(1).Build();
var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1"));
this.Given(_ => GivenTheConfiguration(configuration))
.When(_ => WhenICreate())
.Then(_ => ThenTheStickySessionLoadBalancerIsUsed(loadBalancerOptions))
.BDDfy();
}
[Fact]
public void should_create_downstream_route_with_qos()
{
var qoSOptions = new QoSOptionsBuilder()
.WithExceptionsAllowedBeforeBreaking(1)
.WithTimeoutValue(1)
.Build();
var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", qoSOptions, _handlerOptions, new Version("1.1"));
this.Given(_ => GivenTheConfiguration(configuration))
.And(_ => GivenTheQosCreatorReturns(qoSOptions))
.When(_ => WhenICreate())
.Then(_ => ThenTheQosOptionsAreSet(qoSOptions))
.BDDfy();
}
[Fact]
public void should_create_downstream_route_with_handler_options()
{
var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions, new Version("1.1"));
this.Given(_ => GivenTheConfiguration(configuration))
.When(_ => WhenICreate())
.Then(_ => ThenTheHandlerOptionsAreSet())
.BDDfy();
}
private void GivenTheQosCreatorReturns(QoSOptions options)
{
_qosOptionsCreator
.Setup(x => x.Create(It.IsAny<QoSOptions>(), It.IsAny<string>(), It.IsAny<List<string>>()))
.Returns(options);
}
private void WithRateLimitOptions(RateLimitOptions expected)
{
_result.Data.Route.DownstreamRoute[0].EnableEndpointEndpointRateLimiting.ShouldBeTrue();
_result.Data.Route.DownstreamRoute[0].RateLimitOptions.EnableRateLimiting.ShouldBe(expected.EnableRateLimiting);
_result.Data.Route.DownstreamRoute[0].RateLimitOptions.ClientIdHeader.ShouldBe(expected.ClientIdHeader);
}
private void ThenTheDownstreamRouteIsCreated()
{
_result.Data.Route.DownstreamRoute[0].DownstreamPathTemplate.Value.ShouldBe("/test");
_result.Data.Route.UpstreamHttpMethod[0].ShouldBe(HttpMethod.Get);
_result.Data.Route.DownstreamRoute[0].ServiceName.ShouldBe("auth");
_result.Data.Route.DownstreamRoute[0].LoadBalancerKey.ShouldBe("/auth/test|GET");
_result.Data.Route.DownstreamRoute[0].UseServiceDiscovery.ShouldBeTrue();
_result.Data.Route.DownstreamRoute[0].HttpHandlerOptions.ShouldNotBeNull();
_result.Data.Route.DownstreamRoute[0].QosOptions.ShouldNotBeNull();
_result.Data.Route.DownstreamRoute[0].DownstreamScheme.ShouldBe("http");
_result.Data.Route.DownstreamRoute[0].LoadBalancerOptions.Type.ShouldBe(nameof(Ocelot.LoadBalancer.LoadBalancers.NoLoadBalancer));
_result.Data.Route.DownstreamRoute[0].HttpHandlerOptions.ShouldBe(_handlerOptions);
_result.Data.Route.DownstreamRoute[0].QosOptions.ShouldBe(_qoSOptions);
_result.Data.Route.UpstreamTemplatePattern.ShouldNotBeNull();
_result.Data.Route.DownstreamRoute[0].UpstreamPathTemplate.ShouldNotBeNull();
}
private void ThenTheDownstreamPathIsForwardSlash()
{
_result.Data.Route.DownstreamRoute[0].DownstreamPathTemplate.Value.ShouldBe("/");
_result.Data.Route.DownstreamRoute[0].ServiceName.ShouldBe("auth");
_result.Data.Route.DownstreamRoute[0].LoadBalancerKey.ShouldBe("/auth/|GET");
}
private void ThenThePathDoesNotHaveTrailingSlash()
{
_result.Data.Route.DownstreamRoute[0].DownstreamPathTemplate.Value.ShouldBe("/test");
_result.Data.Route.DownstreamRoute[0].ServiceName.ShouldBe("auth");
_result.Data.Route.DownstreamRoute[0].LoadBalancerKey.ShouldBe("/auth/test|GET");
}
private void ThenTheQueryStringIsRemoved()
{
_result.Data.Route.DownstreamRoute[0].DownstreamPathTemplate.Value.ShouldBe("/test");
_result.Data.Route.DownstreamRoute[0].ServiceName.ShouldBe("auth");
_result.Data.Route.DownstreamRoute[0].LoadBalancerKey.ShouldBe("/auth/test|GET");
}
private void ThenTheStickySessionLoadBalancerIsUsed(LoadBalancerOptions expected)
{
_result.Data.Route.DownstreamRoute[0].LoadBalancerKey.ShouldBe($"{nameof(Ocelot.LoadBalancer.LoadBalancers.CookieStickySessions)}:boom");
_result.Data.Route.DownstreamRoute[0].LoadBalancerOptions.Type.ShouldBe(nameof(Ocelot.LoadBalancer.LoadBalancers.CookieStickySessions));
_result.Data.Route.DownstreamRoute[0].LoadBalancerOptions.ShouldBe(expected);
}
private void ThenTheQosOptionsAreSet(QoSOptions expected)
{
_result.Data.Route.DownstreamRoute[0].QosOptions.ShouldBe(expected);
_result.Data.Route.DownstreamRoute[0].QosOptions.UseQos.ShouldBeTrue();
_qosOptionsCreator
.Verify(x => x.Create(expected, _upstreamUrlPath, It.IsAny<List<string>>()), Times.Once);
}
private void GivenTheConfiguration(IInternalConfiguration config)
{
_upstreamHost = "doesnt matter";
_upstreamUrlPath = "/auth/test";
_upstreamHttpMethod = "GET";
_configuration = config;
}
private void GivenTheConfiguration(IInternalConfiguration config, string upstreamUrlPath)
{
_upstreamHost = "doesnt matter";
_upstreamUrlPath = upstreamUrlPath;
_upstreamHttpMethod = "GET";
_configuration = config;
}
private void ThenTheHandlerOptionsAreSet()
{
_result.Data.Route.DownstreamRoute[0].HttpHandlerOptions.ShouldBe(_handlerOptions);
}
private void WhenICreate()
{
_result = _creator.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _configuration, _upstreamHost);
}
private void WhenICreateAgain()
{
_resultTwo = _creator.Get(_upstreamUrlPath, _upstreamQuery, _upstreamHttpMethod, _configuration, _upstreamHost);
}
private void ThenTheDownstreamRoutesAreTheSameReference()
{
_result.ShouldBe(_resultTwo);
}
private void ThenTheDownstreamRoutesAreTheNotSameReference()
{
_result.ShouldNotBe(_resultTwo);
}
}
}

View File

@ -24,7 +24,7 @@
{
private readonly Mock<IDownstreamRouteProvider> _finder;
private readonly Mock<IDownstreamRouteProviderFactory> _factory;
private Response<DownstreamRoute> _downstreamRoute;
private Response<Ocelot.DownstreamRouteFinder.DownstreamRouteHolder> _downstreamRoute;
private IInternalConfiguration _config;
private Mock<IOcelotLoggerFactory> _loggerFactory;
private Mock<IOcelotLogger> _logger;
@ -50,16 +50,16 @@
{
var config = new InternalConfiguration(null, null, new ServiceProviderConfigurationBuilder().Build(), "", new LoadBalancerOptionsBuilder().Build(), "", new QoSOptionsBuilder().Build(), new HttpHandlerOptionsBuilder().Build(), new Version("1.1"));
var downstreamReRoute = new DownstreamReRouteBuilder()
var downstreamRoute = new DownstreamRouteBuilder()
.WithDownstreamPathTemplate("any old string")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build();
this.Given(x => x.GivenTheDownStreamRouteFinderReturns(
new DownstreamRoute(
new DownstreamRouteHolder(
new List<PlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithDownstreamReRoute(downstreamReRoute)
new RouteBuilder()
.WithDownstreamRoute(downstreamRoute)
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.And(x => GivenTheFollowingConfig(config))
@ -79,9 +79,9 @@
_httpContext.Items.SetIInternalConfiguration(config);
}
private void GivenTheDownStreamRouteFinderReturns(DownstreamRoute downstreamRoute)
private void GivenTheDownStreamRouteFinderReturns(Ocelot.DownstreamRouteFinder.DownstreamRouteHolder downstreamRoute)
{
_downstreamRoute = new OkResponse<DownstreamRoute>(downstreamRoute);
_downstreamRoute = new OkResponse<Ocelot.DownstreamRouteFinder.DownstreamRouteHolder>(downstreamRoute);
_finder
.Setup(x => x.Get(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<IInternalConfiguration>(), It.IsAny<string>()))
.Returns(_downstreamRoute);

View File

@ -1,164 +1,164 @@
namespace Ocelot.UnitTests.DownstreamRouteFinder
{
using System;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.DownstreamRouteFinder.Finder;
using Ocelot.DownstreamRouteFinder.UrlMatcher;
using Ocelot.Logging;
using Shouldly;
using System.Collections.Generic;
using TestStack.BDDfy;
using Xunit;
public class DownstreamRouteProviderFactoryTests
{
private readonly DownstreamRouteProviderFactory _factory;
private IInternalConfiguration _config;
private IDownstreamRouteProvider _result;
private Mock<IOcelotLogger> _logger;
private Mock<IOcelotLoggerFactory> _loggerFactory;
public DownstreamRouteProviderFactoryTests()
{
var services = new ServiceCollection();
services.AddSingleton<IPlaceholderNameAndValueFinder, UrlPathPlaceholderNameAndValueFinder>();
services.AddSingleton<IUrlPathToUrlTemplateMatcher, RegExUrlMatcher>();
services.AddSingleton<IQoSOptionsCreator, QoSOptionsCreator>();
services.AddSingleton<IDownstreamRouteProvider, DownstreamRouteFinder>();
services.AddSingleton<IDownstreamRouteProvider, DownstreamRouteCreator>();
var provider = services.BuildServiceProvider();
_logger = new Mock<IOcelotLogger>();
_loggerFactory = new Mock<IOcelotLoggerFactory>();
_loggerFactory.Setup(x => x.CreateLogger<DownstreamRouteProviderFactory>()).Returns(_logger.Object);
_factory = new DownstreamRouteProviderFactory(provider, _loggerFactory.Object);
}
[Fact]
public void should_return_downstream_route_finder()
{
var reRoutes = new List<ReRoute>
{
new ReRouteBuilder().Build()
};
this.Given(_ => GivenTheReRoutes(reRoutes))
.When(_ => WhenIGet())
.Then(_ => ThenTheResultShouldBe<DownstreamRouteFinder>())
.BDDfy();
}
[Fact]
public void should_return_downstream_route_finder_when_not_dynamic_re_route_and_service_discovery_on()
{
var spConfig = new ServiceProviderConfigurationBuilder().WithScheme("http").WithHost("test").WithPort(50).WithType("test").Build();
var reRoutes = new List<ReRoute>
{
new ReRouteBuilder().WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("woot").Build()).Build()
};
this.Given(_ => GivenTheReRoutes(reRoutes, spConfig))
.When(_ => WhenIGet())
.Then(_ => ThenTheResultShouldBe<DownstreamRouteFinder>())
.BDDfy();
}
[Fact]
public void should_return_downstream_route_finder_as_no_service_discovery_given_no_scheme()
{
var spConfig = new ServiceProviderConfigurationBuilder().WithScheme("").WithHost("test").WithPort(50).Build();
var reRoutes = new List<ReRoute>();
this.Given(_ => GivenTheReRoutes(reRoutes, spConfig))
.When(_ => WhenIGet())
.Then(_ => ThenTheResultShouldBe<DownstreamRouteFinder>())
.BDDfy();
}
[Fact]
public void should_return_downstream_route_finder_as_no_service_discovery_given_no_host()
{
var spConfig = new ServiceProviderConfigurationBuilder().WithScheme("http").WithHost("").WithPort(50).Build();
var reRoutes = new List<ReRoute>();
this.Given(_ => GivenTheReRoutes(reRoutes, spConfig))
.When(_ => WhenIGet())
.Then(_ => ThenTheResultShouldBe<DownstreamRouteFinder>())
.BDDfy();
}
[Fact]
public void should_return_downstream_route_finder_given_no_service_discovery_port()
{
var spConfig = new ServiceProviderConfigurationBuilder().WithScheme("http").WithHost("localhost").WithPort(0).Build();
var reRoutes = new List<ReRoute>();
this.Given(_ => GivenTheReRoutes(reRoutes, spConfig))
.When(_ => WhenIGet())
.Then(_ => ThenTheResultShouldBe<DownstreamRouteFinder>())
.BDDfy();
}
[Fact]
public void should_return_downstream_route_finder_given_no_service_discovery_type()
{
var spConfig = new ServiceProviderConfigurationBuilder().WithScheme("http").WithHost("localhost").WithPort(50).WithType("").Build();
var reRoutes = new List<ReRoute>();
this.Given(_ => GivenTheReRoutes(reRoutes, spConfig))
.When(_ => WhenIGet())
.Then(_ => ThenTheResultShouldBe<DownstreamRouteFinder>())
.BDDfy();
}
[Fact]
public void should_return_downstream_route_creator()
{
var spConfig = new ServiceProviderConfigurationBuilder().WithScheme("http").WithHost("test").WithPort(50).WithType("test").Build();
var reRoutes = new List<ReRoute>();
this.Given(_ => GivenTheReRoutes(reRoutes, spConfig))
.When(_ => WhenIGet())
.Then(_ => ThenTheResultShouldBe<DownstreamRouteCreator>())
.BDDfy();
}
[Fact]
public void should_return_downstream_route_creator_with_dynamic_re_route()
{
var spConfig = new ServiceProviderConfigurationBuilder().WithScheme("http").WithHost("test").WithPort(50).WithType("test").Build();
var reRoutes = new List<ReRoute>
{
new ReRouteBuilder().Build()
};
this.Given(_ => GivenTheReRoutes(reRoutes, spConfig))
.When(_ => WhenIGet())
.Then(_ => ThenTheResultShouldBe<DownstreamRouteCreator>())
.BDDfy();
}
private void ThenTheResultShouldBe<T>()
{
_result.ShouldBeOfType<T>();
}
private void WhenIGet()
{
_result = _factory.Get(_config);
}
private void GivenTheReRoutes(List<ReRoute> reRoutes)
{
_config = new InternalConfiguration(reRoutes, "", null, "", new LoadBalancerOptionsBuilder().Build(), "", new QoSOptionsBuilder().Build(), new HttpHandlerOptionsBuilder().Build(), new Version("1.1"));
}
private void GivenTheReRoutes(List<ReRoute> reRoutes, ServiceProviderConfiguration config)
{
_config = new InternalConfiguration(reRoutes, "", config, "", new LoadBalancerOptionsBuilder().Build(), "", new QoSOptionsBuilder().Build(), new HttpHandlerOptionsBuilder().Build(), new Version("1.1"));
}
}
}
namespace Ocelot.UnitTests.DownstreamRouteFinder
{
using System;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
using Ocelot.DownstreamRouteFinder.Finder;
using Ocelot.DownstreamRouteFinder.UrlMatcher;
using Ocelot.Logging;
using Shouldly;
using System.Collections.Generic;
using TestStack.BDDfy;
using Xunit;
public class DownstreamRouteProviderFactoryTests
{
private readonly DownstreamRouteProviderFactory _factory;
private IInternalConfiguration _config;
private IDownstreamRouteProvider _result;
private Mock<IOcelotLogger> _logger;
private Mock<IOcelotLoggerFactory> _loggerFactory;
public DownstreamRouteProviderFactoryTests()
{
var services = new ServiceCollection();
services.AddSingleton<IPlaceholderNameAndValueFinder, UrlPathPlaceholderNameAndValueFinder>();
services.AddSingleton<IUrlPathToUrlTemplateMatcher, RegExUrlMatcher>();
services.AddSingleton<IQoSOptionsCreator, QoSOptionsCreator>();
services.AddSingleton<IDownstreamRouteProvider, DownstreamRouteFinder>();
services.AddSingleton<IDownstreamRouteProvider, DownstreamRouteCreator>();
var provider = services.BuildServiceProvider();
_logger = new Mock<IOcelotLogger>();
_loggerFactory = new Mock<IOcelotLoggerFactory>();
_loggerFactory.Setup(x => x.CreateLogger<DownstreamRouteProviderFactory>()).Returns(_logger.Object);
_factory = new DownstreamRouteProviderFactory(provider, _loggerFactory.Object);
}
[Fact]
public void should_return_downstream_route_finder()
{
var routes = new List<Route>
{
new RouteBuilder().Build()
};
this.Given(_ => GivenTheRoutes(routes))
.When(_ => WhenIGet())
.Then(_ => ThenTheResultShouldBe<DownstreamRouteFinder>())
.BDDfy();
}
[Fact]
public void should_return_downstream_route_finder_when_not_dynamic_re_route_and_service_discovery_on()
{
var spConfig = new ServiceProviderConfigurationBuilder().WithScheme("http").WithHost("test").WithPort(50).WithType("test").Build();
var routes = new List<Route>
{
new RouteBuilder().WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("woot").Build()).Build()
};
this.Given(_ => GivenTheRoutes(routes, spConfig))
.When(_ => WhenIGet())
.Then(_ => ThenTheResultShouldBe<DownstreamRouteFinder>())
.BDDfy();
}
[Fact]
public void should_return_downstream_route_finder_as_no_service_discovery_given_no_scheme()
{
var spConfig = new ServiceProviderConfigurationBuilder().WithScheme("").WithHost("test").WithPort(50).Build();
var routes = new List<Route>();
this.Given(_ => GivenTheRoutes(routes, spConfig))
.When(_ => WhenIGet())
.Then(_ => ThenTheResultShouldBe<DownstreamRouteFinder>())
.BDDfy();
}
[Fact]
public void should_return_downstream_route_finder_as_no_service_discovery_given_no_host()
{
var spConfig = new ServiceProviderConfigurationBuilder().WithScheme("http").WithHost("").WithPort(50).Build();
var routes = new List<Route>();
this.Given(_ => GivenTheRoutes(routes, spConfig))
.When(_ => WhenIGet())
.Then(_ => ThenTheResultShouldBe<DownstreamRouteFinder>())
.BDDfy();
}
[Fact]
public void should_return_downstream_route_finder_given_no_service_discovery_port()
{
var spConfig = new ServiceProviderConfigurationBuilder().WithScheme("http").WithHost("localhost").WithPort(0).Build();
var routes = new List<Route>();
this.Given(_ => GivenTheRoutes(routes, spConfig))
.When(_ => WhenIGet())
.Then(_ => ThenTheResultShouldBe<DownstreamRouteFinder>())
.BDDfy();
}
[Fact]
public void should_return_downstream_route_finder_given_no_service_discovery_type()
{
var spConfig = new ServiceProviderConfigurationBuilder().WithScheme("http").WithHost("localhost").WithPort(50).WithType("").Build();
var routes = new List<Route>();
this.Given(_ => GivenTheRoutes(routes, spConfig))
.When(_ => WhenIGet())
.Then(_ => ThenTheResultShouldBe<DownstreamRouteFinder>())
.BDDfy();
}
[Fact]
public void should_return_downstream_route_creator()
{
var spConfig = new ServiceProviderConfigurationBuilder().WithScheme("http").WithHost("test").WithPort(50).WithType("test").Build();
var routes = new List<Route>();
this.Given(_ => GivenTheRoutes(routes, spConfig))
.When(_ => WhenIGet())
.Then(_ => ThenTheResultShouldBe<DownstreamRouteCreator>())
.BDDfy();
}
[Fact]
public void should_return_downstream_route_creator_with_dynamic_re_route()
{
var spConfig = new ServiceProviderConfigurationBuilder().WithScheme("http").WithHost("test").WithPort(50).WithType("test").Build();
var routes = new List<Route>
{
new RouteBuilder().Build()
};
this.Given(_ => GivenTheRoutes(routes, spConfig))
.When(_ => WhenIGet())
.Then(_ => ThenTheResultShouldBe<DownstreamRouteCreator>())
.BDDfy();
}
private void ThenTheResultShouldBe<T>()
{
_result.ShouldBeOfType<T>();
}
private void WhenIGet()
{
_result = _factory.Get(_config);
}
private void GivenTheRoutes(List<Route> routes)
{
_config = new InternalConfiguration(routes, "", null, "", new LoadBalancerOptionsBuilder().Build(), "", new QoSOptionsBuilder().Build(), new HttpHandlerOptionsBuilder().Build(), new Version("1.1"));
}
private void GivenTheRoutes(List<Route> routes, ServiceProviderConfiguration config)
{
_config = new InternalConfiguration(routes, "", config, "", new LoadBalancerOptionsBuilder().Build(), "", new QoSOptionsBuilder().Build(), new HttpHandlerOptionsBuilder().Build(), new Version("1.1"));
}
}
}

View File

@ -1,440 +1,440 @@
namespace Ocelot.UnitTests.DownstreamUrlCreator
{
using Microsoft.AspNetCore.Http;
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.DownstreamRouteFinder;
using Ocelot.DownstreamRouteFinder.UrlMatcher;
using Ocelot.DownstreamUrlCreator.Middleware;
using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer;
using Ocelot.Logging;
using Ocelot.Middleware;
using Ocelot.Request.Middleware;
using Ocelot.Responses;
using Ocelot.Values;
using Shouldly;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Ocelot.Infrastructure.RequestData;
using TestStack.BDDfy;
namespace Ocelot.UnitTests.DownstreamUrlCreator
{
using Microsoft.AspNetCore.Http;
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.DownstreamRouteFinder;
using Ocelot.DownstreamRouteFinder.UrlMatcher;
using Ocelot.DownstreamUrlCreator.Middleware;
using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer;
using Ocelot.Logging;
using Ocelot.Middleware;
using Ocelot.Request.Middleware;
using Ocelot.Responses;
using Ocelot.Values;
using Shouldly;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Ocelot.Infrastructure.RequestData;
using TestStack.BDDfy;
using Xunit;
using Ocelot.DownstreamRouteFinder.Middleware;
public class DownstreamUrlCreatorMiddlewareTests
{
private readonly Mock<IDownstreamPathPlaceholderReplacer> _downstreamUrlTemplateVariableReplacer;
private OkResponse<DownstreamPath> _downstreamPath;
private readonly Mock<IOcelotLoggerFactory> _loggerFactory;
private Mock<IOcelotLogger> _logger;
private DownstreamUrlCreatorMiddleware _middleware;
private readonly RequestDelegate _next;
private readonly HttpRequestMessage _request;
private HttpContext _httpContext;
private Mock<IRequestScopedDataRepository> _repo;
public DownstreamUrlCreatorMiddlewareTests()
{
_repo = new Mock<IRequestScopedDataRepository>();
_httpContext = new DefaultHttpContext();
_loggerFactory = new Mock<IOcelotLoggerFactory>();
_logger = new Mock<IOcelotLogger>();
_loggerFactory.Setup(x => x.CreateLogger<DownstreamUrlCreatorMiddleware>()).Returns(_logger.Object);
_downstreamUrlTemplateVariableReplacer = new Mock<IDownstreamPathPlaceholderReplacer>();
public class DownstreamUrlCreatorMiddlewareTests
{
private readonly Mock<IDownstreamPathPlaceholderReplacer> _downstreamUrlTemplateVariableReplacer;
private OkResponse<DownstreamPath> _downstreamPath;
private readonly Mock<IOcelotLoggerFactory> _loggerFactory;
private Mock<IOcelotLogger> _logger;
private DownstreamUrlCreatorMiddleware _middleware;
private readonly RequestDelegate _next;
private readonly HttpRequestMessage _request;
private HttpContext _httpContext;
private Mock<IRequestScopedDataRepository> _repo;
public DownstreamUrlCreatorMiddlewareTests()
{
_repo = new Mock<IRequestScopedDataRepository>();
_httpContext = new DefaultHttpContext();
_loggerFactory = new Mock<IOcelotLoggerFactory>();
_logger = new Mock<IOcelotLogger>();
_loggerFactory.Setup(x => x.CreateLogger<DownstreamUrlCreatorMiddleware>()).Returns(_logger.Object);
_downstreamUrlTemplateVariableReplacer = new Mock<IDownstreamPathPlaceholderReplacer>();
_request = new HttpRequestMessage(HttpMethod.Get, "https://my.url/abc/?q=123");
_next = context => Task.CompletedTask;
}
[Fact]
public void should_replace_scheme_and_path()
{
var downstreamReRoute = new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("any old string")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.WithDownstreamScheme("https")
.Build();
var config = new ServiceProviderConfigurationBuilder()
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(
new DownstreamRoute(
new List<PlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithDownstreamReRoute(downstreamReRoute)
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.And(x => x.GivenTheDownstreamRequestUriIs("http://my.url/abc?q=123"))
.And(x => GivenTheServiceProviderConfigIs(config))
.And(x => x.GivenTheUrlReplacerWillReturn("/api/products/1"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamRequestUriIs("https://my.url:80/api/products/1?q=123"))
.And(x => ThenTheQueryStringIs("?q=123"))
.BDDfy();
}
[Fact]
public void should_replace_query_string()
{
var downstreamReRoute = new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("/api/units/{subscriptionId}/{unitId}/updates")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.WithDownstreamScheme("https")
.Build();
var config = new ServiceProviderConfigurationBuilder()
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(
new DownstreamRoute(
new List<PlaceholderNameAndValue>
{
new PlaceholderNameAndValue("{subscriptionId}", "1"),
new PlaceholderNameAndValue("{unitId}", "2")
},
new ReRouteBuilder()
.WithDownstreamReRoute(downstreamReRoute)
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:5000/api/subscriptions/1/updates?unitId=2"))
.And(x => GivenTheServiceProviderConfigIs(config))
.And(x => x.GivenTheUrlReplacerWillReturn("api/units/1/2/updates"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamRequestUriIs("https://localhost:5000/api/units/1/2/updates"))
.And(x => ThenTheQueryStringIs(""))
.BDDfy();
}
[Fact]
public void should_replace_query_string_but_leave_non_placeholder_queries()
{
var downstreamReRoute = new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("/api/units/{subscriptionId}/{unitId}/updates")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.WithDownstreamScheme("https")
.Build();
var config = new ServiceProviderConfigurationBuilder()
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(
new DownstreamRoute(
new List<PlaceholderNameAndValue>
{
new PlaceholderNameAndValue("{subscriptionId}", "1"),
new PlaceholderNameAndValue("{unitId}", "2")
},
new ReRouteBuilder()
.WithDownstreamReRoute(downstreamReRoute)
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:5000/api/subscriptions/1/updates?unitId=2&productId=2"))
.And(x => GivenTheServiceProviderConfigIs(config))
.And(x => x.GivenTheUrlReplacerWillReturn("api/units/1/2/updates"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamRequestUriIs("https://localhost:5000/api/units/1/2/updates?productId=2"))
.And(x => ThenTheQueryStringIs("?productId=2"))
.BDDfy();
}
[Fact]
public void should_replace_query_string_exact_match()
{
var downstreamReRoute = new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("/api/units/{subscriptionId}/{unitId}/updates/{unitIdIty}")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.WithDownstreamScheme("https")
.Build();
var config = new ServiceProviderConfigurationBuilder()
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(
new DownstreamRoute(
new List<PlaceholderNameAndValue>
{
new PlaceholderNameAndValue("{subscriptionId}", "1"),
new PlaceholderNameAndValue("{unitId}", "2"),
new PlaceholderNameAndValue("{unitIdIty}", "3")
},
new ReRouteBuilder()
.WithDownstreamReRoute(downstreamReRoute)
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:5000/api/subscriptions/1/updates?unitId=2?unitIdIty=3"))
.And(x => GivenTheServiceProviderConfigIs(config))
.And(x => x.GivenTheUrlReplacerWillReturn("api/units/1/2/updates/3"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamRequestUriIs("https://localhost:5000/api/units/1/2/updates/3"))
.And(x => ThenTheQueryStringIs(""))
.BDDfy();
}
[Fact]
public void should_not_create_service_fabric_url()
{
var downstreamReRoute = new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("any old string")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.WithDownstreamScheme("https")
.Build();
var config = new ServiceProviderConfigurationBuilder()
.WithType("ServiceFabric")
.WithHost("localhost")
.WithPort(19081)
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(
new DownstreamRoute(
new List<PlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithDownstreamReRoute(downstreamReRoute)
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.And(x => x.GivenTheDownstreamRequestUriIs("http://my.url/abc?q=123"))
.And(x => GivenTheServiceProviderConfigIs(config))
.And(x => x.GivenTheUrlReplacerWillReturn("/api/products/1"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamRequestUriIs("https://my.url:80/api/products/1?q=123"))
.BDDfy();
}
[Fact]
public void should_create_service_fabric_url()
{
var downstreamReRoute = new DownstreamReRouteBuilder()
.WithDownstreamScheme("http")
.WithServiceName("Ocelot/OcelotApp")
.WithUseServiceDiscovery(true)
.Build();
var downstreamRoute = new DownstreamRoute(
new List<PlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithDownstreamReRoute(downstreamReRoute)
.Build());
var config = new ServiceProviderConfigurationBuilder()
.WithType("ServiceFabric")
.WithHost("localhost")
.WithPort(19081)
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
.And(x => GivenTheServiceProviderConfigIs(config))
.And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:19081"))
.And(x => x.GivenTheUrlReplacerWillReturnSequence("/api/products/1", "Ocelot/OcelotApp"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamRequestUriIs("http://localhost:19081/Ocelot/OcelotApp/api/products/1"))
.BDDfy();
}
[Fact]
public void should_create_service_fabric_url_with_query_string_for_stateless_service()
{
var downstreamReRoute = new DownstreamReRouteBuilder()
.WithDownstreamScheme("http")
.WithServiceName("Ocelot/OcelotApp")
.WithUseServiceDiscovery(true)
.Build();
var downstreamRoute = new DownstreamRoute(
new List<PlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithDownstreamReRoute(downstreamReRoute)
.Build());
var config = new ServiceProviderConfigurationBuilder()
.WithType("ServiceFabric")
.WithHost("localhost")
.WithPort(19081)
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
.And(x => GivenTheServiceProviderConfigIs(config))
.And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:19081?Tom=test&laura=1"))
.And(x => x.GivenTheUrlReplacerWillReturnSequence("/api/products/1", "Ocelot/OcelotApp"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamRequestUriIs("http://localhost:19081/Ocelot/OcelotApp/api/products/1?Tom=test&laura=1"))
.BDDfy();
}
[Fact]
public void should_create_service_fabric_url_with_query_string_for_stateful_service()
{
var downstreamReRoute = new DownstreamReRouteBuilder()
.WithDownstreamScheme("http")
.WithServiceName("Ocelot/OcelotApp")
.WithUseServiceDiscovery(true)
.Build();
var downstreamRoute = new DownstreamRoute(
new List<PlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithDownstreamReRoute(downstreamReRoute)
.Build());
var config = new ServiceProviderConfigurationBuilder()
.WithType("ServiceFabric")
.WithHost("localhost")
.WithPort(19081)
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
.And(x => GivenTheServiceProviderConfigIs(config))
.And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:19081?PartitionKind=test&PartitionKey=1"))
.And(x => x.GivenTheUrlReplacerWillReturnSequence("/api/products/1", "Ocelot/OcelotApp"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamRequestUriIs("http://localhost:19081/Ocelot/OcelotApp/api/products/1?PartitionKind=test&PartitionKey=1"))
.BDDfy();
}
[Fact]
public void should_create_service_fabric_url_with_version_from_upstream_path_template()
{
var downstreamRoute = new DownstreamRoute(
new List<PlaceholderNameAndValue>(),
new ReRouteBuilder().WithDownstreamReRoute(
new DownstreamReRouteBuilder()
.WithDownstreamScheme("http")
.WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("/products").Build())
.WithUseServiceDiscovery(true)
.Build()
).Build());
var config = new ServiceProviderConfigurationBuilder()
.WithType("ServiceFabric")
.WithHost("localhost")
.WithPort(19081)
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
.And(x => GivenTheServiceProviderConfigIs(config))
.And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:19081?PartitionKind=test&PartitionKey=1"))
.And(x => x.GivenTheUrlReplacerWillReturnSequence("/products", "Service_1.0/Api"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamRequestUriIs("http://localhost:19081/Service_1.0/Api/products?PartitionKind=test&PartitionKey=1"))
.BDDfy();
}
[Fact]
public void issue_473_should_not_remove_additional_query_string()
{
var downstreamReRoute = new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("/Authorized/{action}?server={server}")
.WithUpstreamHttpMethod(new List<string> { "Post", "Get" })
.WithDownstreamScheme("http")
.WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("/uc/Authorized/{server}/{action}").Build())
.Build();
var config = new ServiceProviderConfigurationBuilder()
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(
new DownstreamRoute(
new List<PlaceholderNameAndValue>
{
new PlaceholderNameAndValue("{action}", "1"),
new PlaceholderNameAndValue("{server}", "2")
},
new ReRouteBuilder()
.WithDownstreamReRoute(downstreamReRoute)
.WithUpstreamHttpMethod(new List<string> { "Post", "Get" })
.Build())))
.And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:5000/uc/Authorized/2/1/refresh?refreshToken=2288356cfb1338fdc5ff4ca558ec785118dfe1ff2864340937da8226863ff66d"))
.And(x => GivenTheServiceProviderConfigIs(config))
.And(x => x.GivenTheUrlReplacerWillReturn("/Authorized/1?server=2"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamRequestUriIs("http://localhost:5000/Authorized/1?refreshToken=2288356cfb1338fdc5ff4ca558ec785118dfe1ff2864340937da8226863ff66d&server=2"))
.And(x => ThenTheQueryStringIs("?refreshToken=2288356cfb1338fdc5ff4ca558ec785118dfe1ff2864340937da8226863ff66d&server=2"))
.BDDfy();
}
[Fact]
public void should_not_replace_by_empty_scheme()
{
var downstreamReRoute = new DownstreamReRouteBuilder()
.WithDownstreamScheme("")
.WithServiceName("Ocelot/OcelotApp")
.WithUseServiceDiscovery(true)
.Build();
var downstreamRoute = new DownstreamRoute(
new List<PlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithDownstreamReRoute(downstreamReRoute)
.Build());
var config = new ServiceProviderConfigurationBuilder()
.WithType("ServiceFabric")
.WithHost("localhost")
.WithPort(19081)
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
.And(x => GivenTheServiceProviderConfigIs(config))
.And(x => x.GivenTheDownstreamRequestUriIs("https://localhost:19081?PartitionKind=test&PartitionKey=1"))
.And(x => x.GivenTheUrlReplacerWillReturnSequence("/api/products/1", "Ocelot/OcelotApp"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamRequestUriIs("https://localhost:19081/Ocelot/OcelotApp/api/products/1?PartitionKind=test&PartitionKey=1"))
.BDDfy();
}
private void GivenTheServiceProviderConfigIs(ServiceProviderConfiguration config)
{
_next = context => Task.CompletedTask;
}
[Fact]
public void should_replace_scheme_and_path()
{
var downstreamRoute = new DownstreamRouteBuilder()
.WithDownstreamPathTemplate("any old string")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.WithDownstreamScheme("https")
.Build();
var config = new ServiceProviderConfigurationBuilder()
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(
new DownstreamRouteHolder(
new List<PlaceholderNameAndValue>(),
new RouteBuilder()
.WithDownstreamRoute(downstreamRoute)
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.And(x => x.GivenTheDownstreamRequestUriIs("http://my.url/abc?q=123"))
.And(x => GivenTheServiceProviderConfigIs(config))
.And(x => x.GivenTheUrlReplacerWillReturn("/api/products/1"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamRequestUriIs("https://my.url:80/api/products/1?q=123"))
.And(x => ThenTheQueryStringIs("?q=123"))
.BDDfy();
}
[Fact]
public void should_replace_query_string()
{
var downstreamRoute = new DownstreamRouteBuilder()
.WithDownstreamPathTemplate("/api/units/{subscriptionId}/{unitId}/updates")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.WithDownstreamScheme("https")
.Build();
var config = new ServiceProviderConfigurationBuilder()
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(
new DownstreamRouteHolder(
new List<PlaceholderNameAndValue>
{
new PlaceholderNameAndValue("{subscriptionId}", "1"),
new PlaceholderNameAndValue("{unitId}", "2")
},
new RouteBuilder()
.WithDownstreamRoute(downstreamRoute)
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:5000/api/subscriptions/1/updates?unitId=2"))
.And(x => GivenTheServiceProviderConfigIs(config))
.And(x => x.GivenTheUrlReplacerWillReturn("api/units/1/2/updates"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamRequestUriIs("https://localhost:5000/api/units/1/2/updates"))
.And(x => ThenTheQueryStringIs(""))
.BDDfy();
}
[Fact]
public void should_replace_query_string_but_leave_non_placeholder_queries()
{
var downstreamRoute = new DownstreamRouteBuilder()
.WithDownstreamPathTemplate("/api/units/{subscriptionId}/{unitId}/updates")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.WithDownstreamScheme("https")
.Build();
var config = new ServiceProviderConfigurationBuilder()
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(
new DownstreamRouteHolder(
new List<PlaceholderNameAndValue>
{
new PlaceholderNameAndValue("{subscriptionId}", "1"),
new PlaceholderNameAndValue("{unitId}", "2")
},
new RouteBuilder()
.WithDownstreamRoute(downstreamRoute)
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:5000/api/subscriptions/1/updates?unitId=2&productId=2"))
.And(x => GivenTheServiceProviderConfigIs(config))
.And(x => x.GivenTheUrlReplacerWillReturn("api/units/1/2/updates"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamRequestUriIs("https://localhost:5000/api/units/1/2/updates?productId=2"))
.And(x => ThenTheQueryStringIs("?productId=2"))
.BDDfy();
}
[Fact]
public void should_replace_query_string_exact_match()
{
var downstreamRoute = new DownstreamRouteBuilder()
.WithDownstreamPathTemplate("/api/units/{subscriptionId}/{unitId}/updates/{unitIdIty}")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.WithDownstreamScheme("https")
.Build();
var config = new ServiceProviderConfigurationBuilder()
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(
new DownstreamRouteHolder(
new List<PlaceholderNameAndValue>
{
new PlaceholderNameAndValue("{subscriptionId}", "1"),
new PlaceholderNameAndValue("{unitId}", "2"),
new PlaceholderNameAndValue("{unitIdIty}", "3")
},
new RouteBuilder()
.WithDownstreamRoute(downstreamRoute)
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:5000/api/subscriptions/1/updates?unitId=2?unitIdIty=3"))
.And(x => GivenTheServiceProviderConfigIs(config))
.And(x => x.GivenTheUrlReplacerWillReturn("api/units/1/2/updates/3"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamRequestUriIs("https://localhost:5000/api/units/1/2/updates/3"))
.And(x => ThenTheQueryStringIs(""))
.BDDfy();
}
[Fact]
public void should_not_create_service_fabric_url()
{
var downstreamRoute = new DownstreamRouteBuilder()
.WithDownstreamPathTemplate("any old string")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.WithDownstreamScheme("https")
.Build();
var config = new ServiceProviderConfigurationBuilder()
.WithType("ServiceFabric")
.WithHost("localhost")
.WithPort(19081)
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(
new DownstreamRouteHolder(
new List<PlaceholderNameAndValue>(),
new RouteBuilder()
.WithDownstreamRoute(downstreamRoute)
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.And(x => x.GivenTheDownstreamRequestUriIs("http://my.url/abc?q=123"))
.And(x => GivenTheServiceProviderConfigIs(config))
.And(x => x.GivenTheUrlReplacerWillReturn("/api/products/1"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamRequestUriIs("https://my.url:80/api/products/1?q=123"))
.BDDfy();
}
[Fact]
public void should_create_service_fabric_url()
{
var downstreamRoute = new DownstreamRouteBuilder()
.WithDownstreamScheme("http")
.WithServiceName("Ocelot/OcelotApp")
.WithUseServiceDiscovery(true)
.Build();
var downstreamRouteHolder = new Ocelot.DownstreamRouteFinder.DownstreamRouteHolder(
new List<PlaceholderNameAndValue>(),
new RouteBuilder()
.WithDownstreamRoute(downstreamRoute)
.Build());
var config = new ServiceProviderConfigurationBuilder()
.WithType("ServiceFabric")
.WithHost("localhost")
.WithPort(19081)
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRouteHolder))
.And(x => GivenTheServiceProviderConfigIs(config))
.And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:19081"))
.And(x => x.GivenTheUrlReplacerWillReturnSequence("/api/products/1", "Ocelot/OcelotApp"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamRequestUriIs("http://localhost:19081/Ocelot/OcelotApp/api/products/1"))
.BDDfy();
}
[Fact]
public void should_create_service_fabric_url_with_query_string_for_stateless_service()
{
var downstreamRoute = new DownstreamRouteBuilder()
.WithDownstreamScheme("http")
.WithServiceName("Ocelot/OcelotApp")
.WithUseServiceDiscovery(true)
.Build();
var downstreamRouteHolder = new Ocelot.DownstreamRouteFinder.DownstreamRouteHolder(
new List<PlaceholderNameAndValue>(),
new RouteBuilder()
.WithDownstreamRoute(downstreamRoute)
.Build());
var config = new ServiceProviderConfigurationBuilder()
.WithType("ServiceFabric")
.WithHost("localhost")
.WithPort(19081)
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRouteHolder))
.And(x => GivenTheServiceProviderConfigIs(config))
.And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:19081?Tom=test&laura=1"))
.And(x => x.GivenTheUrlReplacerWillReturnSequence("/api/products/1", "Ocelot/OcelotApp"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamRequestUriIs("http://localhost:19081/Ocelot/OcelotApp/api/products/1?Tom=test&laura=1"))
.BDDfy();
}
[Fact]
public void should_create_service_fabric_url_with_query_string_for_stateful_service()
{
var downstreamRoute = new DownstreamRouteBuilder()
.WithDownstreamScheme("http")
.WithServiceName("Ocelot/OcelotApp")
.WithUseServiceDiscovery(true)
.Build();
var downstreamRouteHolder = new Ocelot.DownstreamRouteFinder.DownstreamRouteHolder(
new List<PlaceholderNameAndValue>(),
new RouteBuilder()
.WithDownstreamRoute(downstreamRoute)
.Build());
var config = new ServiceProviderConfigurationBuilder()
.WithType("ServiceFabric")
.WithHost("localhost")
.WithPort(19081)
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRouteHolder))
.And(x => GivenTheServiceProviderConfigIs(config))
.And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:19081?PartitionKind=test&PartitionKey=1"))
.And(x => x.GivenTheUrlReplacerWillReturnSequence("/api/products/1", "Ocelot/OcelotApp"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamRequestUriIs("http://localhost:19081/Ocelot/OcelotApp/api/products/1?PartitionKind=test&PartitionKey=1"))
.BDDfy();
}
[Fact]
public void should_create_service_fabric_url_with_version_from_upstream_path_template()
{
var downstreamRoute = new Ocelot.DownstreamRouteFinder.DownstreamRouteHolder(
new List<PlaceholderNameAndValue>(),
new RouteBuilder().WithDownstreamRoute(
new DownstreamRouteBuilder()
.WithDownstreamScheme("http")
.WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("/products").Build())
.WithUseServiceDiscovery(true)
.Build()
).Build());
var config = new ServiceProviderConfigurationBuilder()
.WithType("ServiceFabric")
.WithHost("localhost")
.WithPort(19081)
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
.And(x => GivenTheServiceProviderConfigIs(config))
.And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:19081?PartitionKind=test&PartitionKey=1"))
.And(x => x.GivenTheUrlReplacerWillReturnSequence("/products", "Service_1.0/Api"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamRequestUriIs("http://localhost:19081/Service_1.0/Api/products?PartitionKind=test&PartitionKey=1"))
.BDDfy();
}
[Fact]
public void issue_473_should_not_remove_additional_query_string()
{
var downstreamRoute = new DownstreamRouteBuilder()
.WithDownstreamPathTemplate("/Authorized/{action}?server={server}")
.WithUpstreamHttpMethod(new List<string> { "Post", "Get" })
.WithDownstreamScheme("http")
.WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().WithOriginalValue("/uc/Authorized/{server}/{action}").Build())
.Build();
var config = new ServiceProviderConfigurationBuilder()
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(
new DownstreamRouteHolder(
new List<PlaceholderNameAndValue>
{
new PlaceholderNameAndValue("{action}", "1"),
new PlaceholderNameAndValue("{server}", "2")
},
new RouteBuilder()
.WithDownstreamRoute(downstreamRoute)
.WithUpstreamHttpMethod(new List<string> { "Post", "Get" })
.Build())))
.And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:5000/uc/Authorized/2/1/refresh?refreshToken=2288356cfb1338fdc5ff4ca558ec785118dfe1ff2864340937da8226863ff66d"))
.And(x => GivenTheServiceProviderConfigIs(config))
.And(x => x.GivenTheUrlReplacerWillReturn("/Authorized/1?server=2"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamRequestUriIs("http://localhost:5000/Authorized/1?refreshToken=2288356cfb1338fdc5ff4ca558ec785118dfe1ff2864340937da8226863ff66d&server=2"))
.And(x => ThenTheQueryStringIs("?refreshToken=2288356cfb1338fdc5ff4ca558ec785118dfe1ff2864340937da8226863ff66d&server=2"))
.BDDfy();
}
[Fact]
public void should_not_replace_by_empty_scheme()
{
var downstreamRoute = new DownstreamRouteBuilder()
.WithDownstreamScheme("")
.WithServiceName("Ocelot/OcelotApp")
.WithUseServiceDiscovery(true)
.Build();
var downstreamRouteHolder = new Ocelot.DownstreamRouteFinder.DownstreamRouteHolder(
new List<PlaceholderNameAndValue>(),
new RouteBuilder()
.WithDownstreamRoute(downstreamRoute)
.Build());
var config = new ServiceProviderConfigurationBuilder()
.WithType("ServiceFabric")
.WithHost("localhost")
.WithPort(19081)
.Build();
this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRouteHolder))
.And(x => GivenTheServiceProviderConfigIs(config))
.And(x => x.GivenTheDownstreamRequestUriIs("https://localhost:19081?PartitionKind=test&PartitionKey=1"))
.And(x => x.GivenTheUrlReplacerWillReturnSequence("/api/products/1", "Ocelot/OcelotApp"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheDownstreamRequestUriIs("https://localhost:19081/Ocelot/OcelotApp/api/products/1?PartitionKind=test&PartitionKey=1"))
.BDDfy();
}
private void GivenTheServiceProviderConfigIs(ServiceProviderConfiguration config)
{
var configuration = new InternalConfiguration(null, null, config, null, null, null, null, null, null);
_httpContext.Items.SetIInternalConfiguration(configuration);
}
private void WhenICallTheMiddleware()
{
_middleware = new DownstreamUrlCreatorMiddleware(_next, _loggerFactory.Object, _downstreamUrlTemplateVariableReplacer.Object);
_middleware.Invoke(_httpContext).GetAwaiter().GetResult();
}
private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute)
_httpContext.Items.SetIInternalConfiguration(configuration);
}
private void WhenICallTheMiddleware()
{
_middleware = new DownstreamUrlCreatorMiddleware(_next, _loggerFactory.Object, _downstreamUrlTemplateVariableReplacer.Object);
_middleware.Invoke(_httpContext).GetAwaiter().GetResult();
}
private void GivenTheDownStreamRouteIs(Ocelot.DownstreamRouteFinder.DownstreamRouteHolder downstreamRoute)
{
_httpContext.Items.UpsertTemplatePlaceholderNameAndValues(downstreamRoute.TemplatePlaceholderNameAndValues);
_httpContext.Items.UpsertDownstreamReRoute(downstreamRoute.ReRoute.DownstreamReRoute[0]);
}
private void GivenTheDownstreamRequestUriIs(string uri)
{
_httpContext.Items.UpsertDownstreamRoute(downstreamRoute.Route.DownstreamRoute[0]);
}
private void GivenTheDownstreamRequestUriIs(string uri)
{
_request.RequestUri = new Uri(uri);
_httpContext.Items.UpsertDownstreamRequest(new DownstreamRequest(_request));
}
private void GivenTheUrlReplacerWillReturnSequence(params string[] paths)
{
var setup = _downstreamUrlTemplateVariableReplacer
.SetupSequence(x => x.Replace(It.IsAny<string>(), It.IsAny<List<PlaceholderNameAndValue>>()));
foreach (var path in paths)
{
var response = new OkResponse<DownstreamPath>(new DownstreamPath(path));
setup.Returns(response);
}
}
private void GivenTheUrlReplacerWillReturn(string path)
{
_downstreamPath = new OkResponse<DownstreamPath>(new DownstreamPath(path));
_downstreamUrlTemplateVariableReplacer
.Setup(x => x.Replace(It.IsAny<string>(), It.IsAny<List<PlaceholderNameAndValue>>()))
.Returns(_downstreamPath);
}
private void ThenTheDownstreamRequestUriIs(string expectedUri)
{
_httpContext.Items.DownstreamRequest().ToHttpRequestMessage().RequestUri.OriginalString.ShouldBe(expectedUri);
}
private void ThenTheQueryStringIs(string queryString)
{
_httpContext.Items.DownstreamRequest().Query.ShouldBe(queryString);
}
}
}
}
private void GivenTheUrlReplacerWillReturnSequence(params string[] paths)
{
var setup = _downstreamUrlTemplateVariableReplacer
.SetupSequence(x => x.Replace(It.IsAny<string>(), It.IsAny<List<PlaceholderNameAndValue>>()));
foreach (var path in paths)
{
var response = new OkResponse<DownstreamPath>(new DownstreamPath(path));
setup.Returns(response);
}
}
private void GivenTheUrlReplacerWillReturn(string path)
{
_downstreamPath = new OkResponse<DownstreamPath>(new DownstreamPath(path));
_downstreamUrlTemplateVariableReplacer
.Setup(x => x.Replace(It.IsAny<string>(), It.IsAny<List<PlaceholderNameAndValue>>()))
.Returns(_downstreamPath);
}
private void ThenTheDownstreamRequestUriIs(string expectedUri)
{
_httpContext.Items.DownstreamRequest().ToHttpRequestMessage().RequestUri.OriginalString.ShouldBe(expectedUri);
}
private void ThenTheQueryStringIs(string queryString)
{
_httpContext.Items.DownstreamRequest().Query.ShouldBe(queryString);
}
}
}

View File

@ -1,210 +1,210 @@
using Ocelot.Configuration.Builder;
using Ocelot.DownstreamRouteFinder;
using Ocelot.DownstreamRouteFinder.UrlMatcher;
using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer;
using Ocelot.Responses;
using Ocelot.Values;
using Shouldly;
using System.Collections.Generic;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer
{
public class UpstreamUrlPathTemplateVariableReplacerTests
{
private DownstreamRoute _downstreamRoute;
private Response<DownstreamPath> _result;
private readonly IDownstreamPathPlaceholderReplacer _downstreamPathReplacer;
public UpstreamUrlPathTemplateVariableReplacerTests()
{
_downstreamPathReplacer = new DownstreamTemplatePathPlaceholderReplacer();
}
[Fact]
public void can_replace_no_template_variables()
{
this.Given(x => x.GivenThereIsAUrlMatch(
new DownstreamRoute(
new List<PlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.When(x => x.WhenIReplaceTheTemplateVariables())
.Then(x => x.ThenTheDownstreamUrlPathIsReturned(""))
.BDDfy();
}
[Fact]
public void can_replace_no_template_variables_with_slash()
{
this.Given(x => x.GivenThereIsAUrlMatch(
new DownstreamRoute(
new List<PlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("/")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.When(x => x.WhenIReplaceTheTemplateVariables())
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("/"))
.BDDfy();
}
[Fact]
public void can_replace_url_no_slash()
{
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List<PlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("api")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.When(x => x.WhenIReplaceTheTemplateVariables())
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("api"))
.BDDfy();
}
[Fact]
public void can_replace_url_one_slash()
{
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List<PlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("api/")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.When(x => x.WhenIReplaceTheTemplateVariables())
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/"))
.BDDfy();
}
[Fact]
public void can_replace_url_multiple_slash()
{
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(new List<PlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("api/product/products/")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.When(x => x.WhenIReplaceTheTemplateVariables())
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/product/products/"))
.BDDfy();
}
[Fact]
public void can_replace_url_one_template_variable()
{
var templateVariables = new List<PlaceholderNameAndValue>()
{
new PlaceholderNameAndValue("{productId}", "1")
};
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables,
new ReRouteBuilder()
.WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("productservice/products/{productId}/")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.When(x => x.WhenIReplaceTheTemplateVariables())
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/"))
.BDDfy();
}
[Fact]
public void can_replace_url_one_template_variable_with_path_after()
{
var templateVariables = new List<PlaceholderNameAndValue>()
{
new PlaceholderNameAndValue("{productId}", "1")
};
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables,
new ReRouteBuilder()
.WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("productservice/products/{productId}/variants")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.When(x => x.WhenIReplaceTheTemplateVariables())
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants"))
.BDDfy();
}
[Fact]
public void can_replace_url_two_template_variable()
{
var templateVariables = new List<PlaceholderNameAndValue>()
{
new PlaceholderNameAndValue("{productId}", "1"),
new PlaceholderNameAndValue("{variantId}", "12")
};
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables,
new ReRouteBuilder()
.WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("productservice/products/{productId}/variants/{variantId}")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.When(x => x.WhenIReplaceTheTemplateVariables())
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants/12"))
.BDDfy();
using Ocelot.Configuration.Builder;
using Ocelot.DownstreamRouteFinder;
using Ocelot.DownstreamRouteFinder.UrlMatcher;
using Ocelot.DownstreamUrlCreator.UrlTemplateReplacer;
using Ocelot.Responses;
using Ocelot.Values;
using Shouldly;
using System.Collections.Generic;
using TestStack.BDDfy;
using Xunit;
namespace Ocelot.UnitTests.DownstreamUrlCreator.UrlTemplateReplacer
{
public class UpstreamUrlPathTemplateVariableReplacerTests
{
private DownstreamRouteHolder _downstreamRoute;
private Response<DownstreamPath> _result;
private readonly IDownstreamPathPlaceholderReplacer _downstreamPathReplacer;
public UpstreamUrlPathTemplateVariableReplacerTests()
{
_downstreamPathReplacer = new DownstreamTemplatePathPlaceholderReplacer();
}
[Fact]
public void can_replace_url_three_template_variable()
{
var templateVariables = new List<PlaceholderNameAndValue>()
{
new PlaceholderNameAndValue("{productId}", "1"),
new PlaceholderNameAndValue("{variantId}", "12"),
new PlaceholderNameAndValue("{categoryId}", "34")
};
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRoute(templateVariables,
new ReRouteBuilder()
.WithDownstreamReRoute(new DownstreamReRouteBuilder()
.WithDownstreamPathTemplate("productservice/category/{categoryId}/products/{productId}/variants/{variantId}")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.When(x => x.WhenIReplaceTheTemplateVariables())
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/category/34/products/1/variants/12"))
.BDDfy();
}
private void GivenThereIsAUrlMatch(DownstreamRoute downstreamRoute)
{
_downstreamRoute = downstreamRoute;
}
private void WhenIReplaceTheTemplateVariables()
{
_result = _downstreamPathReplacer.Replace(_downstreamRoute.ReRoute.DownstreamReRoute[0].DownstreamPathTemplate.Value, _downstreamRoute.TemplatePlaceholderNameAndValues);
}
private void ThenTheDownstreamUrlPathIsReturned(string expected)
{
_result.Data.Value.ShouldBe(expected);
}
}
[Fact]
public void can_replace_no_template_variables()
{
this.Given(x => x.GivenThereIsAUrlMatch(
new DownstreamRouteHolder(
new List<PlaceholderNameAndValue>(),
new RouteBuilder()
.WithDownstreamRoute(new DownstreamRouteBuilder()
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.When(x => x.WhenIReplaceTheTemplateVariables())
.Then(x => x.ThenTheDownstreamUrlPathIsReturned(""))
.BDDfy();
}
[Fact]
public void can_replace_no_template_variables_with_slash()
{
this.Given(x => x.GivenThereIsAUrlMatch(
new DownstreamRouteHolder(
new List<PlaceholderNameAndValue>(),
new RouteBuilder()
.WithDownstreamRoute(new DownstreamRouteBuilder()
.WithDownstreamPathTemplate("/")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.When(x => x.WhenIReplaceTheTemplateVariables())
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("/"))
.BDDfy();
}
[Fact]
public void can_replace_url_no_slash()
{
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRouteHolder(new List<PlaceholderNameAndValue>(),
new RouteBuilder()
.WithDownstreamRoute(new DownstreamRouteBuilder()
.WithDownstreamPathTemplate("api")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.When(x => x.WhenIReplaceTheTemplateVariables())
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("api"))
.BDDfy();
}
[Fact]
public void can_replace_url_one_slash()
{
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRouteHolder(new List<PlaceholderNameAndValue>(),
new RouteBuilder()
.WithDownstreamRoute(new DownstreamRouteBuilder()
.WithDownstreamPathTemplate("api/")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.When(x => x.WhenIReplaceTheTemplateVariables())
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/"))
.BDDfy();
}
[Fact]
public void can_replace_url_multiple_slash()
{
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRouteHolder(new List<PlaceholderNameAndValue>(),
new RouteBuilder()
.WithDownstreamRoute(new DownstreamRouteBuilder()
.WithDownstreamPathTemplate("api/product/products/")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.When(x => x.WhenIReplaceTheTemplateVariables())
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("api/product/products/"))
.BDDfy();
}
[Fact]
public void can_replace_url_one_template_variable()
{
var templateVariables = new List<PlaceholderNameAndValue>()
{
new PlaceholderNameAndValue("{productId}", "1")
};
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRouteHolder(templateVariables,
new RouteBuilder()
.WithDownstreamRoute(new DownstreamRouteBuilder()
.WithDownstreamPathTemplate("productservice/products/{productId}/")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.When(x => x.WhenIReplaceTheTemplateVariables())
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/"))
.BDDfy();
}
[Fact]
public void can_replace_url_one_template_variable_with_path_after()
{
var templateVariables = new List<PlaceholderNameAndValue>()
{
new PlaceholderNameAndValue("{productId}", "1")
};
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRouteHolder(templateVariables,
new RouteBuilder()
.WithDownstreamRoute(new DownstreamRouteBuilder()
.WithDownstreamPathTemplate("productservice/products/{productId}/variants")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.When(x => x.WhenIReplaceTheTemplateVariables())
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants"))
.BDDfy();
}
[Fact]
public void can_replace_url_two_template_variable()
{
var templateVariables = new List<PlaceholderNameAndValue>()
{
new PlaceholderNameAndValue("{productId}", "1"),
new PlaceholderNameAndValue("{variantId}", "12")
};
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRouteHolder(templateVariables,
new RouteBuilder()
.WithDownstreamRoute(new DownstreamRouteBuilder()
.WithDownstreamPathTemplate("productservice/products/{productId}/variants/{variantId}")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.When(x => x.WhenIReplaceTheTemplateVariables())
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/products/1/variants/12"))
.BDDfy();
}
[Fact]
public void can_replace_url_three_template_variable()
{
var templateVariables = new List<PlaceholderNameAndValue>()
{
new PlaceholderNameAndValue("{productId}", "1"),
new PlaceholderNameAndValue("{variantId}", "12"),
new PlaceholderNameAndValue("{categoryId}", "34")
};
this.Given(x => x.GivenThereIsAUrlMatch(new DownstreamRouteHolder(templateVariables,
new RouteBuilder()
.WithDownstreamRoute(new DownstreamRouteBuilder()
.WithDownstreamPathTemplate("productservice/category/{categoryId}/products/{productId}/variants/{variantId}")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build())))
.When(x => x.WhenIReplaceTheTemplateVariables())
.Then(x => x.ThenTheDownstreamUrlPathIsReturned("productservice/category/34/products/1/variants/12"))
.BDDfy();
}
private void GivenThereIsAUrlMatch(DownstreamRouteHolder downstreamRoute)
{
_downstreamRoute = downstreamRoute;
}
private void WhenIReplaceTheTemplateVariables()
{
_result = _downstreamPathReplacer.Replace(_downstreamRoute.Route.DownstreamRoute[0].DownstreamPathTemplate.Value, _downstreamRoute.TemplatePlaceholderNameAndValues);
}
private void ThenTheDownstreamUrlPathIsReturned(string expected)
{
_result.Data.Value.ShouldBe(expected);
}
}
}

View File

@ -1,37 +1,37 @@
namespace Ocelot.UnitTests.Eureka
{
using Microsoft.Extensions.DependencyInjection;
using Moq;
using Ocelot.Configuration.Builder;
using Provider.Eureka;
using Shouldly;
using Steeltoe.Common.Discovery;
using Xunit;
public class EurekaProviderFactoryTests
{
[Fact]
public void should_not_get()
{
var config = new ServiceProviderConfigurationBuilder().Build();
var sp = new ServiceCollection().BuildServiceProvider();
var provider = EurekaProviderFactory.Get(sp, config, null);
provider.ShouldBeNull();
}
[Fact]
public void should_get()
{
var config = new ServiceProviderConfigurationBuilder().WithType("eureka").Build();
var client = new Mock<IDiscoveryClient>();
var services = new ServiceCollection();
services.AddSingleton<IDiscoveryClient>(client.Object);
var sp = services.BuildServiceProvider();
var reRoute = new DownstreamReRouteBuilder()
.WithServiceName("")
.Build();
var provider = EurekaProviderFactory.Get(sp, config, reRoute);
provider.ShouldBeOfType<Eureka>();
}
}
}
namespace Ocelot.UnitTests.Eureka
{
using Microsoft.Extensions.DependencyInjection;
using Moq;
using Ocelot.Configuration.Builder;
using Provider.Eureka;
using Shouldly;
using Steeltoe.Common.Discovery;
using Xunit;
public class EurekaProviderFactoryTests
{
[Fact]
public void should_not_get()
{
var config = new ServiceProviderConfigurationBuilder().Build();
var sp = new ServiceCollection().BuildServiceProvider();
var provider = EurekaProviderFactory.Get(sp, config, null);
provider.ShouldBeNull();
}
[Fact]
public void should_get()
{
var config = new ServiceProviderConfigurationBuilder().WithType("eureka").Build();
var client = new Mock<IDiscoveryClient>();
var services = new ServiceCollection();
services.AddSingleton<IDiscoveryClient>(client.Object);
var sp = services.BuildServiceProvider();
var route = new DownstreamRouteBuilder()
.WithServiceName("")
.Build();
var provider = EurekaProviderFactory.Get(sp, config, route);
provider.ShouldBeOfType<Eureka>();
}
}
}

View File

@ -22,7 +22,7 @@
public class ClaimsToHeadersMiddlewareTests
{
private readonly Mock<IAddHeadersToRequest> _addHeaders;
private Response<DownstreamRoute> _downstreamRoute;
private Response<Ocelot.DownstreamRouteFinder.DownstreamRouteHolder> _downstreamRoute;
private Mock<IOcelotLoggerFactory> _loggerFactory;
private Mock<IOcelotLogger> _logger;
private ClaimsToHeadersMiddleware _middleware;
@ -44,9 +44,9 @@
[Fact]
public void should_call_add_headers_to_request_correctly()
{
var downstreamRoute = new DownstreamRoute(new List<PlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithDownstreamReRoute(new DownstreamReRouteBuilder()
var downstreamRoute = new Ocelot.DownstreamRouteFinder.DownstreamRouteHolder(new List<PlaceholderNameAndValue>(),
new RouteBuilder()
.WithDownstreamRoute(new DownstreamRouteBuilder()
.WithDownstreamPathTemplate("any old string")
.WithClaimsToHeaders(new List<ClaimToThing>
{
@ -69,13 +69,13 @@
_middleware.Invoke(_httpContext).GetAwaiter().GetResult();
}
private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute)
private void GivenTheDownStreamRouteIs(Ocelot.DownstreamRouteFinder.DownstreamRouteHolder downstreamRoute)
{
_downstreamRoute = new OkResponse<DownstreamRoute>(downstreamRoute);
_downstreamRoute = new OkResponse<Ocelot.DownstreamRouteFinder.DownstreamRouteHolder>(downstreamRoute);
_httpContext.Items.UpsertTemplatePlaceholderNameAndValues(downstreamRoute.TemplatePlaceholderNameAndValues);
_httpContext.Items.UpsertDownstreamReRoute(downstreamRoute.ReRoute.DownstreamReRoute[0]);
_httpContext.Items.UpsertDownstreamRoute(downstreamRoute.Route.DownstreamRoute[0]);
}
private void GivenTheAddHeadersToDownstreamRequestReturnsOk()

View File

@ -52,7 +52,7 @@ namespace Ocelot.UnitTests.Headers
{
this.Given(x => GivenTheFollowingRequest())
.And(x => GivenTheDownstreamRequestIs())
.And(x => GivenTheReRouteHasPreFindAndReplaceSetUp())
.And(x => GivenTheRouteHasPreFindAndReplaceSetUp())
.And(x => GivenTheHttpResponseMessageIs())
.When(x => WhenICallTheMiddleware())
.Then(x => ThenTheIHttpContextRequestHeaderReplacerIsCalledCorrectly())
@ -65,13 +65,13 @@ namespace Ocelot.UnitTests.Headers
private void ThenAddHeadersToResponseIsCalledCorrectly()
{
_addHeadersToResponse
.Verify(x => x.Add(_httpContext.Items.DownstreamReRoute().AddHeadersToDownstream, _httpContext.Items.DownstreamResponse()), Times.Once);
.Verify(x => x.Add(_httpContext.Items.DownstreamRoute().AddHeadersToDownstream, _httpContext.Items.DownstreamResponse()), Times.Once);
}
private void ThenAddHeadersToRequestIsCalledCorrectly()
{
_addHeadersToRequest
.Verify(x => x.SetHeadersOnDownstreamRequest(_httpContext.Items.DownstreamReRoute().AddHeadersToUpstream, _httpContext), Times.Once);
.Verify(x => x.SetHeadersOnDownstreamRequest(_httpContext.Items.DownstreamRoute().AddHeadersToUpstream, _httpContext), Times.Once);
}
private void WhenICallTheMiddleware()
@ -89,18 +89,18 @@ namespace Ocelot.UnitTests.Headers
_httpContext.Items.UpsertDownstreamResponse(new DownstreamResponse(new HttpResponseMessage()));
}
private void GivenTheReRouteHasPreFindAndReplaceSetUp()
private void GivenTheRouteHasPreFindAndReplaceSetUp()
{
var fAndRs = new List<HeaderFindAndReplace>();
var reRoute = new ReRouteBuilder()
.WithDownstreamReRoute(new DownstreamReRouteBuilder().WithUpstreamHeaderFindAndReplace(fAndRs)
var route = new RouteBuilder()
.WithDownstreamRoute(new DownstreamRouteBuilder().WithUpstreamHeaderFindAndReplace(fAndRs)
.WithDownstreamHeaderFindAndReplace(fAndRs).Build())
.Build();
var dR = new DownstreamRoute(null, reRoute);
var dR = new Ocelot.DownstreamRouteFinder.DownstreamRouteHolder(null, route);
_httpContext.Items.UpsertTemplatePlaceholderNameAndValues(dR.TemplatePlaceholderNameAndValues);
_httpContext.Items.UpsertDownstreamReRoute(dR.ReRoute.DownstreamReRoute[0]);
_httpContext.Items.UpsertDownstreamRoute(dR.Route.DownstreamRoute[0]);
}
private void ThenTheIHttpContextRequestHeaderReplacerIsCalledCorrectly()

View File

@ -1,74 +1,74 @@
namespace Ocelot.UnitTests.LoadBalancer
{
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.LoadBalancer.LoadBalancers;
using Ocelot.ServiceDiscovery.Providers;
using Ocelot.Responses;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
public class CookieStickySessionsCreatorTests
{
private readonly CookieStickySessionsCreator _creator;
private readonly Mock<IServiceDiscoveryProvider> _serviceProvider;
private DownstreamReRoute _reRoute;
private Response<ILoadBalancer> _loadBalancer;
private string _typeName;
public CookieStickySessionsCreatorTests()
{
_creator = new CookieStickySessionsCreator();
_serviceProvider = new Mock<IServiceDiscoveryProvider>();
}
[Fact]
public void should_return_instance_of_expected_load_balancer_type()
{
var reRoute = new DownstreamReRouteBuilder()
.WithLoadBalancerOptions(new LoadBalancerOptions("myType", "myKey", 1000))
.Build();
this.Given(x => x.GivenAReRoute(reRoute))
.When(x => x.WhenIGetTheLoadBalancer())
.Then(x => x.ThenTheLoadBalancerIsReturned<CookieStickySessions>())
.BDDfy();
}
[Fact]
public void should_return_expected_name()
{
this.When(x => x.WhenIGetTheLoadBalancerTypeName())
.Then(x => x.ThenTheLoadBalancerTypeIs("CookieStickySessions"))
.BDDfy();
}
private void GivenAReRoute(DownstreamReRoute reRoute)
{
_reRoute = reRoute;
}
private void WhenIGetTheLoadBalancer()
{
_loadBalancer = _creator.Create(_reRoute, _serviceProvider.Object);
}
private void WhenIGetTheLoadBalancerTypeName()
{
_typeName = _creator.Type;
}
private void ThenTheLoadBalancerIsReturned<T>()
where T : ILoadBalancer
{
_loadBalancer.Data.ShouldBeOfType<T>();
}
private void ThenTheLoadBalancerTypeIs(string type)
{
_typeName.ShouldBe(type);
}
}
}
namespace Ocelot.UnitTests.LoadBalancer
{
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.LoadBalancer.LoadBalancers;
using Ocelot.ServiceDiscovery.Providers;
using Ocelot.Responses;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
public class CookieStickySessionsCreatorTests
{
private readonly CookieStickySessionsCreator _creator;
private readonly Mock<IServiceDiscoveryProvider> _serviceProvider;
private DownstreamRoute _route;
private Response<ILoadBalancer> _loadBalancer;
private string _typeName;
public CookieStickySessionsCreatorTests()
{
_creator = new CookieStickySessionsCreator();
_serviceProvider = new Mock<IServiceDiscoveryProvider>();
}
[Fact]
public void should_return_instance_of_expected_load_balancer_type()
{
var route = new DownstreamRouteBuilder()
.WithLoadBalancerOptions(new LoadBalancerOptions("myType", "myKey", 1000))
.Build();
this.Given(x => x.GivenARoute(route))
.When(x => x.WhenIGetTheLoadBalancer())
.Then(x => x.ThenTheLoadBalancerIsReturned<CookieStickySessions>())
.BDDfy();
}
[Fact]
public void should_return_expected_name()
{
this.When(x => x.WhenIGetTheLoadBalancerTypeName())
.Then(x => x.ThenTheLoadBalancerTypeIs("CookieStickySessions"))
.BDDfy();
}
private void GivenARoute(DownstreamRoute route)
{
_route = route;
}
private void WhenIGetTheLoadBalancer()
{
_loadBalancer = _creator.Create(_route, _serviceProvider.Object);
}
private void WhenIGetTheLoadBalancerTypeName()
{
_typeName = _creator.Type;
}
private void ThenTheLoadBalancerIsReturned<T>()
where T : ILoadBalancer
{
_loadBalancer.Data.ShouldBeOfType<T>();
}
private void ThenTheLoadBalancerTypeIs(string type)
{
_typeName.ShouldBe(type);
}
}
}

View File

@ -19,16 +19,16 @@ namespace Ocelot.UnitTests.LoadBalancer
public class DelegateInvokingLoadBalancerCreatorTests
{
private DelegateInvokingLoadBalancerCreator<FakeLoadBalancer> _creator;
private Func<DownstreamReRoute, IServiceDiscoveryProvider, ILoadBalancer> _creatorFunc;
private Func<DownstreamRoute, IServiceDiscoveryProvider, ILoadBalancer> _creatorFunc;
private readonly Mock<IServiceDiscoveryProvider> _serviceProvider;
private DownstreamReRoute _reRoute;
private DownstreamRoute _route;
private Response<ILoadBalancer> _loadBalancer;
private string _typeName;
public DelegateInvokingLoadBalancerCreatorTests()
{
_creatorFunc = (reRoute, serviceDiscoveryProvider) =>
new FakeLoadBalancer(reRoute, serviceDiscoveryProvider);
_creatorFunc = (route, serviceDiscoveryProvider) =>
new FakeLoadBalancer(route, serviceDiscoveryProvider);
_creator = new DelegateInvokingLoadBalancerCreator<FakeLoadBalancer>(_creatorFunc);
_serviceProvider = new Mock<IServiceDiscoveryProvider>();
}
@ -44,10 +44,10 @@ namespace Ocelot.UnitTests.LoadBalancer
[Fact]
public void should_return_result_of_specified_creator_func()
{
var reRoute = new DownstreamReRouteBuilder()
var route = new DownstreamRouteBuilder()
.Build();
this.Given(x => x.GivenAReRoute(reRoute))
this.Given(x => x.GivenARoute(route))
.When(x => x.WhenIGetTheLoadBalancer())
.Then(x => x.ThenTheLoadBalancerIsReturned<FakeLoadBalancer>())
.BDDfy();
@ -56,10 +56,10 @@ namespace Ocelot.UnitTests.LoadBalancer
[Fact]
public void should_return_error()
{
var reRoute = new DownstreamReRouteBuilder()
var route = new DownstreamRouteBuilder()
.Build();
this.Given(x => x.GivenAReRoute(reRoute))
this.Given(x => x.GivenARoute(route))
.And(x => x.GivenTheCreatorFuncThrows())
.When(x => x.WhenIGetTheLoadBalancer())
.Then(x => x.ThenAnErrorIsReturned())
@ -68,7 +68,7 @@ namespace Ocelot.UnitTests.LoadBalancer
private void GivenTheCreatorFuncThrows()
{
_creatorFunc = (reRoute, serviceDiscoveryProvider) => throw new Exception();
_creatorFunc = (route, serviceDiscoveryProvider) => throw new Exception();
_creator = new DelegateInvokingLoadBalancerCreator<FakeLoadBalancer>(_creatorFunc);
}
@ -78,14 +78,14 @@ namespace Ocelot.UnitTests.LoadBalancer
_loadBalancer.IsError.ShouldBeTrue();
}
private void GivenAReRoute(DownstreamReRoute reRoute)
private void GivenARoute(DownstreamRoute route)
{
_reRoute = reRoute;
_route = route;
}
private void WhenIGetTheLoadBalancer()
{
_loadBalancer = _creator.Create(_reRoute, _serviceProvider.Object);
_loadBalancer = _creator.Create(_route, _serviceProvider.Object);
}
private void WhenIGetTheLoadBalancerTypeName()
@ -106,13 +106,13 @@ namespace Ocelot.UnitTests.LoadBalancer
private class FakeLoadBalancer : ILoadBalancer
{
public FakeLoadBalancer(DownstreamReRoute reRoute, IServiceDiscoveryProvider serviceDiscoveryProvider)
public FakeLoadBalancer(DownstreamRoute downstreamRoute, IServiceDiscoveryProvider serviceDiscoveryProvider)
{
ReRoute = reRoute;
DownstreamRoute = downstreamRoute;
ServiceDiscoveryProvider = serviceDiscoveryProvider;
}
public DownstreamReRoute ReRoute { get; }
public DownstreamRoute DownstreamRoute { get; }
public IServiceDiscoveryProvider ServiceDiscoveryProvider { get; }
public Task<Response<ServiceHostAndPort>> Lease(HttpContext httpContext)

View File

@ -1,74 +1,74 @@
namespace Ocelot.UnitTests.LoadBalancer
{
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.LoadBalancer.LoadBalancers;
using Ocelot.Responses;
using Ocelot.ServiceDiscovery.Providers;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
public class LeastConnectionCreatorTests
{
private readonly LeastConnectionCreator _creator;
private readonly Mock<IServiceDiscoveryProvider> _serviceProvider;
private DownstreamReRoute _reRoute;
private Response<ILoadBalancer> _loadBalancer;
private string _typeName;
public LeastConnectionCreatorTests()
{
_creator = new LeastConnectionCreator();
_serviceProvider = new Mock<IServiceDiscoveryProvider>();
}
[Fact]
public void should_return_instance_of_expected_load_balancer_type()
{
var reRoute = new DownstreamReRouteBuilder()
.WithServiceName("myService")
.Build();
this.Given(x => x.GivenAReRoute(reRoute))
.When(x => x.WhenIGetTheLoadBalancer())
.Then(x => x.ThenTheLoadBalancerIsReturned<LeastConnection>())
.BDDfy();
}
[Fact]
public void should_return_expected_name()
{
this.When(x => x.WhenIGetTheLoadBalancerTypeName())
.Then(x => x.ThenTheLoadBalancerTypeIs("LeastConnection"))
.BDDfy();
}
private void GivenAReRoute(DownstreamReRoute reRoute)
{
_reRoute = reRoute;
}
private void WhenIGetTheLoadBalancer()
{
_loadBalancer = _creator.Create(_reRoute, _serviceProvider.Object);
}
private void WhenIGetTheLoadBalancerTypeName()
{
_typeName = _creator.Type;
}
private void ThenTheLoadBalancerIsReturned<T>()
where T : ILoadBalancer
{
_loadBalancer.Data.ShouldBeOfType<T>();
}
private void ThenTheLoadBalancerTypeIs(string type)
{
_typeName.ShouldBe(type);
}
}
}
namespace Ocelot.UnitTests.LoadBalancer
{
using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder;
using Ocelot.LoadBalancer.LoadBalancers;
using Ocelot.Responses;
using Ocelot.ServiceDiscovery.Providers;
using Shouldly;
using TestStack.BDDfy;
using Xunit;
public class LeastConnectionCreatorTests
{
private readonly LeastConnectionCreator _creator;
private readonly Mock<IServiceDiscoveryProvider> _serviceProvider;
private DownstreamRoute _route;
private Response<ILoadBalancer> _loadBalancer;
private string _typeName;
public LeastConnectionCreatorTests()
{
_creator = new LeastConnectionCreator();
_serviceProvider = new Mock<IServiceDiscoveryProvider>();
}
[Fact]
public void should_return_instance_of_expected_load_balancer_type()
{
var route = new DownstreamRouteBuilder()
.WithServiceName("myService")
.Build();
this.Given(x => x.GivenARoute(route))
.When(x => x.WhenIGetTheLoadBalancer())
.Then(x => x.ThenTheLoadBalancerIsReturned<LeastConnection>())
.BDDfy();
}
[Fact]
public void should_return_expected_name()
{
this.When(x => x.WhenIGetTheLoadBalancerTypeName())
.Then(x => x.ThenTheLoadBalancerTypeIs("LeastConnection"))
.BDDfy();
}
private void GivenARoute(DownstreamRoute route)
{
_route = route;
}
private void WhenIGetTheLoadBalancer()
{
_loadBalancer = _creator.Create(_route, _serviceProvider.Object);
}
private void WhenIGetTheLoadBalancerTypeName()
{
_typeName = _creator.Type;
}
private void ThenTheLoadBalancerIsReturned<T>()
where T : ILoadBalancer
{
_loadBalancer.Data.ShouldBeOfType<T>();
}
private void ThenTheLoadBalancerTypeIs(string type)
{
_typeName.ShouldBe(type);
}
}
}

View File

@ -21,7 +21,7 @@ namespace Ocelot.UnitTests.LoadBalancer
public class LoadBalancerFactoryTests
{
private DownstreamReRoute _reRoute;
private DownstreamRoute _route;
private readonly LoadBalancerFactory _factory;
private Response<ILoadBalancer> _result;
private readonly Mock<IServiceDiscoveryProviderFactory> _serviceProviderFactory;
@ -46,11 +46,11 @@ namespace Ocelot.UnitTests.LoadBalancer
[Fact]
public void should_return_no_load_balancer_by_default()
{
var reRoute = new DownstreamReRouteBuilder()
var route = new DownstreamRouteBuilder()
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build();
this.Given(x => x.GivenAReRoute(reRoute))
this.Given(x => x.GivenARoute(route))
.And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build()))
.And(x => x.GivenTheServiceProviderFactoryReturns())
.When(x => x.WhenIGetTheLoadBalancer())
@ -61,12 +61,12 @@ namespace Ocelot.UnitTests.LoadBalancer
[Fact]
public void should_return_matching_load_balancer()
{
var reRoute = new DownstreamReRouteBuilder()
var route = new DownstreamRouteBuilder()
.WithLoadBalancerOptions(new LoadBalancerOptions("FakeLoadBalancerTwo", "", 0))
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build();
this.Given(x => x.GivenAReRoute(reRoute))
this.Given(x => x.GivenARoute(route))
.And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build()))
.And(x => x.GivenTheServiceProviderFactoryReturns())
.When(x => x.WhenIGetTheLoadBalancer())
@ -77,12 +77,12 @@ namespace Ocelot.UnitTests.LoadBalancer
[Fact]
public void should_return_error_response_if_cannot_find_load_balancer_creator()
{
var reRoute = new DownstreamReRouteBuilder()
var route = new DownstreamRouteBuilder()
.WithLoadBalancerOptions(new LoadBalancerOptions("DoesntExistLoadBalancer", "", 0))
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build();
this.Given(x => x.GivenAReRoute(reRoute))
this.Given(x => x.GivenARoute(route))
.And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build()))
.And(x => x.GivenTheServiceProviderFactoryReturns())
.When(x => x.WhenIGetTheLoadBalancer())
@ -94,12 +94,12 @@ namespace Ocelot.UnitTests.LoadBalancer
[Fact]
public void should_return_error_response_if_creator_errors()
{
var reRoute = new DownstreamReRouteBuilder()
var route = new DownstreamRouteBuilder()
.WithLoadBalancerOptions(new LoadBalancerOptions("BrokenLoadBalancer", "", 0))
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build();
this.Given(x => x.GivenAReRoute(reRoute))
this.Given(x => x.GivenARoute(route))
.And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build()))
.And(x => x.GivenTheServiceProviderFactoryReturns())
.When(x => x.WhenIGetTheLoadBalancer())
@ -110,12 +110,12 @@ namespace Ocelot.UnitTests.LoadBalancer
[Fact]
public void should_call_service_provider()
{
var reRoute = new DownstreamReRouteBuilder()
var route = new DownstreamRouteBuilder()
.WithLoadBalancerOptions(new LoadBalancerOptions("FakeLoadBalancerOne", "", 0))
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build();
this.Given(x => x.GivenAReRoute(reRoute))
this.Given(x => x.GivenARoute(route))
.And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build()))
.And(x => x.GivenTheServiceProviderFactoryReturns())
.When(x => x.WhenIGetTheLoadBalancer())
@ -126,12 +126,12 @@ namespace Ocelot.UnitTests.LoadBalancer
[Fact]
public void should_return_error_response_when_call_to_service_provider_fails()
{
var reRoute = new DownstreamReRouteBuilder()
var route = new DownstreamRouteBuilder()
.WithLoadBalancerOptions(new LoadBalancerOptions("FakeLoadBalancerOne", "", 0))
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build();
this.Given(x => x.GivenAReRoute(reRoute))
this.Given(x => x.GivenARoute(route))
.And(x => GivenAServiceProviderConfig(new ServiceProviderConfigurationBuilder().Build()))
.And(x => x.GivenTheServiceProviderFactoryFails())
.When(x => x.WhenIGetTheLoadBalancer())
@ -147,31 +147,31 @@ namespace Ocelot.UnitTests.LoadBalancer
private void GivenTheServiceProviderFactoryReturns()
{
_serviceProviderFactory
.Setup(x => x.Get(It.IsAny<ServiceProviderConfiguration>(), It.IsAny<DownstreamReRoute>()))
.Setup(x => x.Get(It.IsAny<ServiceProviderConfiguration>(), It.IsAny<DownstreamRoute>()))
.Returns(new OkResponse<IServiceDiscoveryProvider>(_serviceProvider.Object));
}
private void GivenTheServiceProviderFactoryFails()
{
_serviceProviderFactory
.Setup(x => x.Get(It.IsAny<ServiceProviderConfiguration>(), It.IsAny<DownstreamReRoute>()))
.Setup(x => x.Get(It.IsAny<ServiceProviderConfiguration>(), It.IsAny<DownstreamRoute>()))
.Returns(new ErrorResponse<IServiceDiscoveryProvider>(new CannotFindDataError("For tests")));
}
private void ThenTheServiceProviderIsCalledCorrectly()
{
_serviceProviderFactory
.Verify(x => x.Get(It.IsAny<ServiceProviderConfiguration>(), It.IsAny<DownstreamReRoute>()), Times.Once);
.Verify(x => x.Get(It.IsAny<ServiceProviderConfiguration>(), It.IsAny<DownstreamRoute>()), Times.Once);
}
private void GivenAReRoute(DownstreamReRoute reRoute)
private void GivenARoute(DownstreamRoute route)
{
_reRoute = reRoute;
_route = route;
}
private void WhenIGetTheLoadBalancer()
{
_result = _factory.Get(_reRoute, _serviceProviderConfig);
_result = _factory.Get(_route, _serviceProviderConfig);
}
private void ThenTheLoadBalancerIsReturned<T>()
@ -203,7 +203,7 @@ namespace Ocelot.UnitTests.LoadBalancer
Type = type;
}
public Response<ILoadBalancer> Create(DownstreamReRoute reRoute, IServiceDiscoveryProvider serviceProvider)
public Response<ILoadBalancer> Create(DownstreamRoute route, IServiceDiscoveryProvider serviceProvider)
{
return new OkResponse<ILoadBalancer>(new T());
}
@ -219,7 +219,7 @@ namespace Ocelot.UnitTests.LoadBalancer
Type = typeof(T).Name;
}
public Response<ILoadBalancer> Create(DownstreamReRoute reRoute, IServiceDiscoveryProvider serviceProvider)
public Response<ILoadBalancer> Create(DownstreamRoute route, IServiceDiscoveryProvider serviceProvider)
{
return new ErrorResponse<ILoadBalancer>(new ErrorInvokingLoadBalancerCreator(new Exception()));
}

View File

@ -17,7 +17,7 @@ namespace Ocelot.UnitTests.LoadBalancer
public class LoadBalancerHouseTests
{
private DownstreamReRoute _reRoute;
private DownstreamRoute _route;
private ILoadBalancer _loadBalancer;
private readonly LoadBalancerHouse _loadBalancerHouse;
private Response<ILoadBalancer> _getResult;
@ -34,11 +34,11 @@ namespace Ocelot.UnitTests.LoadBalancer
[Fact]
public void should_store_load_balancer_on_first_request()
{
var reRoute = new DownstreamReRouteBuilder()
var route = new DownstreamRouteBuilder()
.WithLoadBalancerKey("test")
.Build();
this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
this.Given(x => x.GivenThereIsALoadBalancer(route, new FakeLoadBalancer()))
.Then(x => x.ThenItIsAdded())
.BDDfy();
}
@ -46,13 +46,13 @@ namespace Ocelot.UnitTests.LoadBalancer
[Fact]
public void should_not_store_load_balancer_on_second_request()
{
var reRoute = new DownstreamReRouteBuilder()
var route = new DownstreamRouteBuilder()
.WithLoadBalancerOptions(new LoadBalancerOptions("FakeLoadBalancer", "", 0))
.WithLoadBalancerKey("test")
.Build();
this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
.When(x => x.WhenWeGetTheLoadBalancer(reRoute))
this.Given(x => x.GivenThereIsALoadBalancer(route, new FakeLoadBalancer()))
.When(x => x.WhenWeGetTheLoadBalancer(route))
.Then(x => x.ThenItIsReturned())
.BDDfy();
}
@ -60,21 +60,21 @@ namespace Ocelot.UnitTests.LoadBalancer
[Fact]
public void should_store_load_balancers_by_key()
{
var reRoute = new DownstreamReRouteBuilder()
var route = new DownstreamRouteBuilder()
.WithLoadBalancerOptions(new LoadBalancerOptions("FakeLoadBalancer", "", 0))
.WithLoadBalancerKey("test")
.Build();
var reRouteTwo = new DownstreamReRouteBuilder()
var routeTwo = new DownstreamRouteBuilder()
.WithLoadBalancerOptions(new LoadBalancerOptions("FakeRoundRobinLoadBalancer", "", 0))
.WithLoadBalancerKey("testtwo")
.Build();
this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
.And(x => x.GivenThereIsALoadBalancer(reRouteTwo, new FakeRoundRobinLoadBalancer()))
.When(x => x.WhenWeGetTheLoadBalancer(reRoute))
this.Given(x => x.GivenThereIsALoadBalancer(route, new FakeLoadBalancer()))
.And(x => x.GivenThereIsALoadBalancer(routeTwo, new FakeRoundRobinLoadBalancer()))
.When(x => x.WhenWeGetTheLoadBalancer(route))
.Then(x => x.ThenTheLoadBalancerIs<FakeLoadBalancer>())
.When(x => x.WhenWeGetTheLoadBalancer(reRouteTwo))
.When(x => x.WhenWeGetTheLoadBalancer(routeTwo))
.Then(x => x.ThenTheLoadBalancerIs<FakeRoundRobinLoadBalancer>())
.BDDfy();
}
@ -82,39 +82,39 @@ namespace Ocelot.UnitTests.LoadBalancer
[Fact]
public void should_return_error_if_exception()
{
var reRoute = new DownstreamReRouteBuilder().Build();
var route = new DownstreamRouteBuilder().Build();
this.When(x => x.WhenWeGetTheLoadBalancer(reRoute))
this.When(x => x.WhenWeGetTheLoadBalancer(route))
.Then(x => x.ThenAnErrorIsReturned())
.BDDfy();
}
[Fact]
public void should_get_new_load_balancer_if_reroute_load_balancer_has_changed()
public void should_get_new_load_balancer_if_route_load_balancer_has_changed()
{
var reRoute = new DownstreamReRouteBuilder()
var route = new DownstreamRouteBuilder()
.WithLoadBalancerOptions(new LoadBalancerOptions("FakeLoadBalancer", "", 0))
.WithLoadBalancerKey("test")
.Build();
var reRouteTwo = new DownstreamReRouteBuilder()
var routeTwo = new DownstreamRouteBuilder()
.WithLoadBalancerOptions(new LoadBalancerOptions("LeastConnection", "", 0))
.WithLoadBalancerKey("test")
.Build();
this.Given(x => x.GivenThereIsALoadBalancer(reRoute, new FakeLoadBalancer()))
.When(x => x.WhenWeGetTheLoadBalancer(reRoute))
this.Given(x => x.GivenThereIsALoadBalancer(route, new FakeLoadBalancer()))
.When(x => x.WhenWeGetTheLoadBalancer(route))
.Then(x => x.ThenTheLoadBalancerIs<FakeLoadBalancer>())
.When(x => x.WhenIGetTheReRouteWithTheSameKeyButDifferentLoadBalancer(reRouteTwo))
.When(x => x.WhenIGetTheRouteWithTheSameKeyButDifferentLoadBalancer(routeTwo))
.Then(x => x.ThenTheLoadBalancerIs<LeastConnection>())
.BDDfy();
}
private void WhenIGetTheReRouteWithTheSameKeyButDifferentLoadBalancer(DownstreamReRoute reRoute)
private void WhenIGetTheRouteWithTheSameKeyButDifferentLoadBalancer(DownstreamRoute route)
{
_reRoute = reRoute;
_factory.Setup(x => x.Get(_reRoute, _serviceProviderConfig)).Returns(new OkResponse<ILoadBalancer>(new LeastConnection(null, null)));
_getResult = _loadBalancerHouse.Get(_reRoute, _serviceProviderConfig);
_route = route;
_factory.Setup(x => x.Get(_route, _serviceProviderConfig)).Returns(new OkResponse<ILoadBalancer>(new LeastConnection(null, null)));
_getResult = _loadBalancerHouse.Get(_route, _serviceProviderConfig);
}
private void ThenAnErrorIsReturned()
@ -133,26 +133,26 @@ namespace Ocelot.UnitTests.LoadBalancer
_getResult.IsError.ShouldBe(false);
_getResult.ShouldBeOfType<OkResponse<ILoadBalancer>>();
_getResult.Data.ShouldBe(_loadBalancer);
_factory.Verify(x => x.Get(_reRoute, _serviceProviderConfig), Times.Once);
_factory.Verify(x => x.Get(_route, _serviceProviderConfig), Times.Once);
}
private void GivenThereIsALoadBalancer(DownstreamReRoute reRoute, ILoadBalancer loadBalancer)
private void GivenThereIsALoadBalancer(DownstreamRoute route, ILoadBalancer loadBalancer)
{
_reRoute = reRoute;
_route = route;
_loadBalancer = loadBalancer;
_factory.Setup(x => x.Get(_reRoute, _serviceProviderConfig)).Returns(new OkResponse<ILoadBalancer>(loadBalancer));
_getResult = _loadBalancerHouse.Get(reRoute, _serviceProviderConfig);
_factory.Setup(x => x.Get(_route, _serviceProviderConfig)).Returns(new OkResponse<ILoadBalancer>(loadBalancer));
_getResult = _loadBalancerHouse.Get(route, _serviceProviderConfig);
}
private void WhenWeGetTheLoadBalancer(DownstreamReRoute reRoute)
private void WhenWeGetTheLoadBalancer(DownstreamRoute route)
{
_getResult = _loadBalancerHouse.Get(reRoute, _serviceProviderConfig);
_getResult = _loadBalancerHouse.Get(route, _serviceProviderConfig);
}
private void ThenItIsReturned()
{
_getResult.Data.ShouldBe(_loadBalancer);
_factory.Verify(x => x.Get(_reRoute, _serviceProviderConfig), Times.Once);
_factory.Verify(x => x.Get(_route, _serviceProviderConfig), Times.Once);
}
private class FakeLoadBalancer : ILoadBalancer

View File

@ -56,7 +56,7 @@ namespace Ocelot.UnitTests.LoadBalancer
[Fact]
public void should_call_scoped_data_repository_correctly()
{
var downstreamRoute = new DownstreamReRouteBuilder()
var downstreamRoute = new DownstreamRouteBuilder()
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build();
@ -76,7 +76,7 @@ namespace Ocelot.UnitTests.LoadBalancer
[Fact]
public void should_set_pipeline_error_if_cannot_get_load_balancer()
{
var downstreamRoute = new DownstreamReRouteBuilder()
var downstreamRoute = new DownstreamRouteBuilder()
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build();
@ -95,7 +95,7 @@ namespace Ocelot.UnitTests.LoadBalancer
[Fact]
public void should_set_pipeline_error_if_cannot_get_least()
{
var downstreamRoute = new DownstreamReRouteBuilder()
var downstreamRoute = new DownstreamRouteBuilder()
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build();
@ -115,7 +115,7 @@ namespace Ocelot.UnitTests.LoadBalancer
[Fact]
public void should_set_scheme()
{
var downstreamRoute = new DownstreamReRouteBuilder()
var downstreamRoute = new DownstreamRouteBuilder()
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build();
@ -174,16 +174,16 @@ namespace Ocelot.UnitTests.LoadBalancer
.ReturnsAsync(new OkResponse<ServiceHostAndPort>(_hostAndPort));
}
private void GivenTheDownStreamRouteIs(DownstreamReRoute downstreamRoute, List<Ocelot.DownstreamRouteFinder.UrlMatcher.PlaceholderNameAndValue> placeholder)
private void GivenTheDownStreamRouteIs(DownstreamRoute downstreamRoute, List<Ocelot.DownstreamRouteFinder.UrlMatcher.PlaceholderNameAndValue> placeholder)
{
_httpContext.Items.UpsertTemplatePlaceholderNameAndValues(placeholder);
_httpContext.Items.UpsertDownstreamReRoute(downstreamRoute);
_httpContext.Items.UpsertDownstreamRoute(downstreamRoute);
}
private void GivenTheLoadBalancerHouseReturns()
{
_loadBalancerHouse
.Setup(x => x.Get(It.IsAny<DownstreamReRoute>(), It.IsAny<ServiceProviderConfiguration>()))
.Setup(x => x.Get(It.IsAny<DownstreamRoute>(), It.IsAny<ServiceProviderConfiguration>()))
.Returns(new OkResponse<ILoadBalancer>(_loadBalancer.Object));
}
@ -195,7 +195,7 @@ namespace Ocelot.UnitTests.LoadBalancer
});
_loadBalancerHouse
.Setup(x => x.Get(It.IsAny<DownstreamReRoute>(), It.IsAny<ServiceProviderConfiguration>()))
.Setup(x => x.Get(It.IsAny<DownstreamRoute>(), It.IsAny<ServiceProviderConfiguration>()))
.Returns(_getLoadBalancerHouseError);
}

Some files were not shown because too many files have changed in this diff Show More