mirror of
https://github.com/meysamhadeli/booking-microservices.git
synced 2026-04-14 20:54:05 +08:00
Merge pull request #77 from meysamhadeli/bug/fix-dispose-in-test-fixture
fix: Fix bug dispose service provider in test base
This commit is contained in:
commit
c53e6674f4
@ -102,6 +102,7 @@
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.1" />
|
||||
<PackageReference Include="Testcontainers" Version="2.3.0" />
|
||||
<PackageReference Include="Unchase.Swashbuckle.AspNetCore.Extensions" Version="2.7.1" />
|
||||
<PackageReference Include="WebMotions.Fake.Authentication.JwtBearer" Version="7.0.0" />
|
||||
<PackageReference Include="Yarp.ReverseProxy" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.Identity.Web" Version="2.0.5-preview" />
|
||||
|
||||
|
||||
@ -1,32 +0,0 @@
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace BuildingBlocks.TestBase.Auth;
|
||||
|
||||
//ref: https://blog.joaograssi.com/posts/2021/asp-net-core-testing-permission-protected-api-endpoints/
|
||||
public static class AuthServiceCollectionExtensions
|
||||
{
|
||||
private static MockAuthUser GetMockUser() =>
|
||||
new MockAuthUser(new Claim("sub", Guid.NewGuid().ToString()),
|
||||
new Claim("email", "sam@test.com"));
|
||||
|
||||
public static AuthenticationBuilder AddTestAuthentication(this IServiceCollection services)
|
||||
{
|
||||
services.AddAuthorization(options =>
|
||||
{
|
||||
// AuthConstants.Scheme is just a scheme we define. I called it "TestAuth"
|
||||
options.DefaultPolicy = new AuthorizationPolicyBuilder("Test")
|
||||
.RequireAuthenticatedUser()
|
||||
.Build();
|
||||
});
|
||||
|
||||
// Register a default user, so all requests have it by default
|
||||
services.AddScoped(_ => GetMockUser());
|
||||
|
||||
// Register our custom authentication handler
|
||||
return services.AddAuthentication("Test")
|
||||
.AddScheme<AuthenticationSchemeOptions, TestAuthHandler>("Test", options => { });
|
||||
}
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace BuildingBlocks.TestBase.Auth;
|
||||
|
||||
public class MockAuthUser
|
||||
{
|
||||
public List<Claim> Claims { get; }
|
||||
public MockAuthUser(params Claim[] claims) => Claims = claims.ToList();
|
||||
}
|
||||
@ -1,43 +0,0 @@
|
||||
using System.Security.Claims;
|
||||
using System.Text.Encodings.Web;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace BuildingBlocks.TestBase.Auth;
|
||||
|
||||
//ref: https://blog.joaograssi.com/posts/2021/asp-net-core-testing-permission-protected-api-endpoints/
|
||||
public class TestAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
|
||||
{
|
||||
|
||||
|
||||
private readonly MockAuthUser _mockAuthUser;
|
||||
|
||||
public TestAuthHandler(
|
||||
IOptionsMonitor<AuthenticationSchemeOptions> options,
|
||||
ILoggerFactory logger,
|
||||
UrlEncoder encoder,
|
||||
ISystemClock clock,
|
||||
MockAuthUser mockAuthUser)
|
||||
: base(options, logger, encoder, clock)
|
||||
{
|
||||
// 1. We get a "mock" user instance here via DI.
|
||||
// we'll see how this work later, don't worry
|
||||
_mockAuthUser = mockAuthUser;
|
||||
}
|
||||
|
||||
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||
{
|
||||
if (_mockAuthUser.Claims.Count == 0)
|
||||
return Task.FromResult(AuthenticateResult.Fail("Mock auth user not configured."));
|
||||
|
||||
// 2. Create the principal and the ticket
|
||||
var identity = new ClaimsIdentity(_mockAuthUser.Claims, "Test");
|
||||
var principal = new ClaimsPrincipal(identity);
|
||||
var ticket = new AuthenticationTicket(principal, "Test");
|
||||
|
||||
// 3. Authenticate the request
|
||||
var result = AuthenticateResult.Success(ticket);
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
}
|
||||
@ -5,7 +5,6 @@ using BuildingBlocks.EFCore;
|
||||
using BuildingBlocks.MassTransit;
|
||||
using BuildingBlocks.Mongo;
|
||||
using BuildingBlocks.PersistMessageProcessor;
|
||||
using BuildingBlocks.TestBase.Auth;
|
||||
using BuildingBlocks.Web;
|
||||
using DotNet.Testcontainers.Containers;
|
||||
using EasyNetQ.Management.Client;
|
||||
@ -32,6 +31,10 @@ using ILogger = Serilog.ILogger;
|
||||
|
||||
namespace BuildingBlocks.TestBase;
|
||||
|
||||
using System.Net;
|
||||
using System.Security.Claims;
|
||||
using WebMotions.Fake.Authentication.JwtBearer;
|
||||
|
||||
public class TestFixture<TEntryPoint> : IAsyncLifetime
|
||||
where TEntryPoint : class
|
||||
{
|
||||
@ -44,7 +47,18 @@ public class TestFixture<TEntryPoint> : IAsyncLifetime
|
||||
public MongoDbTestcontainer MongoDbTestContainer;
|
||||
|
||||
private ITestHarness TestHarness => ServiceProvider?.GetTestHarness();
|
||||
public HttpClient HttpClient => _factory?.CreateClient();
|
||||
|
||||
public HttpClient HttpClient
|
||||
{
|
||||
get
|
||||
{
|
||||
var claims = new Dictionary<string, object> { { ClaimTypes.Name, "test@sample.com" }, { ClaimTypes.Role, "admin" }, };
|
||||
var httpClient = _factory?.CreateClient();
|
||||
httpClient.SetFakeBearerToken(claims);
|
||||
return httpClient;
|
||||
}
|
||||
}
|
||||
|
||||
public GrpcChannel Channel => GrpcChannel.ForAddress(HttpClient.BaseAddress!, new GrpcChannelOptions { HttpClient = HttpClient });
|
||||
public Action<IServiceCollection> TestRegistrationServices { get; set; }
|
||||
public IServiceProvider ServiceProvider => _factory?.Services;
|
||||
@ -63,7 +77,15 @@ public class TestFixture<TEntryPoint> : IAsyncLifetime
|
||||
{
|
||||
TestRegistrationServices?.Invoke(services);
|
||||
services.ReplaceSingleton(AddHttpContextAccessorMock);
|
||||
services.AddTestAuthentication();
|
||||
|
||||
// add authentication using a fake jwt bearer - we can use SetAdminUser method to set authenticate user to existing HttContextAccessor
|
||||
// https://github.com/webmotions/fake-authentication-jwtbearer
|
||||
// https://github.com/webmotions/fake-authentication-jwtbearer/issues/14
|
||||
services.AddAuthentication(options =>
|
||||
{
|
||||
options.DefaultAuthenticateScheme = FakeJwtBearerDefaults.AuthenticationScheme;
|
||||
options.DefaultChallengeScheme = FakeJwtBearerDefaults.AuthenticationScheme;
|
||||
}).AddFakeJwtBearer();
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -235,13 +257,9 @@ public class TestFixture<TEntryPoint> : IAsyncLifetime
|
||||
configuration.AddInMemoryCollection(new KeyValuePair<string, string>[]
|
||||
{
|
||||
new("DatabaseOptions:DefaultConnection", MsSqlTestContainer.ConnectionString + "TrustServerCertificate=True"),
|
||||
new("PersistMessageOptions:ConnectionString", MsSqlPersistTestContainer.ConnectionString + "TrustServerCertificate=True"),
|
||||
new("RabbitMqOptions:HostName", RabbitMqTestContainer.Hostname),
|
||||
new("RabbitMqOptions:UserName", RabbitMqTestContainer.Username),
|
||||
new("RabbitMqOptions:Password", RabbitMqTestContainer.Password),
|
||||
new("RabbitMqOptions:Port", RabbitMqTestContainer.Port.ToString()),
|
||||
new("MongoOptions:ConnectionString", MongoDbTestContainer.ConnectionString),
|
||||
new("MongoOptions:DatabaseName", MongoDbTestContainer.Database)
|
||||
new("PersistMessageOptions:ConnectionString", MsSqlPersistTestContainer.ConnectionString + "TrustServerCertificate=True"), new("RabbitMqOptions:HostName", RabbitMqTestContainer.Hostname),
|
||||
new("RabbitMqOptions:UserName", RabbitMqTestContainer.Username), new("RabbitMqOptions:Password", RabbitMqTestContainer.Password), new("RabbitMqOptions:Port", RabbitMqTestContainer.Port.ToString()),
|
||||
new("MongoOptions:ConnectionString", MongoDbTestContainer.ConnectionString), new("MongoOptions:DatabaseName", MongoDbTestContainer.Database)
|
||||
});
|
||||
}
|
||||
|
||||
@ -365,7 +383,6 @@ public class TestWriteFixture<TEntryPoint, TWContext> : TestFixture<TEntryPoint>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class TestReadFixture<TEntryPoint, TRContext> : TestFixture<TEntryPoint>
|
||||
where TEntryPoint : class
|
||||
where TRContext : MongoDbContext
|
||||
@ -428,7 +445,6 @@ public class TestFixtureCore<TEntryPoint> : IAsyncLifetime
|
||||
_reSpawnerPersistDb = await Respawner.CreateAsync(PersistDbConnection,
|
||||
new RespawnerOptions { TablesToIgnore = new Table[] { "__EFMigrationsHistory" }, });
|
||||
|
||||
await _reSpawnerPersistDb.ResetAsync(PersistDbConnection);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(databaseOptions?.DefaultConnection))
|
||||
@ -439,18 +455,25 @@ public class TestFixtureCore<TEntryPoint> : IAsyncLifetime
|
||||
_reSpawnerDefaultDb = await Respawner.CreateAsync(DefaultDbConnection,
|
||||
new RespawnerOptions { TablesToIgnore = new Table[] { "__EFMigrationsHistory" }, });
|
||||
|
||||
await _reSpawnerDefaultDb.ResetAsync(DefaultDbConnection);
|
||||
|
||||
await SeedDataAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DisposeAsync()
|
||||
{
|
||||
await ResetSqlAsync();
|
||||
await ResetMongoAsync();
|
||||
await ResetRabbitMqAsync();
|
||||
}
|
||||
|
||||
private async Task ResetSqlAsync()
|
||||
{
|
||||
if (PersistDbConnection is not null)
|
||||
await _reSpawnerPersistDb.ResetAsync(PersistDbConnection);
|
||||
if (DefaultDbConnection is not null)
|
||||
await _reSpawnerDefaultDb.ResetAsync(DefaultDbConnection);
|
||||
}
|
||||
|
||||
private async Task ResetMongoAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
//https://stackoverflow.com/questions/3366397/delete-everything-in-a-mongodb-database
|
||||
@ -517,7 +540,6 @@ public abstract class TestReadBase<TEntryPoint, TRContext> : TestFixtureCore<TEn
|
||||
public TestReadFixture<TEntryPoint, TRContext> Fixture { get; }
|
||||
}
|
||||
|
||||
|
||||
public abstract class TestWriteBase<TEntryPoint, TWContext> : TestFixtureCore<TEntryPoint>
|
||||
//,IClassFixture<IntegrationTestFactory<TEntryPoint, TWContext>>
|
||||
where TEntryPoint : class
|
||||
|
||||
@ -20,7 +20,6 @@ var app = builder.Build();
|
||||
app.MapMinimalEndpoints();
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
app.UseRouting();
|
||||
app.UseHttpsRedirection();
|
||||
app.UseInfrastructure();
|
||||
|
||||
|
||||
@ -21,7 +21,6 @@ var app = builder.Build();
|
||||
app.MapMinimalEndpoints();
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
app.UseRouting();
|
||||
app.UseHttpsRedirection();
|
||||
app.UseInfrastructure();
|
||||
|
||||
|
||||
@ -10,6 +10,8 @@ using Xunit;
|
||||
|
||||
namespace EndToEnd.Test.Flight.Features;
|
||||
|
||||
using BuildingBlocks.Contracts.EventBus.Messages;
|
||||
|
||||
public class GetFlightByIdTests: FlightEndToEndTestBase
|
||||
{
|
||||
public GetFlightByIdTests(TestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFixture) : base(integrationTestFixture)
|
||||
@ -23,6 +25,8 @@ public class GetFlightByIdTests: FlightEndToEndTestBase
|
||||
//Arrange
|
||||
var command = new FakeCreateFlightCommand().Generate();
|
||||
await Fixture.SendAsync(command);
|
||||
(await Fixture.WaitForPublishing<FlightCreated>()).Should().Be(true);
|
||||
(await Fixture.WaitForConsuming<FlightCreated>()).Should().Be(true);
|
||||
(await Fixture.ShouldProcessedPersistInternalCommand<CreateFlightMongoCommand>()).Should().Be(true);
|
||||
|
||||
// Act
|
||||
|
||||
@ -20,7 +20,6 @@ var app = builder.Build();
|
||||
app.MapMinimalEndpoints();
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
app.UseRouting();
|
||||
app.UseHttpsRedirection();
|
||||
app.UseInfrastructure();
|
||||
|
||||
|
||||
@ -20,7 +20,6 @@ var app = builder.Build();
|
||||
app.MapMinimalEndpoints();
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
app.UseRouting();
|
||||
app.UseHttpsRedirection();
|
||||
app.UseInfrastructure();
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user