Skip to content

Commit

Permalink
Merge branch 'develop' into 2168-watchkube
Browse files Browse the repository at this point in the history
  • Loading branch information
raman-m authored Oct 24, 2024
2 parents da71b90 + 1cf5597 commit b3d145d
Show file tree
Hide file tree
Showing 9 changed files with 717 additions and 676 deletions.
7 changes: 5 additions & 2 deletions src/Ocelot.Provider.Consul/ConsulProviderFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,16 @@ public static class ConsulProviderFactory // TODO : IServiceDiscoveryProviderFac
public static ServiceDiscoveryFinderDelegate Get { get; } = CreateProvider;
private static IServiceDiscoveryProvider CreateProvider(IServiceProvider provider, ServiceProviderConfiguration config, DownstreamRoute route)
{
// Singleton services
var factory = provider.GetService<IOcelotLoggerFactory>();
var consulFactory = provider.GetService<IConsulClientFactory>();
var contextAccessor = provider.GetService<IHttpContextAccessor>();

// Scoped services
var context = contextAccessor.HttpContext;
var configuration = new ConsulRegistryConfiguration(config.Scheme, config.Host, config.Port, route.ServiceName, config.Token); // TODO Why not to pass 2 args only: config, route? LoL
contextAccessor.HttpContext.Items[nameof(ConsulRegistryConfiguration)] = configuration; // initialize data
var serviceBuilder = provider.GetService<IConsulServiceBuilder>(); // consume data in default/custom builder
context.Items[nameof(ConsulRegistryConfiguration)] = configuration; // initialize data
var serviceBuilder = context.RequestServices.GetService<IConsulServiceBuilder>(); // consume data in default/custom builder

var consulProvider = new Consul(configuration, factory, consulFactory, serviceBuilder); // TODO It must be added to DI-container!

Expand Down
2 changes: 1 addition & 1 deletion test/Ocelot.AcceptanceTests/AggregateTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ public void Should_return_response_200_with_user_forwarding()
.And(x => x.GivenServiceIsRunning(1, port2, "/", 200, "{Hello from Tom}"))
.And(x => auth.GivenIHaveAToken(identityServerUrl))
.And(x => auth.GivenThereIsAConfiguration(configuration))
.And(x => auth.GivenOcelotIsRunningWithServices(configureServices, configureApp))
.And(x => auth.GivenOcelotIsRunningWithServices(configureServices, configureApp, true))
.And(x => auth.GivenIHaveAddedATokenToMyRequest())
.When(x => auth.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => auth.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
Expand Down
299 changes: 167 additions & 132 deletions test/Ocelot.AcceptanceTests/Configuration/ConfigurationInConsulTests.cs
Original file line number Diff line number Diff line change
@@ -1,180 +1,215 @@
using CacheManager.Core;
using Consul;
using IdentityServer4.Extensions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using Ocelot.AcceptanceTests.Caching;
using Ocelot.Cache.CacheManager;
using Ocelot.Configuration.File;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;
using Ocelot.Provider.Consul;
using System.Text;

namespace Ocelot.AcceptanceTests.Configuration
namespace Ocelot.AcceptanceTests.Configuration;

public sealed class ConfigurationInConsulTests : Steps, IDisposable
{
public class ConfigurationInConsulTests : IDisposable
private IHost _builder;
private IHost _fakeConsulBuilder;
private FileConfiguration _config;
private readonly List<ServiceEntry> _consulServices;

public ConfigurationInConsulTests()
{
private IHost _builder;
private readonly Steps _steps;
private IHost _fakeConsulBuilder;
private FileConfiguration _config;
private readonly List<ServiceEntry> _consulServices;
_consulServices = new List<ServiceEntry>();
}

public ConfigurationInConsulTests()
{
_consulServices = new List<ServiceEntry>();
_steps = new Steps();
}
public override void Dispose()
{
_builder?.Dispose();
_fakeConsulBuilder?.Dispose();
base.Dispose();
}

[Fact]
public void should_return_response_200_with_simple_url_when_using_jsonserialized_cache()
{
var consulPort = PortFinder.GetRandomPort();
var servicePort = PortFinder.GetRandomPort();
[Fact]
public void Should_return_response_200_with_simple_url_when_using_jsonserialized_cache()
{
var consulPort = PortFinder.GetRandomPort();
var servicePort = PortFinder.GetRandomPort();

var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
var configuration = new FileConfiguration
{
Routes = new List<FileRoute>
{
new()
{
new()
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
new()
{
new()
{
Host = "localhost",
Port = servicePort,
},
Host = "localhost",
Port = servicePort,
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
},
GlobalConfiguration = new FileGlobalConfiguration
},
GlobalConfiguration = new FileGlobalConfiguration
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider
{
Scheme = "http",
Host = "localhost",
Port = consulPort,
},
Scheme = "http",
Host = "localhost",
Port = consulPort,
},
};

var fakeConsulServiceDiscoveryUrl = $"http://localhost:{consulPort}";

this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, string.Empty))
.And(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{servicePort}", string.Empty, 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();
}
},
};

var fakeConsulServiceDiscoveryUrl = DownstreamUrl(consulPort);

this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, string.Empty))
.And(x => x.GivenThereIsAServiceRunningOn(DownstreamUrl(servicePort), string.Empty, 200, "Hello from Laura"))
.And(x => GivenThereIsAConfiguration(configuration))
.And(x => x.GivenOcelotIsRunningUsingConsulToStoreConfigAndJsonSerializedCache())
.When(x => WhenIGetUrlOnTheApiGateway("/"))
.Then(x => ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}

