Some checks are pending
CI / Build og unit tests (push) Waiting to run
CI / Integration (mcr.microsoft.com/mssql/server:2017-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2019-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2022-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2025-latest) (push) Blocked by required conditions
- .NET 10 solution with Core, Connectivity, Rules, Contracts, Agent, Web and Hub - Capability model gating collectors and rules by SQL Server version (2000 and later); rules that cannot run are reported as not measurable, never as passed - Connectivity via Microsoft.Data.SqlClient with ODBC fallback for legacy instances, hardened monitoring session settings valid back to SQL Server 2000 - Support lifecycle rule (SQLI-VER-001) with lifecycle data shipped as a rule pack - Version-aware least-privilege permissions script, verified by integration tests against SQL Server in Docker (reads monitoring sources, cannot read customer data) - Forgejo Actions CI, contributing guide, code of conduct, issue templates, legacy version notes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E3EExwndy8Z22EK2Qpt6BK
94 lines
3.1 KiB
C#
94 lines
3.1 KiB
C#
using SQLInsight.Core.Findings;
|
|
using SQLInsight.Core.Instances;
|
|
using SQLInsight.Rules.Engine;
|
|
|
|
namespace SQLInsight.Rules.Tests;
|
|
|
|
public class RuleEngineTests
|
|
{
|
|
private sealed class StubRule(string id, IReadOnlyCollection<Capability> required, Func<RuleContext, RuleEvaluation> evaluate) : IRule
|
|
{
|
|
public int Calls { get; private set; }
|
|
public string Id => id;
|
|
public string Title => $"Stub {id}";
|
|
public IReadOnlyCollection<Capability> RequiredCapabilities => required;
|
|
|
|
public RuleEvaluation Evaluate(RuleContext context)
|
|
{
|
|
Calls++;
|
|
return evaluate(context);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Rule_missing_capabilities_is_not_measurable_and_never_runs()
|
|
{
|
|
var rule = new StubRule("QS", [Capability.QueryStore], _ => RuleEvaluation.Passed());
|
|
var engine = new RuleEngine([rule]);
|
|
|
|
var result = Assert.Single(engine.Evaluate(TestInstances.Context("11.0.7001.0")));
|
|
|
|
Assert.Equal(RuleOutcome.NotMeasurable, result.Outcome);
|
|
Assert.Equal([Capability.QueryStore], result.MissingCapabilities);
|
|
Assert.Contains("SQL Server 2012", result.Reason, StringComparison.Ordinal);
|
|
Assert.Equal(0, rule.Calls);
|
|
}
|
|
|
|
[Fact]
|
|
public void Rule_with_capabilities_runs()
|
|
{
|
|
var rule = new StubRule("QS", [Capability.QueryStore], _ => RuleEvaluation.Passed());
|
|
var engine = new RuleEngine([rule]);
|
|
|
|
var result = Assert.Single(engine.Evaluate(TestInstances.Context("16.0.4135.4")));
|
|
|
|
Assert.Equal(RuleOutcome.Passed, result.Outcome);
|
|
Assert.Equal(1, rule.Calls);
|
|
}
|
|
|
|
[Fact]
|
|
public void Throwing_rule_is_reported_as_error_and_does_not_stop_others()
|
|
{
|
|
var failing = new StubRule("A", [], _ => throw new InvalidOperationException("boom"));
|
|
var finding = new Finding
|
|
{
|
|
RuleId = "B",
|
|
Severity = Severity.Low,
|
|
Title = "t",
|
|
Explanation = "e",
|
|
Recommendation = "r",
|
|
};
|
|
var working = new StubRule("B", [], _ => RuleEvaluation.Found(finding));
|
|
var engine = new RuleEngine([failing, working]);
|
|
|
|
var results = engine.Evaluate(TestInstances.Context("16.0.4135.4"));
|
|
|
|
Assert.Equal(RuleOutcome.Error, results[0].Outcome);
|
|
Assert.Contains("boom", results[0].Reason, StringComparison.Ordinal);
|
|
Assert.Equal(RuleOutcome.Findings, results[1].Outcome);
|
|
Assert.Same(finding, Assert.Single(results[1].Findings));
|
|
}
|
|
|
|
[Fact]
|
|
public void Duplicate_rule_ids_are_rejected()
|
|
{
|
|
var a = new StubRule("SAME", [], _ => RuleEvaluation.Passed());
|
|
var b = new StubRule("same", [], _ => RuleEvaluation.Passed());
|
|
|
|
Assert.Throws<ArgumentException>(() => new RuleEngine([a, b]));
|
|
}
|
|
|
|
[Fact]
|
|
public void Found_requires_at_least_one_finding()
|
|
{
|
|
Assert.Throws<ArgumentException>(() => RuleEvaluation.Found());
|
|
}
|
|
|
|
[Fact]
|
|
public void Built_in_rule_ids_are_unique()
|
|
{
|
|
var engine = new RuleEngine(BuiltInRules.Create());
|
|
|
|
Assert.NotEmpty(engine.Evaluate(TestInstances.Context("16.0.4135.4")));
|
|
}
|
|
}
|