diff --git a/src/Policy/__Libraries/StellaOps.Policy/Gates/BudgetThresholdNotifier.cs b/src/Policy/__Libraries/StellaOps.Policy/Gates/BudgetThresholdNotifier.cs index 6ef8c08a0..a2f3dfb2d 100644 --- a/src/Policy/__Libraries/StellaOps.Policy/Gates/BudgetThresholdNotifier.cs +++ b/src/Policy/__Libraries/StellaOps.Policy/Gates/BudgetThresholdNotifier.cs @@ -18,6 +18,7 @@ public sealed class BudgetThresholdNotifier { private readonly INotifyEventPublisher _publisher; private readonly ILogger _logger; + private readonly TimeProvider _timeProvider; /// /// Thresholds for different budget status levels. @@ -37,10 +38,12 @@ public sealed class BudgetThresholdNotifier /// public BudgetThresholdNotifier( INotifyEventPublisher publisher, - ILogger logger) + ILogger logger, + TimeProvider? timeProvider = null) { _publisher = publisher ?? throw new ArgumentNullException(nameof(publisher)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _timeProvider = timeProvider ?? TimeProvider.System; } /// @@ -73,7 +76,7 @@ public sealed class BudgetThresholdNotifier { if (budget.Status >= BudgetStatus.Yellow) { - var payload = CreatePayload(budget, "warning"); + var payload = CreatePayload(budget, "warning", _timeProvider); await _publisher.PublishAsync( BudgetEventKinds.PolicyBudgetWarning, tenantId, @@ -95,7 +98,7 @@ public sealed class BudgetThresholdNotifier string tenantId, CancellationToken ct = default) { - var payload = CreatePayload(budget, "exceeded"); + var payload = CreatePayload(budget, "exceeded", _timeProvider); await _publisher.PublishAsync( BudgetEventKinds.PolicyBudgetExceeded, tenantId, @@ -118,7 +121,7 @@ public sealed class BudgetThresholdNotifier ? BudgetEventKinds.PolicyBudgetExceeded : BudgetEventKinds.PolicyBudgetWarning; - var payload = CreatePayload(after, after.Status.ToString().ToLowerInvariant()); + var payload = CreatePayload(after, after.Status.ToString().ToLowerInvariant(), _timeProvider); payload["previousStatus"] = before.Status.ToString().ToLowerInvariant(); await _publisher.PublishAsync(eventKind, tenantId, payload, ct); @@ -130,7 +133,7 @@ public sealed class BudgetThresholdNotifier after.Status); } - private static JsonObject CreatePayload(RiskBudget budget, string severity) + private static JsonObject CreatePayload(RiskBudget budget, string severity, TimeProvider timeProvider) { return new JsonObject { @@ -144,7 +147,7 @@ public sealed class BudgetThresholdNotifier ["percentageUsed"] = budget.PercentageUsed, ["status"] = budget.Status.ToString().ToLowerInvariant(), ["severity"] = severity, - ["timestamp"] = DateTimeOffset.UtcNow.ToString("O") + ["timestamp"] = timeProvider.GetUtcNow().ToString("O") }; } } diff --git a/src/Policy/__Libraries/StellaOps.Policy/Gates/EarnedCapacityReplenishment.cs b/src/Policy/__Libraries/StellaOps.Policy/Gates/EarnedCapacityReplenishment.cs index 72da73a83..864bbeba6 100644 --- a/src/Policy/__Libraries/StellaOps.Policy/Gates/EarnedCapacityReplenishment.cs +++ b/src/Policy/__Libraries/StellaOps.Policy/Gates/EarnedCapacityReplenishment.cs @@ -16,6 +16,7 @@ public sealed class EarnedCapacityEvaluator private readonly IPerformanceMetricsStore _metricsStore; private readonly IBudgetStore _budgetStore; private readonly EarnedCapacityOptions _options; + private readonly TimeProvider _timeProvider; /// /// Create a new earned capacity evaluator. @@ -23,11 +24,13 @@ public sealed class EarnedCapacityEvaluator public EarnedCapacityEvaluator( IPerformanceMetricsStore metricsStore, IBudgetStore budgetStore, - EarnedCapacityOptions? options = null) + EarnedCapacityOptions? options = null, + TimeProvider? timeProvider = null) { _metricsStore = metricsStore ?? throw new ArgumentNullException(nameof(metricsStore)); _budgetStore = budgetStore ?? throw new ArgumentNullException(nameof(budgetStore)); _options = options ?? new EarnedCapacityOptions(); + _timeProvider = timeProvider ?? TimeProvider.System; } /// @@ -116,7 +119,7 @@ public sealed class EarnedCapacityEvaluator var updatedBudget = budget with { Allocated = budget.Allocated + additionalPoints, - UpdatedAt = DateTimeOffset.UtcNow + UpdatedAt = _timeProvider.GetUtcNow() }; await _budgetStore.UpdateAsync(updatedBudget, ct);