Merge pull request #255 from meysamhadeli/fix/fix-problem-persist-message-background-job

fix: Fix problem run persist-message background job service in test-base
This commit is contained in:
Meysam Hadeli 2023-05-09 01:55:49 +03:30 committed by GitHub
commit d59c17671e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 65 additions and 44 deletions

View File

@ -373,6 +373,11 @@ dotnet_naming_rule.sanity_check_uncovered_field_case_rule.symbols = sanity_chec
dotnet_naming_rule.sanity_check_uncovered_field_case_rule.style = internal_error_style dotnet_naming_rule.sanity_check_uncovered_field_case_rule.style = internal_error_style
dotnet_naming_rule.sanity_check_uncovered_field_case_rule.severity = error dotnet_naming_rule.sanity_check_uncovered_field_case_rule.severity = error
##########################################
# VSThread
##########################################
dotnet_diagnostic.VSTHRD111.severity = none
########################################## ##########################################
# Other Naming Rules # Other Naming Rules

View File

@ -159,7 +159,6 @@
<Folder Include="Core\Pagination" /> <Folder Include="Core\Pagination" />
<Folder Include="EventStoreDB\BackgroundWorkers" /> <Folder Include="EventStoreDB\BackgroundWorkers" />
<Folder Include="PersistMessageProcessor\Data\Configurations" /> <Folder Include="PersistMessageProcessor\Data\Configurations" />
<Folder Include="PersistMessageProcessor\Data\Migrations" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -12,7 +12,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace BuildingBlocks.PersistMessageProcessor.Data.Migrations namespace BuildingBlocks.PersistMessageProcessor.Data.Migrations
{ {
[DbContext(typeof(PersistMessageDbContext))] [DbContext(typeof(PersistMessageDbContext))]
[Migration("20230331173133_initial")] [Migration("20230508215131_initial")]
partial class initial partial class initial
{ {
/// <inheritdoc /> /// <inheritdoc />

View File

@ -10,7 +10,8 @@ using Microsoft.AspNetCore.Hosting;
public static class Extensions public static class Extensions
{ {
public static IServiceCollection AddPersistMessageProcessor(this IServiceCollection services) public static IServiceCollection AddPersistMessageProcessor(this IServiceCollection services,
IWebHostEnvironment env)
{ {
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true); AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
@ -26,18 +27,23 @@ public static class Extensions
dbOptions.MigrationsAssembly(typeof(PersistMessageDbContext).Assembly.GetName().Name); dbOptions.MigrationsAssembly(typeof(PersistMessageDbContext).Assembly.GetName().Name);
}) })
// https://github.com/efcore/EFCore.NamingConventions // https://github.com/efcore/EFCore.NamingConventions
.UseSnakeCaseNamingConvention();; .UseSnakeCaseNamingConvention();
}); });
services.AddScoped<IPersistMessageDbContext>(provider => provider.GetService<PersistMessageDbContext>()); services.AddScoped<IPersistMessageDbContext>(provider => provider.GetService<PersistMessageDbContext>());
services.AddScoped<IPersistMessageProcessor, PersistMessageProcessor>(); services.AddScoped<IPersistMessageProcessor, PersistMessageProcessor>();
if (env.EnvironmentName != "test")
{
services.AddHostedService<PersistMessageBackgroundService>(); services.AddHostedService<PersistMessageBackgroundService>();
}
return services; return services;
} }
public static IApplicationBuilder UseMigrationPersistMessage<TContext>(this IApplicationBuilder app, IWebHostEnvironment env) public static IApplicationBuilder UseMigrationPersistMessage<TContext>(this IApplicationBuilder app,
IWebHostEnvironment env)
where TContext : DbContext, IPersistMessageDbContext where TContext : DbContext, IPersistMessageDbContext
{ {
using var scope = app.ApplicationServices.CreateScope(); using var scope = app.ApplicationServices.CreateScope();

View File

@ -5,7 +5,6 @@ using BuildingBlocks.EFCore;
using BuildingBlocks.Mongo; using BuildingBlocks.Mongo;
using BuildingBlocks.PersistMessageProcessor; using BuildingBlocks.PersistMessageProcessor;
using BuildingBlocks.Web; using BuildingBlocks.Web;
using DotNet.Testcontainers.Containers;
using EasyNetQ.Management.Client; using EasyNetQ.Management.Client;
using Grpc.Net.Client; using Grpc.Net.Client;
using MassTransit; using MassTransit;
@ -49,6 +48,10 @@ public class TestFixture<TEntryPoint> : IAsyncLifetime
public RabbitMqContainer RabbitMqTestContainer; public RabbitMqContainer RabbitMqTestContainer;
public MongoDbContainer MongoDbTestContainer; public MongoDbContainer MongoDbTestContainer;
public EventStoreDbContainer EventStoreDbTestContainer; public EventStoreDbContainer EventStoreDbTestContainer;
public CancellationTokenSource CancellationTokenSource;
public PersistMessageBackgroundService PersistMessageBackgroundService =>
ServiceProvider.GetRequiredService<PersistMessageBackgroundService>();
public HttpClient HttpClient public HttpClient HttpClient
{ {
@ -85,6 +88,12 @@ public class TestFixture<TEntryPoint> : IAsyncLifetime
TestRegistrationServices?.Invoke(services); TestRegistrationServices?.Invoke(services);
services.ReplaceSingleton(AddHttpContextAccessorMock); services.ReplaceSingleton(AddHttpContextAccessorMock);
services.AddSingleton<PersistMessageBackgroundService>();
// // remove persist-message processor background service
// var descriptor = services.Single(s => s.ImplementationType == typeof(PersistMessageBackgroundService));
// services.Remove(descriptor);
// add authentication using a fake jwt bearer - we can use SetAdminUser method to set authenticate user to existing HttContextAccessor // 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
// https://github.com/webmotions/fake-authentication-jwtbearer/issues/14 // https://github.com/webmotions/fake-authentication-jwtbearer/issues/14
@ -99,6 +108,7 @@ public class TestFixture<TEntryPoint> : IAsyncLifetime
public async Task InitializeAsync() public async Task InitializeAsync()
{ {
CancellationTokenSource = new CancellationTokenSource();
await StartTestContainerAsync(); await StartTestContainerAsync();
} }
@ -106,6 +116,7 @@ public class TestFixture<TEntryPoint> : IAsyncLifetime
{ {
await StopTestContainerAsync(); await StopTestContainerAsync();
await _factory.DisposeAsync(); await _factory.DisposeAsync();
CancellationTokenSource.Cancel();
} }
public virtual void RegisterServices(Action<IServiceCollection> services) public virtual void RegisterServices(Action<IServiceCollection> services)
@ -141,6 +152,7 @@ public class TestFixture<TEntryPoint> : IAsyncLifetime
return result; return result;
} }
public Task<TResponse> SendAsync<TResponse>(IRequest<TResponse> request) public Task<TResponse> SendAsync<TResponse>(IRequest<TResponse> request)
{ {
return ExecuteScopeAsync(sp => return ExecuteScopeAsync(sp =>
@ -173,7 +185,6 @@ public class TestFixture<TEntryPoint> : IAsyncLifetime
{ {
var published = await TestHarness.Published.Any<TMessage>(cancellationToken); var published = await TestHarness.Published.Any<TMessage>(cancellationToken);
var faulty = await TestHarness.Published.Any<Fault<TMessage>>(cancellationToken); var faulty = await TestHarness.Published.Any<Fault<TMessage>>(cancellationToken);
return published && faulty == false; return published && faulty == false;
}); });
return result; return result;
@ -193,6 +204,30 @@ public class TestFixture<TEntryPoint> : IAsyncLifetime
return result; return result;
} }
public async Task<bool> ShouldProcessedPersistInternalCommand<TInternalCommand>(
CancellationToken cancellationToken = default)
where TInternalCommand : class, IInternalCommand
{
var result = await WaitUntilConditionMet(async () =>
{
return await ExecuteScopeAsync(async sp =>
{
var persistMessageProcessor = sp.GetService<IPersistMessageProcessor>();
Guard.Against.Null(persistMessageProcessor, nameof(persistMessageProcessor));
var filter = await persistMessageProcessor.GetByFilterAsync(x =>
x.DeliveryType == MessageDeliveryType.Internal &&
typeof(TInternalCommand).ToString() == x.DataType);
var res = filter.Any(x => x.MessageStatus == MessageStatus.Processed);
return res;
});
});
return result;
}
// Ref: https://tech.energyhelpline.com/in-memory-testing-with-masstransit/ // Ref: https://tech.energyhelpline.com/in-memory-testing-with-masstransit/
private async Task<bool> WaitUntilConditionMet(Func<Task<bool>> conditionToMet, int? timeoutSecond = null) private async Task<bool> WaitUntilConditionMet(Func<Task<bool>> conditionToMet, int? timeoutSecond = null)
{ {
@ -216,30 +251,6 @@ public class TestFixture<TEntryPoint> : IAsyncLifetime
return true; return true;
} }
public async Task<bool> ShouldProcessedPersistInternalCommand<TInternalCommand>()
where TInternalCommand : class, IInternalCommand
{
var result = await WaitUntilConditionMet(async () =>
{
return await ExecuteScopeAsync(async sp =>
{
var persistMessageProcessor = sp.GetService<IPersistMessageProcessor>();
Guard.Against.Null(persistMessageProcessor, nameof(persistMessageProcessor));
var filter = await persistMessageProcessor.GetByFilterAsync(x =>
x.DeliveryType == MessageDeliveryType.Internal &&
typeof(TInternalCommand).ToString() == x.DataType);
var res = filter.Any(x => x.MessageStatus == MessageStatus.Processed);
return res;
});
});
return result;
}
private async Task StartTestContainerAsync() private async Task StartTestContainerAsync()
{ {
PostgresTestcontainer = TestContainers.PostgresTestContainer(); PostgresTestcontainer = TestContainers.PostgresTestContainer();
@ -496,6 +507,8 @@ public class TestFixtureCore<TEntryPoint> : IAsyncLifetime
if (!string.IsNullOrEmpty(persistOptions?.ConnectionString)) if (!string.IsNullOrEmpty(persistOptions?.ConnectionString))
{ {
await Fixture.PersistMessageBackgroundService.StartAsync(Fixture.CancellationTokenSource.Token);
PersistDbConnection = new NpgsqlConnection(persistOptions.ConnectionString); PersistDbConnection = new NpgsqlConnection(persistOptions.ConnectionString);
await PersistDbConnection.OpenAsync(); await PersistDbConnection.OpenAsync();
@ -520,6 +533,8 @@ public class TestFixtureCore<TEntryPoint> : IAsyncLifetime
if (PersistDbConnection is not null) if (PersistDbConnection is not null)
{ {
await _reSpawnerPersistDb.ResetAsync(PersistDbConnection); await _reSpawnerPersistDb.ResetAsync(PersistDbConnection);
await Fixture.PersistMessageBackgroundService.StopAsync(Fixture.CancellationTokenSource.Token);
} }
if (DefaultDbConnection is not null) if (DefaultDbConnection is not null)

View File

@ -57,7 +57,7 @@ public static class InfrastructureExtensions
})); }));
}); });
builder.Services.AddPersistMessageProcessor(); builder.Services.AddPersistMessageProcessor(env);
builder.Services.AddMongoDbContext<BookingReadDbContext>(configuration); builder.Services.AddMongoDbContext<BookingReadDbContext>(configuration);
builder.AddCustomSerilog(env); builder.AddCustomSerilog(env);

