From 94a22dfc23f7b56cab49836a3d7acbcaf516ab88 Mon Sep 17 00:00:00 2001 From: Meysam Hadeli Date: Fri, 20 Feb 2026 02:10:54 +0330 Subject: [PATCH] fix: fix ci failed for tests --- src/BuildingBlocks/TestBase/TestBase.cs | 105 ++++++++---------- .../Identity/Features/RegisterNewUserTests.cs | 8 +- .../CompleteRegisterPassengerTests.cs | 15 ++- 3 files changed, 62 insertions(+), 66 deletions(-) diff --git a/src/BuildingBlocks/TestBase/TestBase.cs b/src/BuildingBlocks/TestBase/TestBase.cs index 3656f79..e23e06d 100644 --- a/src/BuildingBlocks/TestBase/TestBase.cs +++ b/src/BuildingBlocks/TestBase/TestBase.cs @@ -42,8 +42,8 @@ public class TestFixture : IAsyncLifetime where TEntryPoint : class { private readonly WebApplicationFactory _factory; - private int Timeout => 300; // Second - private ITestHarness TestHarness => ServiceProvider?.GetTestHarness(); + private int Timeout => 120; // Second + public ITestHarness TestHarness => ServiceProvider?.GetTestHarness(); private Action TestRegistrationServices { get; set; } private PostgreSqlContainer PostgresTestcontainer; private PostgreSqlContainer PostgresPersistTestContainer; @@ -136,10 +136,14 @@ public class TestFixture : IAsyncLifetime { CancellationTokenSource = new CancellationTokenSource(); await StartTestContainerAsync(); + + await TestHarness.Start(); } public async Task DisposeAsync() { + await TestHarness.Stop(); + await StopTestContainerAsync(); await _factory.DisposeAsync(); await CancellationTokenSource.CancelAsync(); @@ -201,83 +205,71 @@ public class TestFixture : IAsyncLifetime public async Task Publish(TMessage message, CancellationToken cancellationToken = default) where TMessage : class, IEvent { + // Use harness bus to ensure publish happens only after the bus is started. await TestHarness.Bus.Publish(message, cancellationToken); } public async Task WaitForPublishing(CancellationToken cancellationToken = default) where TMessage : class, IEvent { - var result = await WaitUntilConditionMet(async () => - { - var published = await TestHarness.Published.Any(cancellationToken); + var result = await WaitUntilConditionMet( + async () => + { + var published = await TestHarness.Published.Any(cancellationToken); - return published; - }); + return published; + }, + cancellationToken: cancellationToken + ); return result; } - public async Task WaitForConsuming(CancellationToken cancellationToken = default) - where TMessage : class, IEvent - { - var result = await WaitUntilConditionMet(async () => - { - var consumed = await TestHarness.Consumed.Any(cancellationToken); - - return consumed; - }); - - return result; - } - - public async Task ShouldProcessedPersistInternalCommand( + public Task WaitUntilAsync( + Func> condition, + TimeSpan? timeout = null, + TimeSpan? pollInterval = null, CancellationToken cancellationToken = default ) - where TInternalCommand : class, IInternalCommand { - var result = await WaitUntilConditionMet(async () => - { - return await ExecuteScopeAsync(async sp => + var effectiveTimeout = timeout ?? TimeSpan.FromSeconds(Timeout); + var effectivePollInterval = pollInterval ?? TimeSpan.FromMilliseconds(200); + + return WaitUntilConditionMet( + conditionToMet: async () => { - var persistMessageProcessor = sp.GetService(); - - 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; + cancellationToken.ThrowIfCancellationRequested(); + return await condition(); + }, + timeoutSecond: (int)Math.Ceiling(effectiveTimeout.TotalSeconds), + pollInterval: effectivePollInterval, + cancellationToken: cancellationToken + ); } // Ref: https://tech.energyhelpline.com/in-memory-testing-with-masstransit/ - private async Task WaitUntilConditionMet(Func> conditionToMet, int? timeoutSecond = null) + private async Task WaitUntilConditionMet( + Func> conditionToMet, + int? timeoutSecond = null, + TimeSpan? pollInterval = null, + CancellationToken cancellationToken = default + ) { var time = timeoutSecond ?? Timeout; + var delay = pollInterval ?? TimeSpan.FromMilliseconds(100); - var startTime = DateTime.Now; - var timeoutExpired = false; - var meet = await conditionToMet.Invoke(); - - while (!meet) + var startTime = DateTime.UtcNow; + while (DateTime.UtcNow - startTime <= TimeSpan.FromSeconds(time)) { - if (timeoutExpired) - { - return false; - } + cancellationToken.ThrowIfCancellationRequested(); - await Task.Delay(100); - meet = await conditionToMet.Invoke(); - timeoutExpired = DateTime.Now - startTime > TimeSpan.FromSeconds(time); + if (await conditionToMet.Invoke()) + return true; + + await Task.Delay(delay, cancellationToken); } - return true; + return false; } private async Task StartTestContainerAsync() @@ -288,7 +280,6 @@ public class TestFixture : IAsyncLifetime MongoDbTestContainer = TestContainers.MongoTestContainer(); EventStoreDbTestContainer = TestContainers.EventStoreTestContainer(); - // Start containers in parallel for speed await Task.WhenAll( MongoDbTestContainer.StartAsync(), PostgresTestcontainer.StartAsync(), @@ -296,9 +287,7 @@ public class TestFixture : IAsyncLifetime EventStoreDbTestContainer.StartAsync() ); - // Start RabbitMQ last and wait extra time await RabbitMqTestContainer.StartAsync(); - await Task.Delay(5000); // Give RabbitMQ extra time to initialize } private async Task StopTestContainerAsync() @@ -321,7 +310,7 @@ public class TestFixture : IAsyncLifetime new("PostgresOptions:ConnectionString:Identity", PostgresTestcontainer.GetConnectionString()), new("PostgresOptions:ConnectionString:Passenger", PostgresTestcontainer.GetConnectionString()), new("PersistMessageOptions:ConnectionString", PostgresPersistTestContainer.GetConnectionString()), - new("RabbitMqOptions:HostName", RabbitMqTestContainer.Hostname), + new("RabbitMqOptions:HostName", "127.0.0.1"), new("RabbitMqOptions:UserName", TestContainers.RabbitMqContainerConfiguration.UserName), new("RabbitMqOptions:Password", TestContainers.RabbitMqContainerConfiguration.Password), new( diff --git a/src/Services/Identity/tests/IntegrationTest/Identity/Features/RegisterNewUserTests.cs b/src/Services/Identity/tests/IntegrationTest/Identity/Features/RegisterNewUserTests.cs index a1b354f..bb6bc69 100644 --- a/src/Services/Identity/tests/IntegrationTest/Identity/Features/RegisterNewUserTests.cs +++ b/src/Services/Identity/tests/IntegrationTest/Identity/Features/RegisterNewUserTests.cs @@ -10,10 +10,8 @@ namespace Integration.Test.Identity.Features; public class RegisterNewUserTests : IdentityIntegrationTestBase { - public RegisterNewUserTests( - TestWriteFixture integrationTestFactory) : base(integrationTestFactory) - { - } + public RegisterNewUserTests(TestWriteFixture integrationTestFactory) + : base(integrationTestFactory) { } [Fact] public async Task should_create_new_user_to_db_and_publish_message_to_broker() @@ -30,4 +28,4 @@ public class RegisterNewUserTests : IdentityIntegrationTestBase (await Fixture.WaitForPublishing()).Should().Be(true); } -} \ No newline at end of file +} diff --git a/src/Services/Passenger/tests/IntegrationTest/Passenger/Features/CompleteRegisterPassengerTests.cs b/src/Services/Passenger/tests/IntegrationTest/Passenger/Features/CompleteRegisterPassengerTests.cs index 41b0e36..5537ca4 100644 --- a/src/Services/Passenger/tests/IntegrationTest/Passenger/Features/CompleteRegisterPassengerTests.cs +++ b/src/Services/Passenger/tests/IntegrationTest/Passenger/Features/CompleteRegisterPassengerTests.cs @@ -1,4 +1,3 @@ -using BuildingBlocks.Contracts.EventBus.Messages; using BuildingBlocks.TestBase; using FluentAssertions; using Integration.Test.Fakes; @@ -21,8 +20,8 @@ public class CompleteRegisterPassengerTests : PassengerIntegrationTestBase var userCreated = new FakeUserCreated().Generate(); await Fixture.Publish(userCreated); - (await Fixture.WaitForPublishing()).Should().Be(true); - (await Fixture.WaitForConsuming()).Should().Be(true); + + (await WaitUntilPassengerCreatedAsync(userCreated.PassportNumber)).Should().BeTrue(); var command = new FakeCompleteRegisterPassengerCommand(userCreated.PassportNumber).Generate(); @@ -36,4 +35,14 @@ public class CompleteRegisterPassengerTests : PassengerIntegrationTestBase response?.PassengerDto?.PassengerType.ToString().Should().Be(command.PassengerType.ToString()); response?.PassengerDto?.Age.Should().Be(command.Age); } + + private Task WaitUntilPassengerCreatedAsync(string passportNumber) + { + return Fixture.WaitUntilAsync(async () => + { + return await Fixture.ExecuteDbContextAsync(db => + ValueTask.FromResult(db.Passengers.Any(p => p.PassportNumber.Value == passportNumber)) + ); + }); + } }