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}];"); } } }