Skip to content

Commit

Permalink
decided to stick a basic cache in for downstream route creator, can m…
Browse files Browse the repository at this point in the history
…ake fancy if required (#359)
  • Loading branch information
TomPallister authored May 15, 2018
1 parent 061a90f commit a55c75e
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 2 deletions.
27 changes: 25 additions & 2 deletions src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteCreator.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace Ocelot.DownstreamRouteFinder.Finder
{
using System.Collections.Concurrent;
using System.Collections.Generic;
using Configuration;
using Configuration.Builder;
Expand All @@ -12,14 +13,16 @@
public class DownstreamRouteCreator : IDownstreamRouteProvider
{
private readonly IQoSOptionsCreator _qoSOptionsCreator;
private readonly ConcurrentDictionary<string, OkResponse<DownstreamRoute>> _cache;

public DownstreamRouteCreator(IQoSOptionsCreator qoSOptionsCreator)
{
_qoSOptionsCreator = qoSOptionsCreator;
_cache = new ConcurrentDictionary<string, OkResponse<DownstreamRoute>>();
}

public Response<DownstreamRoute> Get(string upstreamUrlPath, string upstreamHttpMethod, IInternalConfiguration configuration, string upstreamHost)
{
{
var serviceName = GetServiceName(upstreamUrlPath);

var downstreamPath = GetDownstreamPath(upstreamUrlPath);
Expand All @@ -33,6 +36,11 @@ public Response<DownstreamRoute> Get(string upstreamUrlPath, string upstreamHttp

var loadBalancerKey = CreateLoadBalancerKey(downstreamPathForKeys, upstreamHttpMethod, configuration.LoadBalancerOptions);

if(_cache.TryGetValue(loadBalancerKey, out var downstreamRoute))
{
return downstreamRoute;
}

var qosOptions = _qoSOptionsCreator.Create(configuration.QoSOptions, downstreamPathForKeys, new []{ upstreamHttpMethod });

var downstreamReRoute = new DownstreamReRouteBuilder()
Expand All @@ -51,7 +59,11 @@ public Response<DownstreamRoute> Get(string upstreamUrlPath, string upstreamHttp
.WithUpstreamHttpMethod(new List<string>(){ upstreamHttpMethod })
.Build();

return new OkResponse<DownstreamRoute>(new DownstreamRoute(new List<PlaceholderNameAndValue>(), reRoute));
downstreamRoute = new OkResponse<DownstreamRoute>(new DownstreamRoute(new List<PlaceholderNameAndValue>(), reRoute));

_cache.AddOrUpdate(loadBalancerKey, downstreamRoute, (x, y) => downstreamRoute);

return downstreamRoute;
}

private static string RemoveQueryString(string downstreamPath)
Expand All @@ -67,12 +79,23 @@ private static bool HasQueryString(string downstreamPath)

private static string GetDownstreamPath(string upstreamUrlPath)
{
if(upstreamUrlPath.IndexOf('/', 1) == -1)
{
return "/";
}

return upstreamUrlPath
.Substring(upstreamUrlPath.IndexOf('/', 1));
}

private static string GetServiceName(string upstreamUrlPath)
{
if(upstreamUrlPath.IndexOf('/', 1) == -1)
{
return upstreamUrlPath
.Substring(1);
}

return upstreamUrlPath
.Substring(1, upstreamUrlPath.IndexOf('/', 1))
.TrimEnd('/');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

namespace Ocelot.UnitTests.DownstreamRouteFinder
{
using System;
using Moq;
using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Creator;
Expand All @@ -26,6 +27,7 @@ public class DownstreamRouteCreatorTests
private string _upstreamHttpMethod;
private IInternalConfiguration _configuration;
private Mock<IQoSOptionsCreator> _qosOptionsCreator;
private Response<DownstreamRoute> _resultTwo;

public DownstreamRouteCreatorTests()
{
Expand All @@ -50,6 +52,32 @@ public void should_create_downstream_route()
.BDDfy();
}

[Fact]
public void should_cache_downstream_route()
{
var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions);

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);

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()
{
Expand All @@ -62,6 +90,30 @@ public void should_create_downstream_route_with_no_path()
.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);

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);

this.Given(_ => GivenTheConfiguration(configuration, upstreamUrlPath))
.When(_ => WhenICreate())
.Then(_ => ThenThePathDoesNotHaveTrailingSlash())
.BDDfy();
}

[Fact]
public void should_create_downstream_route_and_remove_query_string()
{
Expand Down Expand Up @@ -143,6 +195,13 @@ private void ThenTheDownstreamPathIsForwardSlash()
_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");
Expand Down Expand Up @@ -190,5 +249,20 @@ private void WhenICreate()
{
_result = _creator.Get(_upstreamUrlPath, _upstreamHttpMethod, _configuration, _upstreamHost);
}

private void WhenICreateAgain()
{
_resultTwo = _creator.Get(_upstreamUrlPath, _upstreamHttpMethod, _configuration, _upstreamHost);
}

private void ThenTheDownstreamRoutesAreTheSameReference()
{
_result.ShouldBe(_resultTwo);
}

private void ThenTheDownstreamRoutesAreTheNotSameReference()
{
_result.ShouldNotBe(_resultTwo);
}
}
}

0 comments on commit a55c75e

Please sign in to comment.