Skip to content

Commit 786fbb1

Browse files
authored
Merge pull request #370 from meysamhadeli/fix/fix-ci-failed
fix: fix ci failed
2 parents 9dcd662 + b9b3c26 commit 786fbb1

File tree

3 files changed

+158
-36
lines changed

3 files changed

+158
-36
lines changed

src/BuildingBlocks/TestBase/TestBase.cs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public class TestFixture<TEntryPoint> : IAsyncLifetime
4242
where TEntryPoint : class
4343
{
4444
private readonly WebApplicationFactory<TEntryPoint> _factory;
45-
private int Timeout => 120; // Second
45+
private int Timeout => 300; // Second
4646
private ITestHarness TestHarness => ServiceProvider?.GetTestHarness();
4747
private Action<IServiceCollection> TestRegistrationServices { get; set; }
4848
private PostgreSqlContainer PostgresTestcontainer;
@@ -140,6 +140,9 @@ public async Task InitializeAsync()
140140
if (ServiceProvider.GetService<ITestHarness>() is { } harness)
141141
{
142142
await harness.Start();
143+
144+
// Add a small delay to ensure harness is ready
145+
await Task.Delay(1000);
143146
}
144147
}
145148

@@ -298,11 +301,24 @@ private async Task StartTestContainerAsync()
298301
MongoDbTestContainer = TestContainers.MongoTestContainer();
299302
EventStoreDbTestContainer = TestContainers.EventStoreTestContainer();
300303

301-
await MongoDbTestContainer.StartAsync();
302-
await PostgresTestcontainer.StartAsync();
303-
await PostgresPersistTestContainer.StartAsync();
304+
// Start containers in parallel for speed
305+
await Task.WhenAll(
306+
MongoDbTestContainer.StartAsync(),
307+
PostgresTestcontainer.StartAsync(),
308+
PostgresPersistTestContainer.StartAsync(),
309+
EventStoreDbTestContainer.StartAsync()
310+
);
311+
312+
// Start RabbitMQ last and wait extra time
304313
await RabbitMqTestContainer.StartAsync();
305-
await EventStoreDbTestContainer.StartAsync();
314+
await Task.Delay(5000); // Give RabbitMQ extra time to initialize
315+
316+
// Verify RabbitMQ is healthy
317+
var healthCheck = await RabbitMqTestContainer.ExecAsync(new[] { "rabbitmq-diagnostics", "ping" });
318+
if (healthCheck.ExitCode != 0)
319+
{
320+
await Task.Delay(5000); // Wait more if not healthy
321+
}
306322
}
307323

308324
private async Task StopTestContainerAsync()
@@ -727,4 +743,4 @@ protected TestBase(
727743
}
728744

729745
public TestFixture<TEntryPoint, TWContext, TRContext> Fixture { get; }
730-
}
746+
}

src/BuildingBlocks/TestBase/TestContainers.cs

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -87,25 +87,16 @@ public static MongoDbContainer MongoTestContainer()
8787

8888
public static RabbitMqContainer RabbitMqTestContainer()
8989
{
90-
var builder = new RabbitMqBuilder()
90+
var baseBuilder = new RabbitMqBuilder()
9191
.WithUsername(RabbitMqContainerConfiguration.UserName)
9292
.WithPassword(RabbitMqContainerConfiguration.Password)
93+
.WithLabel("Key", "Value");
94+
95+
var builder = baseBuilder
9396
.WithImage(RabbitMqContainerConfiguration.ImageName)
9497
.WithName(RabbitMqContainerConfiguration.Name)
9598
.WithPortBinding(RabbitMqContainerConfiguration.ApiPort, true)
9699
.WithPortBinding(RabbitMqContainerConfiguration.Port, true)
97-
.WithWaitStrategy(
98-
Wait.ForUnixContainer()
99-
.UntilHttpRequestIsSucceeded(request =>
100-
request
101-
.ForPort((ushort)RabbitMqContainerConfiguration.ApiPort)
102-
.ForPath("/api/overview")
103-
.WithBasicAuthentication(
104-
RabbitMqContainerConfiguration.UserName,
105-
RabbitMqContainerConfiguration.Password
106-
)
107-
)
108-
)
109100
.Build();
110101

111102
return builder;
@@ -166,4 +157,4 @@ public sealed class EventStoreContainerOptions
166157
public int Port { get; set; } = 2113;
167158
public string ImageName { get; set; } = "eventstore/eventstore:latest";
168159
}
169-
}
160+
}