View File

@ -65,7 +65,7 @@ public static class InfrastructureExtensions
builder.Services.AddCustomDbContext<FlightDbContext>(); builder.Services.AddCustomDbContext<FlightDbContext>();
builder.Services.AddScoped<IDataSeeder, FlightDataSeeder>(); builder.Services.AddScoped<IDataSeeder, FlightDataSeeder>();
builder.Services.AddMongoDbContext<FlightReadDbContext>(configuration); builder.Services.AddMongoDbContext<FlightReadDbContext>(configuration);
builder.Services.AddPersistMessageProcessor(); builder.Services.AddPersistMessageProcessor(env);
builder.AddCustomSerilog(env); builder.AddCustomSerilog(env);
builder.Services.AddJwt(); builder.Services.AddJwt();

View File

@ -9,8 +9,6 @@ using Xunit;
namespace Integration.Test.Aircraft.Features; namespace Integration.Test.Aircraft.Features;
using global::Flight.Aircrafts.Features.CreatingAircraft.V1;
public class CreateAircraftTests : FlightIntegrationTestBase public class CreateAircraftTests : FlightIntegrationTestBase
{ {
public CreateAircraftTests( public CreateAircraftTests(

View File

@ -9,8 +9,6 @@ using Xunit;
namespace Integration.Test.Airport.Features; namespace Integration.Test.Airport.Features;
using global::Flight.Airports.Features.CreatingAirport.V1;
public class CreateAirportTests : FlightIntegrationTestBase public class CreateAirportTests : FlightIntegrationTestBase
{ {
public CreateAirportTests( public CreateAirportTests(

View File

@ -59,7 +59,7 @@ public static class InfrastructureExtensions
}); });
builder.Services.AddControllers(); builder.Services.AddControllers();
builder.Services.AddPersistMessageProcessor(); builder.Services.AddPersistMessageProcessor(env);
builder.Services.AddCustomDbContext<IdentityContext>(); builder.Services.AddCustomDbContext<IdentityContext>();
builder.Services.AddScoped<IDataSeeder, IdentityDataSeeder>(); builder.Services.AddScoped<IDataSeeder, IdentityDataSeeder>();
builder.AddCustomSerilog(env); builder.AddCustomSerilog(env);

View File

@ -58,7 +58,7 @@ public static class InfrastructureExtensions
})); }));
}); });
builder.Services.AddPersistMessageProcessor(); builder.Services.AddPersistMessageProcessor(env);
builder.Services.AddCustomDbContext<PassengerDbContext>(); builder.Services.AddCustomDbContext<PassengerDbContext>();
builder.Services.AddMongoDbContext<PassengerReadDbContext>(configuration); builder.Services.AddMongoDbContext<PassengerReadDbContext>(configuration);