| | | 1 | | using AsiBackbone.Core.Constraints; |
| | | 2 | | using AsiBackbone.Core.Decisions; |
| | | 3 | | using AsiBackbone.Core.Evaluation; |
| | | 4 | | |
| | | 5 | | namespace AsiBackbone.Testing.Contracts; |
| | | 6 | | |
| | | 7 | | /// <summary> |
| | | 8 | | /// Reusable contract fixture for <see cref="IAsiBackbonePolicyEvaluator{TContext}" /> implementations. |
| | | 9 | | /// </summary> |
| | | 10 | | /// <typeparam name="TContext">The framework-neutral evaluation context type.</typeparam> |
| | | 11 | | public abstract class AsiBackbonePolicyEvaluatorContract<TContext> |
| | | 12 | | where TContext : IAsiBackboneConstraintEvaluationContext |
| | | 13 | | { |
| | | 14 | | /// <summary> |
| | | 15 | | /// Creates the evaluator implementation under test. |
| | | 16 | | /// </summary> |
| | | 17 | | /// <returns>The evaluator implementation to validate.</returns> |
| | | 18 | | protected abstract IAsiBackbonePolicyEvaluator<TContext> CreateEvaluator(); |
| | | 19 | | |
| | | 20 | | /// <summary> |
| | | 21 | | /// Creates the context supplied to the evaluator implementation under test. |
| | | 22 | | /// </summary> |
| | | 23 | | /// <returns>The evaluation context to validate with.</returns> |
| | | 24 | | protected abstract TContext CreateEvaluationContext(); |
| | | 25 | | |
| | | 26 | | /// <summary> |
| | | 27 | | /// Verifies that the evaluator returns a safe, non-null decision and preserves supplied decision telemetry. |
| | | 28 | | /// </summary> |
| | | 29 | | /// <param name="cancellationToken">A token that can cancel the contract validation.</param> |
| | | 30 | | /// <returns>The verified governance decision.</returns> |
| | | 31 | | public async ValueTask<GovernanceDecision> VerifyEvaluatorReturnsSafeDecisionAsync(CancellationToken cancellationTok |
| | | 32 | | { |
| | 14 | 33 | | IAsiBackbonePolicyEvaluator<TContext> evaluator = CreateEvaluator() |
| | 14 | 34 | | ?? throw new AsiBackboneContractViolationException("Policy evaluator contract must provide an evaluator inst |
| | 12 | 35 | | TContext context = CreateEvaluationContext() |
| | 12 | 36 | | ?? throw new AsiBackboneContractViolationException("Policy evaluator contract must provide an evaluation con |
| | | 37 | | |
| | | 38 | | try |
| | | 39 | | { |
| | 10 | 40 | | GovernanceDecision decision = await evaluator.EvaluateAsync(context, cancellationToken).ConfigureAwait(false |
| | 4 | 41 | | return AsiBackboneDecisionContract.VerifyTelemetryFromContext(decision, context, "Policy evaluator decision" |
| | | 42 | | } |
| | 2 | 43 | | catch (OperationCanceledException) |
| | | 44 | | { |
| | 2 | 45 | | throw; |
| | | 46 | | } |
| | 4 | 47 | | catch (AsiBackboneContractViolationException) |
| | | 48 | | { |
| | 4 | 49 | | throw; |
| | | 50 | | } |
| | 2 | 51 | | catch (Exception exception) |
| | | 52 | | { |
| | 2 | 53 | | throw new AsiBackboneContractViolationException( |
| | 2 | 54 | | "Policy evaluator implementations must not fail open or bypass the policy pipeline by throwing during no |
| | 2 | 55 | | exception); |
| | | 56 | | } |
| | 2 | 57 | | } |
| | | 58 | | } |