mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-04-22 18:22:49 +08:00
* Add Advanced Aggregation Feature * fix overwrite error * distinct data for better performance * remove constructor parameter * fix tests issue * fix tests * fix tests issue * Add UnitTest and AcceptanceTest * fix responseKeys typo * Update SimpleJsonResponseAggregator.cs * change port
This commit is contained in:
parent
44dccf1fce
commit
faaabbe7a7
@ -4,6 +4,7 @@
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using Ocelot.Values;
|
using Ocelot.Values;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Ocelot.Configuration.File;
|
||||||
|
|
||||||
public class ReRouteBuilder
|
public class ReRouteBuilder
|
||||||
{
|
{
|
||||||
@ -11,11 +12,13 @@
|
|||||||
private List<HttpMethod> _upstreamHttpMethod;
|
private List<HttpMethod> _upstreamHttpMethod;
|
||||||
private string _upstreamHost;
|
private string _upstreamHost;
|
||||||
private List<DownstreamReRoute> _downstreamReRoutes;
|
private List<DownstreamReRoute> _downstreamReRoutes;
|
||||||
|
private List<AggregateReRouteConfig> _downstreamReRoutesConfig;
|
||||||
private string _aggregator;
|
private string _aggregator;
|
||||||
|
|
||||||
public ReRouteBuilder()
|
public ReRouteBuilder()
|
||||||
{
|
{
|
||||||
_downstreamReRoutes = new List<DownstreamReRoute>();
|
_downstreamReRoutes = new List<DownstreamReRoute>();
|
||||||
|
_downstreamReRoutesConfig = new List<AggregateReRouteConfig>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReRouteBuilder WithDownstreamReRoute(DownstreamReRoute value)
|
public ReRouteBuilder WithDownstreamReRoute(DownstreamReRoute value)
|
||||||
@ -48,6 +51,12 @@
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ReRouteBuilder WithAggregateReRouteConfig(List<AggregateReRouteConfig> aggregateReRouteConfigs)
|
||||||
|
{
|
||||||
|
_downstreamReRoutesConfig = aggregateReRouteConfigs;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public ReRouteBuilder WithAggregator(string aggregator)
|
public ReRouteBuilder WithAggregator(string aggregator)
|
||||||
{
|
{
|
||||||
_aggregator = aggregator;
|
_aggregator = aggregator;
|
||||||
@ -58,6 +67,7 @@
|
|||||||
{
|
{
|
||||||
return new ReRoute(
|
return new ReRoute(
|
||||||
_downstreamReRoutes,
|
_downstreamReRoutes,
|
||||||
|
_downstreamReRoutesConfig,
|
||||||
_upstreamHttpMethod,
|
_upstreamHttpMethod,
|
||||||
_upstreamTemplatePattern,
|
_upstreamTemplatePattern,
|
||||||
_upstreamHost,
|
_upstreamHost,
|
||||||
|
@ -24,22 +24,27 @@ namespace Ocelot.Configuration.Creator
|
|||||||
|
|
||||||
private ReRoute SetUpAggregateReRoute(IEnumerable<ReRoute> reRoutes, FileAggregateReRoute aggregateReRoute, FileGlobalConfiguration globalConfiguration)
|
private ReRoute SetUpAggregateReRoute(IEnumerable<ReRoute> reRoutes, FileAggregateReRoute aggregateReRoute, FileGlobalConfiguration globalConfiguration)
|
||||||
{
|
{
|
||||||
var applicableReRoutes = reRoutes
|
var applicableReRoutes = new List<DownstreamReRoute>();
|
||||||
.SelectMany(x => x.DownstreamReRoute)
|
var allReRoutes = reRoutes.SelectMany(x => x.DownstreamReRoute);
|
||||||
.Where(r => aggregateReRoute.ReRouteKeys.Contains(r.Key))
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
if (applicableReRoutes.Count != aggregateReRoute.ReRouteKeys.Count)
|
foreach (var reRouteKey in aggregateReRoute.ReRouteKeys)
|
||||||
|
{
|
||||||
|
var selec = allReRoutes.FirstOrDefault(q => q.Key == reRouteKey);
|
||||||
|
if (selec == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applicableReRoutes.Add(selec);
|
||||||
|
}
|
||||||
|
|
||||||
var upstreamTemplatePattern = _creator.Create(aggregateReRoute);
|
var upstreamTemplatePattern = _creator.Create(aggregateReRoute);
|
||||||
|
|
||||||
var reRoute = new ReRouteBuilder()
|
var reRoute = new ReRouteBuilder()
|
||||||
.WithUpstreamHttpMethod(aggregateReRoute.UpstreamHttpMethod)
|
.WithUpstreamHttpMethod(aggregateReRoute.UpstreamHttpMethod)
|
||||||
.WithUpstreamPathTemplate(upstreamTemplatePattern)
|
.WithUpstreamPathTemplate(upstreamTemplatePattern)
|
||||||
.WithDownstreamReRoutes(applicableReRoutes)
|
.WithDownstreamReRoutes(applicableReRoutes)
|
||||||
|
.WithAggregateReRouteConfig(aggregateReRoute.ReRouteKeysConfig)
|
||||||
.WithUpstreamHost(aggregateReRoute.UpstreamHost)
|
.WithUpstreamHost(aggregateReRoute.UpstreamHost)
|
||||||
.WithAggregator(aggregateReRoute.Aggregator)
|
.WithAggregator(aggregateReRoute.Aggregator)
|
||||||
.Build();
|
.Build();
|
||||||
|
13
src/Ocelot/Configuration/File/AggregateReRouteConfig.cs
Normal file
13
src/Ocelot/Configuration/File/AggregateReRouteConfig.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Ocelot.Configuration.File
|
||||||
|
{
|
||||||
|
public class AggregateReRouteConfig
|
||||||
|
{
|
||||||
|
public string ReRouteKey { get; set; }
|
||||||
|
public string Parameter { get; set; }
|
||||||
|
public string JsonPath { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ namespace Ocelot.Configuration.File
|
|||||||
public class FileAggregateReRoute : IReRoute
|
public class FileAggregateReRoute : IReRoute
|
||||||
{
|
{
|
||||||
public List<string> ReRouteKeys { get;set; }
|
public List<string> ReRouteKeys { get;set; }
|
||||||
|
public List<AggregateReRouteConfig> ReRouteKeysConfig { get;set; }
|
||||||
public string UpstreamPathTemplate { get;set; }
|
public string UpstreamPathTemplate { get;set; }
|
||||||
public string UpstreamHost { get; set; }
|
public string UpstreamHost { get; set; }
|
||||||
public bool ReRouteIsCaseSensitive { get; set; }
|
public bool ReRouteIsCaseSensitive { get; set; }
|
||||||
|
@ -2,11 +2,13 @@
|
|||||||
{
|
{
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using Ocelot.Configuration.File;
|
||||||
using Ocelot.Values;
|
using Ocelot.Values;
|
||||||
|
|
||||||
public class ReRoute
|
public class ReRoute
|
||||||
{
|
{
|
||||||
public ReRoute(List<DownstreamReRoute> downstreamReRoute,
|
public ReRoute(List<DownstreamReRoute> downstreamReRoute,
|
||||||
|
List<AggregateReRouteConfig> downstreamReRouteConfig,
|
||||||
List<HttpMethod> upstreamHttpMethod,
|
List<HttpMethod> upstreamHttpMethod,
|
||||||
UpstreamPathTemplate upstreamTemplatePattern,
|
UpstreamPathTemplate upstreamTemplatePattern,
|
||||||
string upstreamHost,
|
string upstreamHost,
|
||||||
@ -14,6 +16,7 @@
|
|||||||
{
|
{
|
||||||
UpstreamHost = upstreamHost;
|
UpstreamHost = upstreamHost;
|
||||||
DownstreamReRoute = downstreamReRoute;
|
DownstreamReRoute = downstreamReRoute;
|
||||||
|
DownstreamReRouteConfig = downstreamReRouteConfig;
|
||||||
UpstreamHttpMethod = upstreamHttpMethod;
|
UpstreamHttpMethod = upstreamHttpMethod;
|
||||||
UpstreamTemplatePattern = upstreamTemplatePattern;
|
UpstreamTemplatePattern = upstreamTemplatePattern;
|
||||||
Aggregator = aggregator;
|
Aggregator = aggregator;
|
||||||
@ -23,6 +26,7 @@
|
|||||||
public List<HttpMethod> UpstreamHttpMethod { get; private set; }
|
public List<HttpMethod> UpstreamHttpMethod { get; private set; }
|
||||||
public string UpstreamHost { get; private set; }
|
public string UpstreamHost { get; private set; }
|
||||||
public List<DownstreamReRoute> DownstreamReRoute { get; private set; }
|
public List<DownstreamReRoute> DownstreamReRoute { get; private set; }
|
||||||
|
public List<AggregateReRouteConfig> DownstreamReRouteConfig { get; private set; }
|
||||||
public string Aggregator {get; private set;}
|
public string Aggregator {get; private set;}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,12 @@ namespace Ocelot.Middleware.Multiplexer
|
|||||||
public class InMemoryResponseAggregatorFactory : IResponseAggregatorFactory
|
public class InMemoryResponseAggregatorFactory : IResponseAggregatorFactory
|
||||||
{
|
{
|
||||||
private readonly UserDefinedResponseAggregator _userDefined;
|
private readonly UserDefinedResponseAggregator _userDefined;
|
||||||
private readonly SimpleJsonResponseAggregator _simple;
|
private readonly IResponseAggregator _simple;
|
||||||
|
|
||||||
public InMemoryResponseAggregatorFactory(IDefinedAggregatorProvider provider)
|
public InMemoryResponseAggregatorFactory(IDefinedAggregatorProvider provider, IResponseAggregator responseAggregator)
|
||||||
{
|
{
|
||||||
_userDefined = new UserDefinedResponseAggregator(provider);
|
_userDefined = new UserDefinedResponseAggregator(provider);
|
||||||
_simple = new SimpleJsonResponseAggregator();
|
_simple = responseAggregator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IResponseAggregator Get(ReRoute reRoute)
|
public IResponseAggregator Get(ReRoute reRoute)
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
|
using Ocelot.DownstreamRouteFinder.UrlMatcher;
|
||||||
|
|
||||||
namespace Ocelot.Middleware.Multiplexer
|
namespace Ocelot.Middleware.Multiplexer
|
||||||
{
|
{
|
||||||
@ -15,6 +17,9 @@ namespace Ocelot.Middleware.Multiplexer
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async Task Multiplex(DownstreamContext context, ReRoute reRoute, OcelotRequestDelegate next)
|
public async Task Multiplex(DownstreamContext context, ReRoute reRoute, OcelotRequestDelegate next)
|
||||||
|
{
|
||||||
|
var reRouteKeysConfigs = reRoute.DownstreamReRouteConfig;
|
||||||
|
if (reRouteKeysConfigs == null || !reRouteKeysConfigs.Any())
|
||||||
{
|
{
|
||||||
var tasks = new Task<DownstreamContext>[reRoute.DownstreamReRoute.Count];
|
var tasks = new Task<DownstreamContext>[reRoute.DownstreamReRoute.Count];
|
||||||
|
|
||||||
@ -42,6 +47,77 @@ namespace Ocelot.Middleware.Multiplexer
|
|||||||
|
|
||||||
await Map(reRoute, context, contexts);
|
await Map(reRoute, context, contexts);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var downstreamContextMain = new DownstreamContext(context.HttpContext)
|
||||||
|
{
|
||||||
|
TemplatePlaceholderNameAndValues = context.TemplatePlaceholderNameAndValues,
|
||||||
|
Configuration = context.Configuration,
|
||||||
|
DownstreamReRoute = reRoute.DownstreamReRoute[0],
|
||||||
|
};
|
||||||
|
var mainResponse = await Fire(downstreamContextMain, next);
|
||||||
|
|
||||||
|
if (reRoute.DownstreamReRoute.Count == 1)
|
||||||
|
{
|
||||||
|
MapNotAggregate(context, new List<DownstreamContext>() { mainResponse });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tasks = new List<Task<DownstreamContext>>();
|
||||||
|
if (mainResponse.DownstreamResponse == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var content = await mainResponse.DownstreamResponse.Content.ReadAsStringAsync();
|
||||||
|
var jObject = Newtonsoft.Json.Linq.JToken.Parse(content);
|
||||||
|
|
||||||
|
for (var i = 1; i < reRoute.DownstreamReRoute.Count; i++)
|
||||||
|
{
|
||||||
|
var templatePlaceholderNameAndValues = context.TemplatePlaceholderNameAndValues;
|
||||||
|
var downstreamReRoute = reRoute.DownstreamReRoute[i];
|
||||||
|
var matchAdvancedAgg = reRouteKeysConfigs.FirstOrDefault(q => q.ReRouteKey == downstreamReRoute.Key);
|
||||||
|
if (matchAdvancedAgg != null)
|
||||||
|
{
|
||||||
|
var values = jObject.SelectTokens(matchAdvancedAgg.JsonPath).Select(s => s.ToString()).Distinct().ToList();
|
||||||
|
|
||||||
|
foreach (var value in values)
|
||||||
|
{
|
||||||
|
var downstreamContext = new DownstreamContext(context.HttpContext)
|
||||||
|
{
|
||||||
|
TemplatePlaceholderNameAndValues = new List<PlaceholderNameAndValue>(templatePlaceholderNameAndValues),
|
||||||
|
Configuration = context.Configuration,
|
||||||
|
DownstreamReRoute = downstreamReRoute,
|
||||||
|
};
|
||||||
|
downstreamContext.TemplatePlaceholderNameAndValues.Add(new PlaceholderNameAndValue("{" + matchAdvancedAgg.Parameter + "}", value.ToString()));
|
||||||
|
tasks.Add(Fire(downstreamContext, next));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var downstreamContext = new DownstreamContext(context.HttpContext)
|
||||||
|
{
|
||||||
|
TemplatePlaceholderNameAndValues = new List<PlaceholderNameAndValue>(templatePlaceholderNameAndValues),
|
||||||
|
Configuration = context.Configuration,
|
||||||
|
DownstreamReRoute = downstreamReRoute,
|
||||||
|
};
|
||||||
|
tasks.Add(Fire(downstreamContext, next));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.WhenAll(tasks);
|
||||||
|
|
||||||
|
var contexts = new List<DownstreamContext>() { mainResponse };
|
||||||
|
|
||||||
|
foreach (var task in tasks)
|
||||||
|
{
|
||||||
|
var finished = await task;
|
||||||
|
contexts.Add(finished);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Map(reRoute, context, contexts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task Map(ReRoute reRoute, DownstreamContext context, List<DownstreamContext> contexts)
|
private async Task Map(ReRoute reRoute, DownstreamContext context, List<DownstreamContext> contexts)
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
@ -21,19 +22,54 @@ namespace Ocelot.Middleware.Multiplexer
|
|||||||
|
|
||||||
contentBuilder.Append("{");
|
contentBuilder.Append("{");
|
||||||
|
|
||||||
for (var i = 0; i < downstreamContexts.Count; i++)
|
var responseKeys = downstreamContexts.Select(s => s.DownstreamReRoute.Key).Distinct().ToList();
|
||||||
|
|
||||||
|
for (var k = 0; k < responseKeys.Count; k++)
|
||||||
{
|
{
|
||||||
if (downstreamContexts[i].IsError)
|
var contexts = downstreamContexts.Where(w => w.DownstreamReRoute.Key == responseKeys[k]).ToList();
|
||||||
|
if (contexts.Count == 1)
|
||||||
{
|
{
|
||||||
MapAggregateError(originalContext, downstreamContexts, i);
|
if (contexts[0].IsError)
|
||||||
|
{
|
||||||
|
MapAggregateError(originalContext, contexts[0]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var content = await downstreamContexts[i].DownstreamResponse.Content.ReadAsStringAsync();
|
var content = await contexts[0].DownstreamResponse.Content.ReadAsStringAsync();
|
||||||
|
contentBuilder.Append($"\"{responseKeys[k]}\":{content}");
|
||||||
|
|
||||||
contentBuilder.Append($"\"{downstreamContexts[i].DownstreamReRoute.Key}\":{content}");
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
contentBuilder.Append($"\"{responseKeys[k]}\":");
|
||||||
|
contentBuilder.Append("[");
|
||||||
|
|
||||||
if (i + 1 < downstreamContexts.Count)
|
for (var i = 0; i < contexts.Count; i++)
|
||||||
|
{
|
||||||
|
if (contexts[i].IsError)
|
||||||
|
{
|
||||||
|
MapAggregateError(originalContext, contexts[i]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var content = await contexts[i].DownstreamResponse.Content.ReadAsStringAsync();
|
||||||
|
if (string.IsNullOrWhiteSpace(content))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
contentBuilder.Append($"{content}");
|
||||||
|
|
||||||
|
if (i + 1 < contexts.Count)
|
||||||
|
{
|
||||||
|
contentBuilder.Append(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contentBuilder.Append("]");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k + 1 < responseKeys.Count)
|
||||||
{
|
{
|
||||||
contentBuilder.Append(",");
|
contentBuilder.Append(",");
|
||||||
}
|
}
|
||||||
@ -43,16 +79,16 @@ namespace Ocelot.Middleware.Multiplexer
|
|||||||
|
|
||||||
var stringContent = new StringContent(contentBuilder.ToString())
|
var stringContent = new StringContent(contentBuilder.ToString())
|
||||||
{
|
{
|
||||||
Headers = {ContentType = new MediaTypeHeaderValue("application/json")}
|
Headers = { ContentType = new MediaTypeHeaderValue("application/json") }
|
||||||
};
|
};
|
||||||
|
|
||||||
originalContext.DownstreamResponse = new DownstreamResponse(stringContent, HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "cannot return from aggregate..which reason phrase would you use?");
|
originalContext.DownstreamResponse = new DownstreamResponse(stringContent, HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "cannot return from aggregate..which reason phrase would you use?");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void MapAggregateError(DownstreamContext originalContext, List<DownstreamContext> downstreamContexts, int i)
|
private static void MapAggregateError(DownstreamContext originalContext, DownstreamContext downstreamContext)
|
||||||
{
|
{
|
||||||
originalContext.Errors.AddRange(downstreamContexts[i].Errors);
|
originalContext.Errors.AddRange(downstreamContext.Errors);
|
||||||
originalContext.DownstreamResponse = downstreamContexts[i].DownstreamResponse;
|
originalContext.DownstreamResponse = downstreamContext.DownstreamResponse;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,6 +141,100 @@ namespace Ocelot.AcceptanceTests
|
|||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_return_response_200_with_advanced_aggregate_configs()
|
||||||
|
{
|
||||||
|
var configuration = new FileConfiguration
|
||||||
|
{
|
||||||
|
ReRoutes = new List<FileReRoute>
|
||||||
|
{
|
||||||
|
new FileReRoute
|
||||||
|
{
|
||||||
|
DownstreamPathTemplate = "/",
|
||||||
|
DownstreamScheme = "http",
|
||||||
|
DownstreamHostAndPorts = new List<FileHostAndPort>
|
||||||
|
{
|
||||||
|
new FileHostAndPort
|
||||||
|
{
|
||||||
|
Host = "localhost",
|
||||||
|
Port = 51889,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
UpstreamPathTemplate = "/Comments",
|
||||||
|
UpstreamHttpMethod = new List<string> { "Get" },
|
||||||
|
Key = "Comments"
|
||||||
|
},
|
||||||
|
new FileReRoute
|
||||||
|
{
|
||||||
|
DownstreamPathTemplate = "/users/{userId}",
|
||||||
|
DownstreamScheme = "http",
|
||||||
|
DownstreamHostAndPorts = new List<FileHostAndPort>
|
||||||
|
{
|
||||||
|
new FileHostAndPort
|
||||||
|
{
|
||||||
|
Host = "localhost",
|
||||||
|
Port = 51890,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
UpstreamPathTemplate = "/UserDetails",
|
||||||
|
UpstreamHttpMethod = new List<string> { "Get" },
|
||||||
|
Key = "UserDetails"
|
||||||
|
},
|
||||||
|
new FileReRoute
|
||||||
|
{
|
||||||
|
DownstreamPathTemplate = "/posts/{postId}",
|
||||||
|
DownstreamScheme = "http",
|
||||||
|
DownstreamHostAndPorts = new List<FileHostAndPort>
|
||||||
|
{
|
||||||
|
new FileHostAndPort
|
||||||
|
{
|
||||||
|
Host = "localhost",
|
||||||
|
Port = 51887,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
UpstreamPathTemplate = "/PostDetails",
|
||||||
|
UpstreamHttpMethod = new List<string> { "Get" },
|
||||||
|
Key = "PostDetails"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Aggregates = new List<FileAggregateReRoute>
|
||||||
|
{
|
||||||
|
new FileAggregateReRoute
|
||||||
|
{
|
||||||
|
UpstreamPathTemplate = "/",
|
||||||
|
UpstreamHost = "localhost",
|
||||||
|
ReRouteKeys = new List<string>
|
||||||
|
{
|
||||||
|
"Comments",
|
||||||
|
"UserDetails",
|
||||||
|
"PostDetails"
|
||||||
|
},
|
||||||
|
ReRouteKeysConfig = new List<AggregateReRouteConfig>()
|
||||||
|
{
|
||||||
|
new AggregateReRouteConfig(){ReRouteKey = "UserDetails",JsonPath = "$[*].writerId",Parameter = "userId"},
|
||||||
|
new AggregateReRouteConfig(){ReRouteKey = "PostDetails",JsonPath = "$[*].postId",Parameter = "postId"}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var userDetailsResponseContent = @"{""id"":1,""firstName"":""abolfazl"",""lastName"":""rajabpour""}";
|
||||||
|
var postDetailsResponseContent = @"{""id"":1,""title"":""post1""}";
|
||||||
|
var commentsResponseContent = @"[{""id"":1,""writerId"":1,""postId"":2,""text"":""text1""},{""id"":2,""writerId"":1,""postId"":2,""text"":""text2""}]";
|
||||||
|
|
||||||
|
var expected = "{\"Comments\":" + commentsResponseContent + ",\"UserDetails\":" + userDetailsResponseContent + ",\"PostDetails\":" + postDetailsResponseContent + "}";
|
||||||
|
|
||||||
|
this.Given(x => x.GivenServiceOneIsRunning("http://localhost:51889", "/", 200, commentsResponseContent))
|
||||||
|
.Given(x => x.GivenServiceTwoIsRunning("http://localhost:51890", "/users/1", 200, userDetailsResponseContent))
|
||||||
|
.Given(x => x.GivenServiceTwoIsRunning("http://localhost:51887", "/posts/2", 200, postDetailsResponseContent))
|
||||||
|
.And(x => _steps.GivenThereIsAConfiguration(configuration))
|
||||||
|
.And(x => _steps.GivenOcelotIsRunning())
|
||||||
|
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
|
||||||
|
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
||||||
|
.And(x => _steps.ThenTheResponseBodyShouldBe(expected))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_return_response_200_with_simple_url_user_defined_aggregate()
|
public void should_return_response_200_with_simple_url_user_defined_aggregate()
|
||||||
{
|
{
|
||||||
@ -189,8 +283,8 @@ namespace Ocelot.AcceptanceTests
|
|||||||
UpstreamHost = "localhost",
|
UpstreamHost = "localhost",
|
||||||
ReRouteKeys = new List<string>
|
ReRouteKeys = new List<string>
|
||||||
{
|
{
|
||||||
"Tom",
|
"Laura",
|
||||||
"Laura"
|
"Tom"
|
||||||
},
|
},
|
||||||
Aggregator = "FakeDefinedAggregator"
|
Aggregator = "FakeDefinedAggregator"
|
||||||
}
|
}
|
||||||
@ -258,8 +352,8 @@ namespace Ocelot.AcceptanceTests
|
|||||||
UpstreamHost = "localhost",
|
UpstreamHost = "localhost",
|
||||||
ReRouteKeys = new List<string>
|
ReRouteKeys = new List<string>
|
||||||
{
|
{
|
||||||
"Tom",
|
"Laura",
|
||||||
"Laura"
|
"Tom"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -326,8 +420,9 @@ namespace Ocelot.AcceptanceTests
|
|||||||
UpstreamHost = "localhost",
|
UpstreamHost = "localhost",
|
||||||
ReRouteKeys = new List<string>
|
ReRouteKeys = new List<string>
|
||||||
{
|
{
|
||||||
"Tom",
|
"Laura",
|
||||||
"Laura"
|
"Tom"
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -394,8 +489,8 @@ namespace Ocelot.AcceptanceTests
|
|||||||
UpstreamHost = "localhost",
|
UpstreamHost = "localhost",
|
||||||
ReRouteKeys = new List<string>
|
ReRouteKeys = new List<string>
|
||||||
{
|
{
|
||||||
"Tom",
|
"Laura",
|
||||||
"Laura"
|
"Tom"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -462,8 +557,8 @@ namespace Ocelot.AcceptanceTests
|
|||||||
UpstreamHost = "localhost",
|
UpstreamHost = "localhost",
|
||||||
ReRouteKeys = new List<string>
|
ReRouteKeys = new List<string>
|
||||||
{
|
{
|
||||||
"Tom",
|
"Laura",
|
||||||
"Laura"
|
"Tom"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,8 @@ namespace Ocelot.UnitTests.Middleware
|
|||||||
public ResponseAggregatorFactoryTests()
|
public ResponseAggregatorFactoryTests()
|
||||||
{
|
{
|
||||||
_provider = new Mock<IDefinedAggregatorProvider>();
|
_provider = new Mock<IDefinedAggregatorProvider>();
|
||||||
_factory = new InMemoryResponseAggregatorFactory(_provider.Object);
|
_aggregator = new SimpleJsonResponseAggregator();
|
||||||
|
_factory = new InMemoryResponseAggregatorFactory(_provider.Object, _aggregator);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -7,11 +7,11 @@ using Castle.Components.DictionaryAdapter;
|
|||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
using Ocelot.Configuration.Builder;
|
using Ocelot.Configuration.Builder;
|
||||||
using Ocelot.Errors;
|
using Ocelot.Configuration.File;
|
||||||
using Ocelot.Middleware;
|
using Ocelot.Middleware;
|
||||||
using Ocelot.Middleware.Multiplexer;
|
using Ocelot.Middleware.Multiplexer;
|
||||||
using Ocelot.Request.Middleware;
|
|
||||||
using Ocelot.UnitTests.Responder;
|
using Ocelot.UnitTests.Responder;
|
||||||
|
using Ocelot.Values;
|
||||||
using Shouldly;
|
using Shouldly;
|
||||||
using TestStack.BDDfy;
|
using TestStack.BDDfy;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
@ -30,6 +30,58 @@ namespace Ocelot.UnitTests.Middleware
|
|||||||
_aggregator = new SimpleJsonResponseAggregator();
|
_aggregator = new SimpleJsonResponseAggregator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_aggregate_n_responses_and_set_response_content_on_upstream_context_withConfig()
|
||||||
|
{
|
||||||
|
var commentsDownstreamReRoute = new DownstreamReRouteBuilder().WithKey("Comments").Build();
|
||||||
|
|
||||||
|
var userDetailsDownstreamReRoute = new DownstreamReRouteBuilder().WithKey("UserDetails")
|
||||||
|
.WithUpstreamPathTemplate(new UpstreamPathTemplate("", 0, false, "/v1/users/{userId}"))
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var downstreamReRoutes = new List<DownstreamReRoute>
|
||||||
|
{
|
||||||
|
commentsDownstreamReRoute,
|
||||||
|
userDetailsDownstreamReRoute
|
||||||
|
};
|
||||||
|
|
||||||
|
var reRoute = new ReRouteBuilder()
|
||||||
|
.WithDownstreamReRoutes(downstreamReRoutes)
|
||||||
|
.WithAggregateReRouteConfig(new List<AggregateReRouteConfig>()
|
||||||
|
{
|
||||||
|
new AggregateReRouteConfig(){ReRouteKey = "UserDetails",JsonPath = "$[*].writerId",Parameter = "userId"}
|
||||||
|
})
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var commentsResponseContent = @"[{""id"":1,""writerId"":1,""postId"":1,""text"":""text1""},{""id"":2,""writerId"":2,""postId"":2,""text"":""text2""},{""id"":3,""writerId"":2,""postId"":1,""text"":""text21""}]";
|
||||||
|
var commentsDownstreamContext = new DownstreamContext(new DefaultHttpContext())
|
||||||
|
{
|
||||||
|
DownstreamResponse = new DownstreamResponse(new StringContent(commentsResponseContent, Encoding.UTF8, "application/json"), HttpStatusCode.OK, new EditableList<KeyValuePair<string, IEnumerable<string>>>(), "some reason"),
|
||||||
|
DownstreamReRoute = commentsDownstreamReRoute
|
||||||
|
};
|
||||||
|
|
||||||
|
var userDetailsResponseContent = @"[{""id"":1,""firstName"":""abolfazl"",""lastName"":""rajabpour""},{""id"":2,""firstName"":""reza"",""lastName"":""rezaei""}]";
|
||||||
|
var userDetailsDownstreamContext = new DownstreamContext(new DefaultHttpContext())
|
||||||
|
{
|
||||||
|
DownstreamResponse = new DownstreamResponse(new StringContent(userDetailsResponseContent, Encoding.UTF8, "application/json"), HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>(), "some reason"),
|
||||||
|
DownstreamReRoute = userDetailsDownstreamReRoute
|
||||||
|
};
|
||||||
|
|
||||||
|
var downstreamContexts = new List<DownstreamContext> { commentsDownstreamContext, userDetailsDownstreamContext };
|
||||||
|
|
||||||
|
var expected = "{\"Comments\":" + commentsResponseContent + ",\"UserDetails\":" + userDetailsResponseContent + "}";
|
||||||
|
|
||||||
|
this.Given(x => GivenTheUpstreamContext(new DownstreamContext(new DefaultHttpContext())))
|
||||||
|
.And(x => GivenTheReRoute(reRoute))
|
||||||
|
.And(x => GivenTheDownstreamContext(downstreamContexts))
|
||||||
|
.When(x => WhenIAggregate())
|
||||||
|
.Then(x => ThenTheContentIs(expected))
|
||||||
|
.And(x => ThenTheContentTypeIs("application/json"))
|
||||||
|
.And(x => ThenTheReasonPhraseIs("cannot return from aggregate..which reason phrase would you use?"))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_aggregate_n_responses_and_set_response_content_on_upstream_context()
|
public void should_aggregate_n_responses_and_set_response_content_on_upstream_context()
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user