src/Services/Passenger/tests/IntegrationTest/Passenger/Features/CompleteRegisterPassengerTests.cs

Lines changed: 131 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,154 @@
22
using BuildingBlocks.TestBase;
33
using FluentAssertions;
44
using Integration.Test.Fakes;
5+
using Microsoft.Extensions.Logging;
56
using Passenger.Data;
67
using Xunit;
8+
using Xunit.Abstractions;
79

810
namespace Integration.Test.Passenger.Features;
911

1012
public class CompleteRegisterPassengerTests : PassengerIntegrationTestBase
1113
{
12-
1314
public CompleteRegisterPassengerTests(
14-
TestFixture<Program, PassengerDbContext, PassengerReadDbContext> integrationTestFactory) : base(integrationTestFactory)
15+
TestFixture<Program, PassengerDbContext, PassengerReadDbContext> integrationTestFactory,
16+
ITestOutputHelper outputHelper
17+
)
18+
: base(integrationTestFactory)
1519
{
20+
Fixture.Logger = Fixture.CreateLogger(outputHelper);
1621
}
1722

1823
[Fact]
1924
public async Task should_complete_register_passenger_and_update_to_db()
2025
{
2126
// Arrange
22-
var userCreated = new FakeUserCreated().Generate();
27+
Fixture.Logger?.LogInformation("Starting CompleteRegisterPassenger test at {Time}", DateTime.UtcNow);
28+
29+
try
30+
{
31+
// Generate and publish UserCreated event
32+
var userCreated = new FakeUserCreated().Generate();
33+
Fixture.Logger?.LogInformation(
34+
"Generated UserCreated event with PassportNumber: {PassportNumber}",
35+
userCreated.PassportNumber
36+
);
37+
38+
await Fixture.Publish(userCreated);
39+
Fixture.Logger?.LogInformation("Published UserCreated event");
40+
41+
// Wait for publishing with retry logic
42+
var published = await WaitForWithRetry(
43+
async () => await Fixture.WaitForPublishing<UserCreated>(),
44+
"publishing",
45+
maxRetries: 3
46+
);
47+
48+
published.Should().BeTrue("UserCreated event should be published to message broker");
49+
Fixture.Logger?.LogInformation("UserCreated event published successfully");
50+
51+
// Wait for consuming with retry logic
52+
var consumed = await WaitForWithRetry(
53+
async () => await Fixture.WaitForConsuming<UserCreated>(),
54+
"consuming",
55+
maxRetries: 5
56+
);
57+
58+
consumed.Should().BeTrue("UserCreated event should be consumed by the passenger service");
59+
Fixture.Logger?.LogInformation("UserCreated event consumed successfully");
60+
61+
// Small delay to ensure event processing is complete
62+
await Task.Delay(1000);
63+
64+
// Generate and send complete registration command
65+
var command = new FakeCompleteRegisterPassengerCommand(userCreated.PassportNumber).Generate();
66+
Fixture.Logger?.LogInformation(
67+
"Sending CompleteRegisterPassenger command for PassportNumber: {PassportNumber}",
68+
command.PassportNumber
69+
);
70+
71+
// Act
72+
var response = await Fixture.SendAsync(command);
73+
Fixture.Logger?.LogInformation("Received response for CompleteRegisterPassenger command");
74+
75+
// Assert with detailed logging
76+
response.Should().NotBeNull("Response should not be null");
77+
Fixture.Logger?.LogInformation("Response is not null");
78+
79+
response?.PassengerDto.Should().NotBeNull("PassengerDto should not be null");
80+
81+
response
82+
?.PassengerDto?.Name.Should()
83+
.Be(
84+
userCreated.Name,
85+
$"Passenger name should be '{userCreated.Name}' but was '{response?.PassengerDto?.Name}'"
86+
);
87+
88+
response
89+
?.PassengerDto?.PassportNumber.Should()
90+
.Be(
91+
command.PassportNumber,
92+
$"Passport number should be '{command.PassportNumber}' but was '{response?.PassengerDto?.PassportNumber}'"
93+
);
94+
95+
response
96+
?.PassengerDto?.PassengerType.ToString()
97+
.Should()
98+
.Be(
99+
command.PassengerType.ToString(),
100+
$"Passenger type should be '{command.PassengerType}' but was '{response?.PassengerDto?.PassengerType}'"
101+
);
102+
103+
response
104+
?.PassengerDto?.Age.Should()
105+
.Be(command.Age, $"Age should be {command.Age} but was {response?.PassengerDto?.Age}");
106+
107+
Fixture.Logger?.LogInformation("All assertions passed successfully");
108+
}
109+
catch (Exception ex)
110+
{
111+
Fixture.Logger?.LogError(ex, "Test failed with exception: {Message}", ex.Message);
112+
throw;
113+
}
114+
finally
115+
{
116+
Fixture.Logger?.LogInformation("Test completed at {Time}", DateTime.UtcNow);
117+
}
118+
}
119+
120+
private async Task<bool> WaitForWithRetry(Func<Task<bool>> waitCondition, string operation, int maxRetries = 3)
121+
{
122+
for (int i = 0; i < maxRetries; i++)
123+
{
124+
Fixture.Logger?.LogInformation(
125+
"Attempt {Attempt}/{MaxRetries} for {Operation}",
126+
i + 1,
127+
maxRetries,
128+
operation
129+
);
23130

24-
await Fixture.Publish(userCreated);
25-
(await Fixture.WaitForPublishing<UserCreated>()).Should().Be(true);
26-
(await Fixture.WaitForConsuming<UserCreated>()).Should().Be(true);
131+
var result = await waitCondition();
27132

28-
var command = new FakeCompleteRegisterPassengerCommand(userCreated.PassportNumber).Generate();
133+
if (result)
134+
{
135+
Fixture.Logger?.LogInformation("{Operation} successful on attempt {Attempt}", operation, i + 1);
136+
return true;
137+
}
29138

30-
// Act
31-
var response = await Fixture.SendAsync(command);
139+
if (i < maxRetries - 1)
140+
{
141+
var delaySeconds = (i + 1) * 2; // Exponential backoff: 2, 4, 6 seconds
142+
Fixture.Logger?.LogWarning(
143+
"{Operation} failed on attempt {Attempt}, waiting {Delay}s before retry",
144+
operation,
145+
i + 1,
146+
delaySeconds
147+
);
148+
await Task.Delay(TimeSpan.FromSeconds(delaySeconds));
149+
}
150+
}
32151

33-
// Assert
34-
response.Should().NotBeNull();
35-
response?.PassengerDto?.Name.Should().Be(userCreated.Name);
36-
response?.PassengerDto?.PassportNumber.Should().Be(command.PassportNumber);
37-
response?.PassengerDto?.PassengerType.ToString().Should().Be(command.PassengerType.ToString());
38-
response?.PassengerDto?.Age.Should().Be(command.Age);
152+
Fixture.Logger?.LogError("{Operation} failed after {MaxRetries} attempts", operation, maxRetries);
153+
return false;
39154
}
40-
}
155+
}

0 commit comments

Comments
 (0)