sqlinsight-pro/tests/SQLInsight.Rules.Tests/TempdbRuleTests.cs
Søren Eggert Lundsteen Olsen 4d18d20ab0 tempdb and version store (8c)
A five-minute collector reads tempdb space (free, version store, user and
internal objects, whether files can grow), the 'Version Store Size (KB)'
counter, the sessions using most tempdb, the oldest snapshot transaction
and, only when the version store is large, the databases generating
versions. Trend and heavy sessions survive restarts; used space and the
version store become metrics with explanation and assessment.

Rules SQLI-TEMP-001 (version store > 1 GB or steadily growing),
SQLI-TEMP-002 (nearly full and cannot grow) and SQLI-TEMP-003 (session
above 1 GB for 15 minutes), configurable under SQLInsight:Tempdb.
"tempdb lige nu" on the instance page; GET /api/v1/instances/{name}/tempdb.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 10:42:38 +02:00

51 lines
2.7 KiB
C#

using SQLInsight.Core.Data;
using SQLInsight.Core.Findings;
using SQLInsight.Rules.Engine;
using SQLInsight.Rules.Instance;
using static SQLInsight.Rules.Tests.TestInstances;
namespace SQLInsight.Rules.Tests;
public class TempdbRuleTests
{
private static RuleResult Run(IRule rule, RuleContext context) => Assert.Single(new RuleEngine([rule]).Evaluate(context));
private static TempdbSnapshot Tempdb(double versionStore = 100, double free = 5000, bool canGrow = true, IReadOnlyList<double>? history = null) => new()
{
CapturedAt = Now, SizeMegabytes = 10000, FreeMegabytes = free, VersionStoreMegabytes = versionStore, CanGrow = canGrow,
VersionStoreHistory = history ?? [versionStore],
OldestSnapshotTransaction = new SnapshotTransaction(61, 7200, @"KUNDE\anne", "Ax32.exe"),
VersionGenerators = [new VersionGenerator("AXDB", 900)],
};
[Fact]
public void A_large_or_steadily_growing_version_store_is_found()
{
Assert.Equal(RuleOutcome.Passed, Run(new VersionStoreRule(), With(Tempdb(500))).Outcome);
var large = Assert.Single(Run(new VersionStoreRule(), With(Tempdb(2000))).Findings);
Assert.Contains(large.Evidence, e => e.Name == "Databaser, der laver versioner" && e.Value.Contains("AXDB", StringComparison.Ordinal));
Assert.True(large.Evidence.Single(e => e.Name == "Dens login og program").Sensitive);
Assert.Equal(RuleOutcome.Findings, Run(new VersionStoreRule(), With(Tempdb(600, history: [100, 200, 300, 400, 500, 600]))).Outcome);
Assert.False(TempdbAnalysis.IsGrowing([100, 200, 150, 400, 500, 600]));
}
[Theory]
[InlineData(500, false, RuleOutcome.Findings)]
[InlineData(500, true, RuleOutcome.Passed)] // it can still grow
[InlineData(2000, false, RuleOutcome.Passed)] // 20 % free
public void Tempdb_nearly_full_only_when_it_cannot_grow(double free, bool canGrow, RuleOutcome expected) =>
Assert.Equal(expected, Run(new TempdbFullRule(), With(Tempdb(free: free, canGrow: canGrow))).Outcome);
[Fact]
public void A_session_heavy_for_fifteen_minutes_is_found()
{
var session = new TempdbSession(70, Now.AddHours(-1), 3000, "anne", "SSMS", "PC01", "running");
var first = TempdbAnalysis.Advance(null, Tempdb() with { CapturedAt = Now.AddMinutes(-20), TopSessions = [session] });
var now = TempdbAnalysis.Advance(first, Tempdb() with { TopSessions = [session] });
Assert.Equal(RuleOutcome.Passed, Run(new TempdbSessionRule(), With(first)).Outcome);
var finding = Assert.Single(Run(new TempdbSessionRule(), With(now)).Findings);
Assert.Equal(Severity.Medium, finding.Severity);
Assert.True(finding.Evidence.Single(e => e.Name == "Login").Sensitive);
}
}