Fix ordering and basked scenarios

This commit is contained in:
David Fowler 2023-05-01 17:32:57 -07:00
parent 2736eae13e
commit 2b0889f684
8 changed files with 84 additions and 58 deletions

View File

@ -10,21 +10,21 @@ namespace Microsoft.AspNetCore.Hosting
{
public static class IWebHostExtensions
{
public static bool IsInKubernetes(this IWebHost webHost)
public static bool IsInKubernetes(this IServiceProvider services)
{
var cfg = webHost.Services.GetService<IConfiguration>();
var cfg = services.GetService<IConfiguration>();
var orchestratorType = cfg.GetValue<string>("OrchestratorType");
return orchestratorType?.ToUpper() == "K8S";
}
public static IWebHost MigrateDbContext<TContext>(this IWebHost webHost, Action<TContext, IServiceProvider> seeder) where TContext : DbContext
public static IServiceProvider MigrateDbContext<TContext>(this IServiceProvider services, Action<TContext, IServiceProvider> seeder) where TContext : DbContext
{
var underK8s = webHost.IsInKubernetes();
var underK8s = services.IsInKubernetes();
using var scope = webHost.Services.CreateScope();
var services = scope.ServiceProvider;
var logger = services.GetRequiredService<ILogger<TContext>>();
var context = services.GetService<TContext>();
using var scope = services.CreateScope();
var scopeServices = scope.ServiceProvider;
var logger = scopeServices.GetRequiredService<ILogger<TContext>>();
var context = scopeServices.GetService<TContext>();
try
{
@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Hosting
if (underK8s)
{
InvokeSeeder(seeder, context, services);
InvokeSeeder(seeder, context, scopeServices);
}
else
{
@ -50,7 +50,7 @@ namespace Microsoft.AspNetCore.Hosting
//migration can't fail for network related exception. The retry options for DbContext only
//apply to transient exceptions
// Note that this is NOT applied when running some orchestrators (let the orchestrator to recreate the failing service)
retry.Execute(() => InvokeSeeder(seeder, context, services));
retry.Execute(() => InvokeSeeder(seeder, context, scopeServices));
}
logger.LogInformation("Migrated database associated with context {DbContextName}", typeof(TContext).Name);
@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Hosting
}
}
return webHost;
return services;
}
private static void InvokeSeeder<TContext>(Action<TContext, IServiceProvider> seeder, TContext context, IServiceProvider services)

View File

@ -6,6 +6,12 @@ namespace Basket.FunctionalTests.Base;
public class BasketScenarioBase : WebApplicationFactory<Program>
{
private const string ApiUrlBase = "api/v1/basket";
public TestServer CreateServer()
{
return Server;
}
public static class Get
{
public static string GetBasket(int id)

View File

@ -6,10 +6,6 @@
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<None Remove="appsettings.json" />
</ItemGroup>
<ItemGroup>
<Content Include="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>

View File

@ -1,20 +1,15 @@
namespace Basket.FunctionalTests;
public class BasketScenarios : BasketScenarioBase
public class BasketScenarios :
BasketScenarioBase
{
private readonly HttpClient _httpClient;
public BasketScenarios()
{
_httpClient = CreateClient();
}
[Fact]
public async Task Post_basket_and_response_ok_status_code()
{
using var server = CreateServer();
var content = new StringContent(BuildBasket(), UTF8Encoding.UTF8, "application/json");
var uri = "/api/v1/basket/";
var response = await _httpClient.PostAsync(uri, content);
var response = await server.CreateClient().PostAsync(uri, content);
response.EnsureSuccessStatusCode();
}
@ -22,7 +17,8 @@ public class BasketScenarios : BasketScenarioBase
[Fact]
public async Task Get_basket_and_response_ok_status_code()
{
var response = await _httpClient
using var server = CreateServer();
var response = await server.CreateClient()
.GetAsync(Get.GetBasket(1));
response.EnsureSuccessStatusCode();
}
@ -30,9 +26,10 @@ public class BasketScenarios : BasketScenarioBase
[Fact]
public async Task Send_Checkout_basket_and_response_ok_status_code()
{
using var server = CreateServer();
var contentBasket = new StringContent(BuildBasket(), UTF8Encoding.UTF8, "application/json");
await _httpClient
await server.CreateClient()
.PostAsync(Post.Basket, contentBasket);
var contentCheckout = new StringContent(BuildCheckout(), UTF8Encoding.UTF8, "application/json")
@ -40,7 +37,7 @@ public class BasketScenarios : BasketScenarioBase
Headers = { { "x-requestid", Guid.NewGuid().ToString() } }
};
var response = await _httpClient
var response = await server.CreateClient()
.PostAsync(Post.CheckoutOrder, contentCheckout);
response.EnsureSuccessStatusCode();

View File

@ -331,7 +331,7 @@ static class CustomExtensionsMethods
public static IServiceCollection AddCustomSwagger(this IServiceCollection services, IConfiguration configuration)
{
services.AddSwaggerGen(options =>
return services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo
{
@ -339,6 +339,9 @@ static class CustomExtensionsMethods
Version = "v1",
Description = "The Ordering Service HTTP API"
});
var identityUrl = configuration["IdentityUrlExternal"];
options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OAuth2,
@ -346,8 +349,8 @@ static class CustomExtensionsMethods
{
Implicit = new OpenApiOAuthFlow()
{
AuthorizationUrl = new Uri($"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize"),
TokenUrl = new Uri($"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/token"),
AuthorizationUrl = new Uri($"{identityUrl}/connect/authorize"),
TokenUrl = new Uri($"{identityUrl}/connect/token"),
Scopes = new Dictionary<string, string>()
{
{ "orders", "Ordering API" }
@ -355,9 +358,9 @@ static class CustomExtensionsMethods
}
}
});
options.OperationFilter<AuthorizeCheckOperationFilter>();
});
return services;
}
public static IServiceCollection AddCustomIntegrations(this IServiceCollection services, IConfiguration configuration)

View File

@ -6,6 +6,12 @@
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<Content Include="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
@ -18,7 +24,6 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Web\WebMVC\WebMVC.csproj" />
<ProjectReference Include="..\Ordering.API\Ordering.API.csproj" />
<ProjectReference Include="..\Ordering.Domain\Ordering.Domain.csproj" />
<ProjectReference Include="..\Ordering.Infrastructure\Ordering.Infrastructure.csproj" />

View File

@ -1,24 +1,13 @@
namespace Ordering.FunctionalTests;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.Hosting;
public class OrderingScenarioBase
namespace Ordering.FunctionalTests;
public class OrderingScenarioBase : WebApplicationFactory<Program>
{
public TestServer CreateServer()
{
var path = Assembly.GetAssembly(typeof(OrderingScenarioBase))
.Location;
var hostBuilder = new WebHostBuilder()
.UseContentRoot(Path.GetDirectoryName(path))
.ConfigureAppConfiguration(cb =>
{
cb.AddJsonFile("appsettings.json", optional: false)
.AddEnvironmentVariables();
});
var testServer = new TestServer(hostBuilder);
testServer.Host
.MigrateDbContext<OrderingContext>((context, services) =>
Services.MigrateDbContext<OrderingContext>((context, services) =>
{
var env = services.GetService<IWebHostEnvironment>();
var settings = services.GetService<IOptions<OrderingSettings>>();
@ -30,7 +19,24 @@ public class OrderingScenarioBase
})
.MigrateDbContext<IntegrationEventLogContext>((_, __) => { });
return testServer;
return Server;
}
protected override IHost CreateHost(IHostBuilder builder)
{
builder.ConfigureServices(servies =>
{
servies.AddSingleton<IStartupFilter, AuthStartupFilter>();
});
builder.ConfigureAppConfiguration(c =>
{
var directory = Path.GetDirectoryName(typeof(OrderingScenarioBase).Assembly.Location)!;
c.AddJsonFile(Path.Combine(directory, "appsettings.json"), optional: false);
});
return base.CreateHost(builder);
}
public static class Get
@ -48,4 +54,17 @@ public class OrderingScenarioBase
public static string CancelOrder = "api/v1/orders/cancel";
public static string ShipOrder = "api/v1/orders/ship";
}
private class AuthStartupFilter : IStartupFilter
{
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
{
return app =>
{
app.UseMiddleware<AutoAuthorizeMiddleware>();
next(app);
};
}
}
}

View File

@ -1,7 +1,6 @@
using System.Net;
using System.Text;
using System.Text.Json;
using WebMVC.Services.ModelDTOs;
using Xunit;
namespace Ordering.FunctionalTests
@ -16,6 +15,7 @@ namespace Ordering.FunctionalTests
var response = await server.CreateClient()
.GetAsync(Get.Orders);
var s = await response.Content.ReadAsStringAsync();
response.EnsureSuccessStatusCode();
}
@ -49,7 +49,7 @@ namespace Ordering.FunctionalTests
string BuildOrder()
{
var order = new OrderDTO()
var order = new
{
OrderNumber = "-1"
};