using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Data.SqlClient;
using SQLInsight.Collectors.Instance;
using SQLInsight.Core.Data;
using SQLInsight.Core.Instances;
using SQLInsight.Repository;
namespace SQLInsight.IntegrationTests;
/// tempdb and the version store as the least-privilege agent reads them.
[Collection(SqlServerTestGroup.Name)]
[Trait("Category", "Integration")]
public class TempdbTests(SqlServerFixture sql)
{
[Fact]
public async Task Space_version_store_and_the_session_filling_tempdb_are_read()
{
await using var user = new SqlConnection(new SqlConnectionStringBuilder(sql.SaConnectionString) { ApplicationName = "Rapport" }.ConnectionString);
await user.OpenAsync();
await using (var fill = new SqlCommand("CREATE TABLE #big (Id int, Pad char(4000)); INSERT #big SELECT TOP (3000) 1, 'x' FROM sys.all_objects a CROSS JOIN sys.all_objects b;", user))
{
await fill.ExecuteNonQueryAsync();
}
await using var session = await AgentSession.OpenAsync(sql);
var first = await session.CollectAsync(new TempdbCollector(sessionMegabytes: 1));
var second = await session.CollectAsync(new TempdbCollector(sessionMegabytes: 1), first);
Assert.True(first.SizeMegabytes > 0);
Assert.InRange(first.FreeMegabytes, 0, first.SizeMegabytes);
Assert.True(first.VersionStoreMegabytes >= 0);
var heavy = Assert.Single(first.TopSessions, s => s.ProgramName == "Rapport");
Assert.True(heavy.UsedMegabytes >= 10);
Assert.Equal(2, second.VersionStoreHistory.Count);
Assert.Equal(first.HeavySessionsSince[heavy.Key], second.HeavySessionsSince[heavy.Key]); // the start is kept
}
[Fact]
public async Task Instance_page_and_api_show_tempdb_with_logins_left_out()
{
var database = "SQLInsightTmp_" + Guid.NewGuid().ToString("N")[..8];
await sql.ExecuteAsSaAsync($"CREATE DATABASE [{database}];");
try
{
var repository = new InsightRepository(sql.DatabaseConnectionString(database));
await repository.MigrateAsync();
var now = DateTimeOffset.UtcNow;
var id = await repository.UpsertInstanceAsync("prod-sql01", new InstanceInfo
{
ServerName = "SQL01", Version = SqlServerVersion.Parse("16.0.4135.4"), ProductLevel = "RTM", Edition = "Standard Edition", EngineEdition = EngineEdition.Standard,
}, "SqlClient", false, now);
await repository.SaveCollectedAsync(id, "tempdb", new TempdbSnapshot
{
CapturedAt = now, SizeMegabytes = 8192, FreeMegabytes = 1024, VersionStoreMegabytes = 2048,
TopSessions = [new TempdbSession(70, now.AddHours(-1), 3000, @"KUNDE\anne", "SSMS", "PC01", "running")],
VersionGenerators = [new VersionGenerator("AXDB", 1800)],
});
await using var factory = new WebApplicationFactory().WithWebHostBuilder(b =>
{
b.UseEnvironment("Development");
b.UseSetting("SQLInsight:Repository:ConnectionString", sql.DatabaseConnectionString(database));
b.UseSetting("SQLInsight:Web:Authentication", "None");
});
var client = factory.CreateClient();
var page = await client.GetStringAsync("/instanser/prod-sql01");
var api = await client.GetStringAsync("/api/v1/instances/prod-sql01/tempdb");
Assert.Contains("tempdb lige nu", page, StringComparison.Ordinal);
Assert.Contains("AXDB", page, StringComparison.Ordinal);
Assert.Contains("Version store (MB)", page, StringComparison.Ordinal); // the graph with its explanation
Assert.Contains("\"versionStoreMegabytes\":2048", api, StringComparison.Ordinal);
Assert.DoesNotContain("anne", api, StringComparison.Ordinal);
Assert.Single(await repository.GetMetricSamplesAsync(id, Metrics.VersionStoreMegabytes, now.AddMinutes(-5), now.AddMinutes(5)));
}
finally
{
await sql.ExecuteAsSaAsync($"ALTER DATABASE [{database}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE [{database}];");
}
}
}