mirror of
https://github.com/meysamhadeli/booking-microservices.git
synced 2026-04-24 14:28:09 +08:00
fix: fix ci failed for tests
This commit is contained in:
parent
3ce312891a
commit
94a22dfc23
@ -42,8 +42,8 @@ public class TestFixture<TEntryPoint> : IAsyncLifetime
|
|||||||
where TEntryPoint : class
|
where TEntryPoint : class
|
||||||
{
|
{
|
||||||
private readonly WebApplicationFactory<TEntryPoint> _factory;
|
private readonly WebApplicationFactory<TEntryPoint> _factory;
|
||||||
private int Timeout => 300; // Second
|
private int Timeout => 120; // Second
|
||||||
private ITestHarness TestHarness => ServiceProvider?.GetTestHarness();
|
public ITestHarness TestHarness => ServiceProvider?.GetTestHarness();
|
||||||
private Action<IServiceCollection> TestRegistrationServices { get; set; }
|
private Action<IServiceCollection> TestRegistrationServices { get; set; }
|
||||||
private PostgreSqlContainer PostgresTestcontainer;
|
private PostgreSqlContainer PostgresTestcontainer;
|
||||||
private PostgreSqlContainer PostgresPersistTestContainer;
|
private PostgreSqlContainer PostgresPersistTestContainer;
|
||||||
@ -136,10 +136,14 @@ public class TestFixture<TEntryPoint> : IAsyncLifetime
|
|||||||
{
|
{
|
||||||
CancellationTokenSource = new CancellationTokenSource();
|
CancellationTokenSource = new CancellationTokenSource();
|
||||||
await StartTestContainerAsync();
|
await StartTestContainerAsync();
|
||||||
|
|
||||||
|
await TestHarness.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DisposeAsync()
|
public async Task DisposeAsync()
|
||||||
{
|
{
|
||||||
|
await TestHarness.Stop();
|
||||||
|
|
||||||
await StopTestContainerAsync();
|
await StopTestContainerAsync();
|
||||||
await _factory.DisposeAsync();
|
await _factory.DisposeAsync();
|
||||||
await CancellationTokenSource.CancelAsync();
|
await CancellationTokenSource.CancelAsync();
|
||||||
@ -201,83 +205,71 @@ public class TestFixture<TEntryPoint> : IAsyncLifetime
|
|||||||
public async Task Publish<TMessage>(TMessage message, CancellationToken cancellationToken = default)
|
public async Task Publish<TMessage>(TMessage message, CancellationToken cancellationToken = default)
|
||||||
where TMessage : class, IEvent
|
where TMessage : class, IEvent
|
||||||
{
|
{
|
||||||
|
// Use harness bus to ensure publish happens only after the bus is started.
|
||||||
await TestHarness.Bus.Publish(message, cancellationToken);
|
await TestHarness.Bus.Publish(message, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> WaitForPublishing<TMessage>(CancellationToken cancellationToken = default)
|
public async Task<bool> WaitForPublishing<TMessage>(CancellationToken cancellationToken = default)
|
||||||
where TMessage : class, IEvent
|
where TMessage : class, IEvent
|
||||||
{
|
{
|
||||||
var result = await WaitUntilConditionMet(async () =>
|
var result = await WaitUntilConditionMet(
|
||||||
{
|
async () =>
|
||||||
var published = await TestHarness.Published.Any<TMessage>(cancellationToken);
|
{
|
||||||
|
var published = await TestHarness.Published.Any<TMessage>(cancellationToken);
|
||||||
|
|
||||||
return published;
|
return published;
|
||||||
});
|
},
|
||||||
|
cancellationToken: cancellationToken
|
||||||
|
);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> WaitForConsuming<TMessage>(CancellationToken cancellationToken = default)
|
public Task<bool> WaitUntilAsync(
|
||||||
where TMessage : class, IEvent
|
Func<Task<bool>> condition,
|
||||||
{
|
TimeSpan? timeout = null,
|
||||||
var result = await WaitUntilConditionMet(async () =>
|
TimeSpan? pollInterval = null,
|
||||||
{
|
|
||||||
var consumed = await TestHarness.Consumed.Any<TMessage>(cancellationToken);
|
|
||||||
|
|
||||||
return consumed;
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> ShouldProcessedPersistInternalCommand<TInternalCommand>(
|
|
||||||
CancellationToken cancellationToken = default
|
CancellationToken cancellationToken = default
|
||||||
)
|
)
|
||||||
where TInternalCommand : class, IInternalCommand
|
|
||||||
{
|
{
|
||||||
var result = await WaitUntilConditionMet(async () =>
|
var effectiveTimeout = timeout ?? TimeSpan.FromSeconds(Timeout);
|
||||||
{
|
var effectivePollInterval = pollInterval ?? TimeSpan.FromMilliseconds(200);
|
||||||
return await ExecuteScopeAsync(async sp =>
|
|
||||||
|
return WaitUntilConditionMet(
|
||||||
|
conditionToMet: async () =>
|
||||||
{
|
{
|
||||||
var persistMessageProcessor = sp.GetService<IPersistMessageProcessor>();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
return await condition();
|
||||||
Guard.Against.Null(persistMessageProcessor, nameof(persistMessageProcessor));
|
},
|
||||||
|
timeoutSecond: (int)Math.Ceiling(effectiveTimeout.TotalSeconds),
|
||||||
var filter = await persistMessageProcessor.GetByFilterAsync(x =>
|
pollInterval: effectivePollInterval,
|
||||||
x.DeliveryType == MessageDeliveryType.Internal && typeof(TInternalCommand).ToString() == x.DataType
|
cancellationToken: cancellationToken
|
||||||
);
|
);
|
||||||
|
|
||||||
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,
|
||||||
|
TimeSpan? pollInterval = null,
|
||||||
|
CancellationToken cancellationToken = default
|
||||||
|
)
|
||||||
{
|
{
|
||||||
var time = timeoutSecond ?? Timeout;
|
var time = timeoutSecond ?? Timeout;
|
||||||
|
var delay = pollInterval ?? TimeSpan.FromMilliseconds(100);
|
||||||
|
|
||||||
var startTime = DateTime.Now;
|
var startTime = DateTime.UtcNow;
|
||||||
var timeoutExpired = false;
|
while (DateTime.UtcNow - startTime <= TimeSpan.FromSeconds(time))
|
||||||
var meet = await conditionToMet.Invoke();
|
|
||||||
|
|
||||||
while (!meet)
|
|
||||||
{
|
{
|
||||||
if (timeoutExpired)
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
await Task.Delay(100);
|
if (await conditionToMet.Invoke())
|
||||||
meet = await conditionToMet.Invoke();
|
return true;
|
||||||
timeoutExpired = DateTime.Now - startTime > TimeSpan.FromSeconds(time);
|
|
||||||
|
await Task.Delay(delay, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task StartTestContainerAsync()
|
private async Task StartTestContainerAsync()
|
||||||
@ -288,7 +280,6 @@ public class TestFixture<TEntryPoint> : IAsyncLifetime
|
|||||||
MongoDbTestContainer = TestContainers.MongoTestContainer();
|
MongoDbTestContainer = TestContainers.MongoTestContainer();
|
||||||
EventStoreDbTestContainer = TestContainers.EventStoreTestContainer();
|
EventStoreDbTestContainer = TestContainers.EventStoreTestContainer();
|
||||||
|
|
||||||
// Start containers in parallel for speed
|
|
||||||
await Task.WhenAll(
|
await Task.WhenAll(
|
||||||
MongoDbTestContainer.StartAsync(),
|
MongoDbTestContainer.StartAsync(),
|
||||||
PostgresTestcontainer.StartAsync(),
|
PostgresTestcontainer.StartAsync(),
|
||||||
@ -296,9 +287,7 @@ public class TestFixture<TEntryPoint> : IAsyncLifetime
|
|||||||
EventStoreDbTestContainer.StartAsync()
|
EventStoreDbTestContainer.StartAsync()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Start RabbitMQ last and wait extra time
|
|
||||||
await RabbitMqTestContainer.StartAsync();
|
await RabbitMqTestContainer.StartAsync();
|
||||||
await Task.Delay(5000); // Give RabbitMQ extra time to initialize
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task StopTestContainerAsync()
|
private async Task StopTestContainerAsync()
|
||||||
@ -321,7 +310,7 @@ public class TestFixture<TEntryPoint> : IAsyncLifetime
|
|||||||
new("PostgresOptions:ConnectionString:Identity", PostgresTestcontainer.GetConnectionString()),
|
new("PostgresOptions:ConnectionString:Identity", PostgresTestcontainer.GetConnectionString()),
|
||||||
new("PostgresOptions:ConnectionString:Passenger", PostgresTestcontainer.GetConnectionString()),
|
new("PostgresOptions:ConnectionString:Passenger", PostgresTestcontainer.GetConnectionString()),
|
||||||
new("PersistMessageOptions:ConnectionString", PostgresPersistTestContainer.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:UserName", TestContainers.RabbitMqContainerConfiguration.UserName),
|
||||||
new("RabbitMqOptions:Password", TestContainers.RabbitMqContainerConfiguration.Password),
|
new("RabbitMqOptions:Password", TestContainers.RabbitMqContainerConfiguration.Password),
|
||||||
new(
|
new(
|
||||||
|
|||||||
@ -10,10 +10,8 @@ namespace Integration.Test.Identity.Features;
|
|||||||
|
|
||||||
public class RegisterNewUserTests : IdentityIntegrationTestBase
|
public class RegisterNewUserTests : IdentityIntegrationTestBase
|
||||||
{
|
{
|
||||||
public RegisterNewUserTests(
|
public RegisterNewUserTests(TestWriteFixture<Program, IdentityContext> integrationTestFactory)
|
||||||
TestWriteFixture<Program, IdentityContext> integrationTestFactory) : base(integrationTestFactory)
|
: base(integrationTestFactory) { }
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task should_create_new_user_to_db_and_publish_message_to_broker()
|
public async Task should_create_new_user_to_db_and_publish_message_to_broker()
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
using BuildingBlocks.Contracts.EventBus.Messages;
|
|
||||||
using BuildingBlocks.TestBase;
|
using BuildingBlocks.TestBase;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using Integration.Test.Fakes;
|
using Integration.Test.Fakes;
|
||||||
@ -21,8 +20,8 @@ public class CompleteRegisterPassengerTests : PassengerIntegrationTestBase
|
|||||||
var userCreated = new FakeUserCreated().Generate();
|
var userCreated = new FakeUserCreated().Generate();
|
||||||
|
|
||||||
await Fixture.Publish(userCreated);
|
await Fixture.Publish(userCreated);
|
||||||
(await Fixture.WaitForPublishing<UserCreated>()).Should().Be(true);
|
|
||||||
(await Fixture.WaitForConsuming<UserCreated>()).Should().Be(true);
|
(await WaitUntilPassengerCreatedAsync(userCreated.PassportNumber)).Should().BeTrue();
|
||||||
|
|
||||||
var command = new FakeCompleteRegisterPassengerCommand(userCreated.PassportNumber).Generate();
|
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?.PassengerType.ToString().Should().Be(command.PassengerType.ToString());
|
||||||
response?.PassengerDto?.Age.Should().Be(command.Age);
|
response?.PassengerDto?.Age.Should().Be(command.Age);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Task<bool> WaitUntilPassengerCreatedAsync(string passportNumber)
|
||||||
|
{
|
||||||
|
return Fixture.WaitUntilAsync(async () =>
|
||||||
|
{
|
||||||
|
return await Fixture.ExecuteDbContextAsync(db =>
|
||||||
|
ValueTask.FromResult(db.Passengers.Any(p => p.PassportNumber.Value == passportNumber))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user