mirror of
https://github.com/meysamhadeli/booking-microservices.git
synced 2026-05-05 04:28:49 +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="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.1" />
|
||||||
<PackageReference Include="Testcontainers" Version="2.3.0" />
|
<PackageReference Include="Testcontainers" Version="2.3.0" />
|
||||||
<PackageReference Include="Unchase.Swashbuckle.AspNetCore.Extensions" Version="2.7.1" />
|
<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="Yarp.ReverseProxy" Version="1.1.1" />
|
||||||
<PackageReference Include="Microsoft.Identity.Web" Version="2.0.5-preview" />
|
<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.MassTransit;
|
||||||
using BuildingBlocks.Mongo;
|
using BuildingBlocks.Mongo;
|
||||||
using BuildingBlocks.PersistMessageProcessor;
|
using BuildingBlocks.PersistMessageProcessor;
|
||||||
using BuildingBlocks.TestBase.Auth;
|
|
||||||
using BuildingBlocks.Web;
|
using BuildingBlocks.Web;
|
||||||
using DotNet.Testcontainers.Containers;
|
using DotNet.Testcontainers.Containers;
|
||||||
using EasyNetQ.Management.Client;
|
using EasyNetQ.Management.Client;
|
||||||
@ -32,6 +31,10 @@ using ILogger = Serilog.ILogger;
|
|||||||
|
|
||||||
namespace BuildingBlocks.TestBase;
|
namespace BuildingBlocks.TestBase;
|
||||||
|
|
||||||
|
using System.Net;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using WebMotions.Fake.Authentication.JwtBearer;
|
||||||
|
|
||||||
public class TestFixture<TEntryPoint> : IAsyncLifetime
|
public class TestFixture<TEntryPoint> : IAsyncLifetime
|
||||||
where TEntryPoint : class
|
where TEntryPoint : class
|
||||||
{
|
{
|
||||||
@ -44,7 +47,18 @@ public class TestFixture<TEntryPoint> : IAsyncLifetime
|
|||||||
public MongoDbTestcontainer MongoDbTestContainer;
|
public MongoDbTestcontainer MongoDbTestContainer;
|
||||||
|
|
||||||
private ITestHarness TestHarness => ServiceProvider?.GetTestHarness();
|
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 GrpcChannel Channel => GrpcChannel.ForAddress(HttpClient.BaseAddress!, new GrpcChannelOptions { HttpClient = HttpClient });
|
||||||
public Action<IServiceCollection> TestRegistrationServices { get; set; }
|
public Action<IServiceCollection> TestRegistrationServices { get; set; }
|
||||||
public IServiceProvider ServiceProvider => _factory?.Services;
|
public IServiceProvider ServiceProvider => _factory?.Services;
|
||||||
@ -63,7 +77,15 @@ public class TestFixture<TEntryPoint> : IAsyncLifetime
|
|||||||
{
|
{
|
||||||
TestRegistrationServices?.Invoke(services);
|
TestRegistrationServices?.Invoke(services);
|
||||||
services.ReplaceSingleton(AddHttpContextAccessorMock);
|
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>[]
|
configuration.AddInMemoryCollection(new KeyValuePair<string, string>[]
|
||||||
{
|
{
|
||||||
new("DatabaseOptions:DefaultConnection", MsSqlTestContainer.ConnectionString + "TrustServerCertificate=True"),
|
new("DatabaseOptions:DefaultConnection", MsSqlTestContainer.ConnectionString + "TrustServerCertificate=True"),
|
||||||
new("PersistMessageOptions:ConnectionString", MsSqlPersistTestContainer.ConnectionString + "TrustServerCertificate=True"),
|
new("PersistMessageOptions:ConnectionString", MsSqlPersistTestContainer.ConnectionString + "TrustServerCertificate=True"), new("RabbitMqOptions:HostName", RabbitMqTestContainer.Hostname),
|
||||||
new("RabbitMqOptions:HostName", RabbitMqTestContainer.Hostname),
|
new("RabbitMqOptions:UserName", RabbitMqTestContainer.Username), new("RabbitMqOptions:Password", RabbitMqTestContainer.Password), new("RabbitMqOptions:Port", RabbitMqTestContainer.Port.ToString()),
|
||||||
new("RabbitMqOptions:UserName", RabbitMqTestContainer.Username),
|
new("MongoOptions:ConnectionString", MongoDbTestContainer.ConnectionString), new("MongoOptions:DatabaseName", MongoDbTestContainer.Database)
|
||||||
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>
|
public class TestReadFixture<TEntryPoint, TRContext> : TestFixture<TEntryPoint>
|
||||||
where TEntryPoint : class
|
where TEntryPoint : class
|
||||||
where TRContext : MongoDbContext
|
where TRContext : MongoDbContext
|
||||||
@ -428,7 +445,6 @@ public class TestFixtureCore<TEntryPoint> : IAsyncLifetime
|
|||||||
_reSpawnerPersistDb = await Respawner.CreateAsync(PersistDbConnection,
|
_reSpawnerPersistDb = await Respawner.CreateAsync(PersistDbConnection,
|
||||||
new RespawnerOptions { TablesToIgnore = new Table[] { "__EFMigrationsHistory" }, });
|
new RespawnerOptions { TablesToIgnore = new Table[] { "__EFMigrationsHistory" }, });
|
||||||
|
|
||||||
await _reSpawnerPersistDb.ResetAsync(PersistDbConnection);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(databaseOptions?.DefaultConnection))
|
if (!string.IsNullOrEmpty(databaseOptions?.DefaultConnection))
|
||||||
@ -439,18 +455,25 @@ public class TestFixtureCore<TEntryPoint> : IAsyncLifetime
|
|||||||
_reSpawnerDefaultDb = await Respawner.CreateAsync(DefaultDbConnection,
|
_reSpawnerDefaultDb = await Respawner.CreateAsync(DefaultDbConnection,
|
||||||
new RespawnerOptions { TablesToIgnore = new Table[] { "__EFMigrationsHistory" }, });
|
new RespawnerOptions { TablesToIgnore = new Table[] { "__EFMigrationsHistory" }, });
|
||||||
|
|
||||||
await _reSpawnerDefaultDb.ResetAsync(DefaultDbConnection);
|
|
||||||
|
|
||||||
await SeedDataAsync();
|
await SeedDataAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DisposeAsync()
|
public async Task DisposeAsync()
|
||||||
{
|
{
|
||||||
|
await ResetSqlAsync();
|
||||||
await ResetMongoAsync();
|
await ResetMongoAsync();
|
||||||
await ResetRabbitMqAsync();
|
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)
|
private async Task ResetMongoAsync(CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
//https://stackoverflow.com/questions/3366397/delete-everything-in-a-mongodb-database
|
//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 TestReadFixture<TEntryPoint, TRContext> Fixture { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public abstract class TestWriteBase<TEntryPoint, TWContext> : TestFixtureCore<TEntryPoint>
|
public abstract class TestWriteBase<TEntryPoint, TWContext> : TestFixtureCore<TEntryPoint>
|
||||||
//,IClassFixture<IntegrationTestFactory<TEntryPoint, TWContext>>
|
//,IClassFixture<IntegrationTestFactory<TEntryPoint, TWContext>>
|
||||||
where TEntryPoint : class
|
where TEntryPoint : class
|
||||||
|
|||||||
@ -20,7 +20,6 @@ var app = builder.Build();
|
|||||||
app.MapMinimalEndpoints();
|
app.MapMinimalEndpoints();
|
||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
app.UseRouting();
|
|
||||||
app.UseHttpsRedirection();
|
app.UseHttpsRedirection();
|
||||||
app.UseInfrastructure();
|
app.UseInfrastructure();
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,6 @@ var app = builder.Build();
|
|||||||
app.MapMinimalEndpoints();
|
app.MapMinimalEndpoints();
|
||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
app.UseRouting();
|
|
||||||
app.UseHttpsRedirection();
|
app.UseHttpsRedirection();
|
||||||
app.UseInfrastructure();
|
app.UseInfrastructure();
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,8 @@ using Xunit;
|
|||||||
|
|
||||||
namespace EndToEnd.Test.Flight.Features;
|
namespace EndToEnd.Test.Flight.Features;
|
||||||
|
|
||||||
|
using BuildingBlocks.Contracts.EventBus.Messages;
|
||||||
|
|
||||||
public class GetFlightByIdTests: FlightEndToEndTestBase
|
public class GetFlightByIdTests: FlightEndToEndTestBase
|
||||||
{
|
{
|
||||||
public GetFlightByIdTests(TestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFixture) : base(integrationTestFixture)
|
public GetFlightByIdTests(TestFixture<Program, FlightDbContext, FlightReadDbContext> integrationTestFixture) : base(integrationTestFixture)
|
||||||
@ -23,6 +25,8 @@ public class GetFlightByIdTests: FlightEndToEndTestBase
|
|||||||
//Arrange
|
//Arrange
|
||||||
var command = new FakeCreateFlightCommand().Generate();
|
var command = new FakeCreateFlightCommand().Generate();
|
||||||
await Fixture.SendAsync(command);
|
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);
|
(await Fixture.ShouldProcessedPersistInternalCommand<CreateFlightMongoCommand>()).Should().Be(true);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|||||||
@ -20,7 +20,6 @@ var app = builder.Build();
|
|||||||
app.MapMinimalEndpoints();
|
app.MapMinimalEndpoints();
|
||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
app.UseRouting();
|
|
||||||
app.UseHttpsRedirection();
|
app.UseHttpsRedirection();
|
||||||
app.UseInfrastructure();
|
app.UseInfrastructure();
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,6 @@ var app = builder.Build();
|
|||||||
app.MapMinimalEndpoints();
|
app.MapMinimalEndpoints();
|
||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
app.UseRouting();
|
|
||||||
app.UseHttpsRedirection();
|
app.UseHttpsRedirection();
|
||||||
app.UseInfrastructure();
|
app.UseInfrastructure();
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user