using Xunit; using System.Collections.Immutable; using StellaOps.Policy.Engine.Domain; using StellaOps.Policy.Engine.Services; using StellaOps.TestKit; namespace StellaOps.Policy.Engine.Tests; public sealed class PolicyRuntimeEvaluatorTests { [Trait("Category", TestCategories.Unit)] [Fact] public async Task EvaluateAsync_ReturnsDeterministicDecisionAndCaches() { var repo = new InMemoryPolicyPackRepository(TimeProvider.System); await repo.StoreBundleAsync( "pack-1", 1, new PolicyBundleRecord( Digest: "sha256:abc", Signature: "sig:sha256:abc", Size: 4, CreatedAt: DateTimeOffset.UnixEpoch, Payload: new byte[] { 1, 2, 3, 4 }.ToImmutableArray()), TestContext.Current.CancellationToken); var evaluator = new PolicyRuntimeEvaluator(repo); var request = new PolicyEvaluationRequest("pack-1", 1, "subject-a"); var first = await evaluator.EvaluateAsync(request, TestContext.Current.CancellationToken); var second = await evaluator.EvaluateAsync(request, TestContext.Current.CancellationToken); Assert.Equal(first.Decision, second.Decision); Assert.False(first.Cached); Assert.True(second.Cached); Assert.Equal("pack-1", first.PackId); Assert.Equal(1, first.Version); } [Trait("Category", TestCategories.Unit)] [Fact] public async Task EvaluateAsync_ThrowsWhenBundleMissing() { var evaluator = new PolicyRuntimeEvaluator(new InMemoryPolicyPackRepository(TimeProvider.System)); var request = new PolicyEvaluationRequest("pack-x", 1, "subject-a"); await Assert.ThrowsAsync(() => evaluator.EvaluateAsync(request, TestContext.Current.CancellationToken)); } }