diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d7d4fa51..e6b49668 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,13 +1,16 @@ name: ci -# Trigger events as per Git Flow documentation +# Trigger events optimized to avoid duplicate runs +# - pull_request: Run checks on all PRs (primary validation) +# - push to main: Run checks after merge (final validation) +# - push tags: Trigger release workflow +# Note: Removed push trigger for develop to avoid duplicate runs with pull_request on: push: branches: - - main - - develop + - main # Only run on main after PR merge tags: - - 'v*' + - 'v*' # Trigger release on version tags pull_request: branches: - main diff --git a/src/StarGate.Server/Handlers/ShippingProcessHandler.cs b/src/StarGate.Server/Handlers/ShippingProcessHandler.cs index 05332a8b..da2a74bc 100644 --- a/src/StarGate.Server/Handlers/ShippingProcessHandler.cs +++ b/src/StarGate.Server/Handlers/ShippingProcessHandler.cs @@ -10,10 +10,19 @@ namespace StarGate.Server.Handlers; public class ShippingProcessHandler : IProcessHandler { private readonly ILogger _logger; - - public ShippingProcessHandler(ILogger logger) + private readonly Random _random; + + /// + /// Initializes a new instance of the class. + /// + /// Logger instance. + /// Optional seed for Random. Use for deterministic testing. Default: null (time-based). + public ShippingProcessHandler( + ILogger logger, + int? randomSeed = null) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _random = randomSeed.HasValue ? new Random(randomSeed.Value) : new Random(); } public string ProcessType => "shipping"; @@ -166,8 +175,7 @@ private async Task CalculateShippingCostAsync( }; // Add random variation - var random = new Random(); - var variation = (decimal)(random.NextDouble() * 5.0); + var variation = (decimal)(_random.NextDouble() * 5.0); return baseCost + variation; } @@ -186,8 +194,7 @@ private async Task ReserveCarrierCapacityAsync( shipmentId); // Simulate capacity check (could fail with probability) - var random = new Random(); - if (random.Next(100) < 2) // 2% failure rate + if (_random.Next(100) < 2) // 2% failure rate { throw new HttpRequestException($"Carrier {carrier} has no available capacity"); } diff --git a/tests/StarGate.Server.Tests/Handlers/ShippingProcessHandlerTests.cs b/tests/StarGate.Server.Tests/Handlers/ShippingProcessHandlerTests.cs index 2f75dded..3fb70733 100644 --- a/tests/StarGate.Server.Tests/Handlers/ShippingProcessHandlerTests.cs +++ b/tests/StarGate.Server.Tests/Handlers/ShippingProcessHandlerTests.cs @@ -8,11 +8,16 @@ namespace StarGate.Server.Tests.Handlers; public class ShippingProcessHandlerTests { + // Use deterministic seed for consistent test results + // Production code uses time-based random (no seed) + private const int TestRandomSeed = 42; private readonly ShippingProcessHandler _handler; public ShippingProcessHandlerTests() { - _handler = new ShippingProcessHandler(NullLogger.Instance); + _handler = new ShippingProcessHandler( + NullLogger.Instance, + randomSeed: TestRandomSeed); } [Fact] @@ -179,9 +184,7 @@ public async Task ExecuteAsync_Should_AcceptValidCarriers(string carrier) } }; - // Act & Assert - // Note: May occasionally fail due to simulated random failures - // In production tests, you'd mock external dependencies + // Act & Assert - Deterministic with seed=42 await _handler.ExecuteAsync(context); } @@ -261,12 +264,8 @@ public async Task ExecuteAsync_Should_CompleteSuccessfully_WithValidData() } }; - // Act - // Note: May occasionally fail due to simulated random failures - // In production tests, you'd mock external dependencies + // Act & Assert - Deterministic with seed=42 await _handler.ExecuteAsync(context); - - // Assert - no exception thrown } [Fact] @@ -279,4 +278,29 @@ public void Constructor_Should_ThrowArgumentNullException_WhenLoggerIsNull() act.Should().Throw() .WithParameterName("logger"); } + + [Fact] + public void Constructor_Should_AcceptRandomSeed() + { + // Act + var handler = new ShippingProcessHandler( + NullLogger.Instance, + randomSeed: 123); + + // Assert + handler.Should().NotBeNull(); + handler.ProcessType.Should().Be("shipping"); + } + + [Fact] + public void Constructor_Should_UseTimeBasedRandom_WhenSeedNotProvided() + { + // Act + var handler = new ShippingProcessHandler( + NullLogger.Instance); + + // Assert + handler.Should().NotBeNull(); + handler.ProcessType.Should().Be("shipping"); + } }