Some checks failed
deploy community / deploy (push) Successful in 15s
deploy hub / deploy (push) Successful in 19s
CI / Build og unit tests (push) Successful in 7s
CI / MSI-installer (push) Successful in 17s
CI / Integration (mcr.microsoft.com/mssql/server:2017-latest) (push) Has been cancelled
CI / Integration (mcr.microsoft.com/mssql/server:2019-latest) (push) Has been cancelled
CI / Integration (mcr.microsoft.com/mssql/server:2022-latest) (push) Has been cancelled
CI / Integration (mcr.microsoft.com/mssql/server:2025-latest) (push) Has been cancelled
Registers 1.3's SQL in SqlScriptSources (DatabaseDiscovery: databases 2005/2000 and the Dynamics AX signature per database; PermissionCheck: login/sysadmin, the HAS_PERMS_BY_NAME checks for 2005-2012, 2014-2019/MI and 2022+, databases without access) and adds _collectors/DatabaseDiscovery.sql and PermissionCheck.sql with Danish review headers. The constants are renamed *Sql and the login query moved to PermissionCheck.WhoSql so the registry test finds them. The scripts of the collectors that now skip unchosen databases say so (their SQL is unchanged). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
99 lines
4.9 KiB
C#
99 lines
4.9 KiB
C#
using System.Text.RegularExpressions;
|
|
using SQLInsight.Collectors.Discovery;
|
|
using SQLInsight.Core.Instances;
|
|
|
|
namespace SQLInsight.Collectors.Tests;
|
|
|
|
/// <summary>Database discovery and the permission check: version-guarded SQL and what is asked for on each version.</summary>
|
|
public sealed class DiscoveryTests
|
|
{
|
|
private static InstanceInfo Instance(string version, EngineEdition edition = EngineEdition.Standard) => new()
|
|
{
|
|
ServerName = "SQL01", Version = SqlServerVersion.Parse(version), Edition = "Standard Edition", EngineEdition = edition,
|
|
};
|
|
|
|
[Theory]
|
|
[InlineData(3, 10, "3.0")]
|
|
[InlineData(3, 19, "4.0+")]
|
|
[InlineData(3, null, "4.0+")]
|
|
[InlineData(2, 10, null)]
|
|
[InlineData(0, null, null)]
|
|
public void Dynamics_ax_is_recognised_by_its_three_system_tables_and_the_recid_type(int tables, int? precision, string? expected) =>
|
|
Assert.Equal(expected, DatabaseDiscovery.DynamicsAxVersion(tables, precision));
|
|
|
|
[Fact]
|
|
public void Dynamics_ax_detection_uses_three_part_names_and_catalog_views_by_version()
|
|
{
|
|
var modern = DatabaseDiscovery.DynamicsAxSql("AX]30", SqlServerVersion.Parse("9.0.5000.0"));
|
|
var legacy = DatabaseDiscovery.DynamicsAxSql("AX30", SqlServerVersion.Parse("8.0.2039.0"));
|
|
|
|
Assert.Contains("[AX]]30].sys.tables", modern, StringComparison.Ordinal);
|
|
Assert.DoesNotContain("USE ", modern, StringComparison.OrdinalIgnoreCase);
|
|
Assert.Contains("[AX30].dbo.sysobjects", legacy, StringComparison.Ordinal);
|
|
Assert.DoesNotContain("sys.", legacy, StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void Sql_server_2008_r2_is_checked_for_view_server_state_and_a_user_in_each_database()
|
|
{
|
|
var checks = PermissionCheck.ChecksFor(Instance("10.50.6000.34")).Select(c => c.Name).ToList();
|
|
|
|
Assert.Contains("VIEW SERVER STATE", checks);
|
|
Assert.Contains("VIEW ANY DEFINITION", checks);
|
|
Assert.DoesNotContain("CONNECT ANY DATABASE", checks);
|
|
Assert.DoesNotContain("VIEW SERVER PERFORMANCE STATE", checks);
|
|
Assert.Contains("SELECT ON msdb.dbo.backupset", checks);
|
|
}
|
|
|
|
[Fact]
|
|
public void Sql_server_2022_is_checked_for_the_granular_rights_and_managed_instance_like_2019()
|
|
{
|
|
var sql2022 = PermissionCheck.ChecksFor(Instance("16.0.4135.4")).Select(c => c.Name).ToList();
|
|
var managed = PermissionCheck.ChecksFor(Instance("12.0.2000.8", EngineEdition.AzureSqlManagedInstance)).Select(c => c.Name).ToList();
|
|
|
|
Assert.Contains("VIEW SERVER PERFORMANCE STATE", sql2022);
|
|
Assert.Contains("VIEW SERVER SECURITY STATE", sql2022);
|
|
Assert.DoesNotContain("VIEW SERVER STATE", sql2022);
|
|
Assert.Contains("CONNECT ANY DATABASE", sql2022);
|
|
Assert.Contains("VIEW SERVER STATE", managed);
|
|
Assert.Contains("CONNECT ANY DATABASE", managed);
|
|
Assert.False(PermissionCheck.ChecksFor(Instance("16.0.4135.4")).Single(c => c.Name == "ALTER TRACE").Required);
|
|
}
|
|
|
|
/// <summary>2008+ constructs that make a batch fail on 2005 (as in Sql2005CompatibilityTests).</summary>
|
|
private static readonly Regex[] Sql2008Only =
|
|
[
|
|
new(@"DECLARE\s+@\w+\s+\w+(\s*\([\d\s,]+\))?\s*=", RegexOptions.IgnoreCase),
|
|
new(@"\bMERGE\s", RegexOptions.IgnoreCase),
|
|
new(@"\b(CONCAT|IIF|CHOOSE|FORMAT|TRY_CONVERT|TRY_CAST|STRING_AGG|STRING_SPLIT)\s*\(", RegexOptions.IgnoreCase),
|
|
new(@"\bOFFSET\s+\S+\s+ROWS\b", RegexOptions.IgnoreCase),
|
|
new(@"\bVALUES\s*\([^)]*\)\s*,\s*\(", RegexOptions.IgnoreCase),
|
|
];
|
|
|
|
[Fact]
|
|
public void Discovery_and_permission_sql_runs_on_sql_server_2005()
|
|
{
|
|
var sql2005 = Instance("9.0.5000.0");
|
|
var batches = new[]
|
|
{
|
|
DatabaseDiscovery.Databases2005Sql, DatabaseDiscovery.Databases2000Sql, DatabaseDiscovery.DynamicsAxSql("AX30", sql2005.Version),
|
|
PermissionCheck.BuildSql(PermissionCheck.ChecksFor(sql2005)), PermissionCheck.DatabasesWithoutAccessSql,
|
|
};
|
|
|
|
Assert.All(batches, sql => Assert.DoesNotContain(Sql2008Only, p => p.IsMatch(sql)));
|
|
Assert.All(batches, sql => Assert.DoesNotContain("PXI_BATCHMONITORTABLE", sql, StringComparison.OrdinalIgnoreCase));
|
|
Assert.DoesNotContain("sys.", DatabaseDiscovery.Databases2000Sql, StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void Collector_context_includes_every_database_without_a_selection()
|
|
{
|
|
var context = new CollectorContext(null!, Instance("16.0.4135.4"), InstanceCapabilities.From(Instance("16.0.4135.4")), DateTimeOffset.UtcNow, null, CancellationToken.None);
|
|
var chosen = context with { Databases = new Core.Configuration.DatabaseSelection(false, ["Sales"], [], []) };
|
|
|
|
Assert.True(context.IncludesDatabase("Anything"));
|
|
Assert.True(chosen.IncludesDatabase("Sales"));
|
|
Assert.True(chosen.IncludesDatabase("msdb"));
|
|
Assert.False(chosen.IncludesDatabase("Anything"));
|
|
}
|
|
}
|