private Task GivenThereIsAFakeConsulServiceDiscoveryProvider(string url, string serviceName)
{
_fakeConsulBuilder = Host.CreateDefaultBuilder()
.ConfigureWebHost(webBuilder =>
{
webBuilder.UseUrls(url)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseUrls(url)
.Configure(app =>
private void GivenOcelotIsRunningUsingConsulToStoreConfigAndJsonSerializedCache()
{
_webHostBuilder = new WebHostBuilder()
.UseDefaultServiceProvider(_ => _.ValidateScopes = true)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", true, false)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", true, false);
config.AddJsonFile(_ocelotConfigFileName, true, false);
config.AddEnvironmentVariables();
})
.ConfigureServices(s =>
{
s.AddOcelot()
.AddCacheManager(x => x
.WithMicrosoftLogging(_ => { /*log.AddConsole(LogLevel.Debug);*/ })
.WithJsonSerializer()
.WithHandle(typeof(InMemoryJsonHandle<>)))
.AddConsul()
.AddConfigStoredInConsul();
})
.Configure(app => app.UseOcelot().GetAwaiter().GetResult()); // Turning as async/await some tests got broken

_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}

private Task 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 =>
{
app.Run(async context =>
if (context.Request.Method.ToLower() == "get" && context.Request.Path.Value == "/v1/kv/InternalConfiguration")
{
if (context.Request.Method.ToLower() == "get" && context.Request.Path.Value == "/v1/kv/InternalConfiguration")
{
var json = JsonConvert.SerializeObject(_config);
var json = JsonConvert.SerializeObject(_config);
var bytes = Encoding.UTF8.GetBytes(json);
var bytes = Encoding.UTF8.GetBytes(json);
var base64 = Convert.ToBase64String(bytes);
var base64 = Convert.ToBase64String(bytes);
var kvp = new FakeConsulGetResponse(base64);
var kvp = new FakeConsulGetResponse(base64);
await context.Response.WriteJsonAsync(new[] { kvp });
}
else if (context.Request.Method.ToLower() == "put" && context.Request.Path.Value == "/v1/kv/InternalConfiguration")
await context.Response.WriteJsonAsync(new[] { kvp });
}
else if (context.Request.Method.ToLower() == "put" && context.Request.Path.Value == "/v1/kv/InternalConfiguration")
{
try
{
try
{
var reader = new StreamReader(context.Request.Body);
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();
// 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);
_config = JsonConvert.DeserializeObject<FileConfiguration>(json);
var response = JsonConvert.SerializeObject(true);
var response = JsonConvert.SerializeObject(true);
await context.Response.WriteAsync(response);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
await context.Response.WriteAsync(response);
}
else if (context.Request.Path.Value == $"/v1/health/service/{serviceName}")
catch (Exception e)
{
await context.Response.WriteJsonAsync(_consulServices);
Console.WriteLine(e);
throw;
}
});
}
else if (context.Request.Path.Value == $"/v1/health/service/{serviceName}")
{
await context.Response.WriteJsonAsync(_consulServices);
}
});
}).Build();
return _fakeConsulBuilder.StartAsync();
}
});
}).Build();
return _fakeConsulBuilder.StartAsync();
}

public class FakeConsulGetResponse
public class FakeConsulGetResponse
{
public FakeConsulGetResponse(string value)
{
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; }
public string Session => "adf4238a-882b-9ddc-4a9d-5b6758e4159e";
Value = value;
}

private Task GivenThereIsAServiceRunningOn(string url, string basePath, int statusCode, string responseBody)
{
_builder = Host.CreateDefaultBuilder()
.ConfigureWebHost(webBuilder =>
public int CreateIndex => 100;
public int ModifyIndex => 200;
public int LockIndex => 200;
public string Key => "InternalConfiguration";
public int Flags => 0;
public string Value { get; }
public string Session => "adf4238a-882b-9ddc-4a9d-5b6758e4159e";
}

private Task 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 =>
{
webBuilder.UseUrls(url)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseUrls(url)
.Configure(app =>
app.UsePathBase(basePath);
app.Run(async context =>
{
app.UsePathBase(basePath);
app.Run(async context =>
{
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
});
context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody);
});
})
.Build();
return _builder.StartAsync();
}

public void Dispose()
{
_builder?.Dispose();
_steps.Dispose();
}
});
})
.Build();
return _builder.StartAsync();
}
}
Loading

0 comments on commit b3d145d

Please sign in to comment.