sqlinsight-pro/tests/SQLInsight.Servers.Tests/LocalCimTests.cs
Søren Eggert Lundsteen Olsen 7082b278e3 Collection: Windows servers over CIM (WS-Man, DCOM fallback) and synthetic check runners
New project SQLInsight.Servers:
- CimWindowsServerSource (Microsoft.Management.Infrastructure, the API behind
  Get-CimInstance): WS-Man first, DCOM if that fails, a local session for the
  agent's own computer, as the agent's identity. Only SELECT queries (CimQueries)
  and Task Scheduler's read-only GetInfo. CPU and paging from raw counters, disks
  (Win32_Volume, Win32_LogicalDisk fallback), services, scheduled tasks, and the
  System/Application logs through the Event Log service (MS-EVEN6, XPath filter on
  the server) with Win32_NTLogEvent as fallback.
- ServerErrors: access denied, missing namespace, RPC/WinRM unreachable and
  timeouts become "ikke målbar" reasons that name the missing right and the grant
  script; never local administrator.
- WindowsServerTester: tries every area once for the web UI's test.
- SyntheticCheckRunner: TCP, HTTP(S) with expected status/text and TLS certificate
  expiry (also for refused certificates), SQL login + read-only query (re-validated,
  in a transaction that is always rolled back), DNS, and the Dynamics AX logon:
  AOS port, then a logon through the .NET Business Connector in a separate Windows
  PowerShell process with a timeout when it is installed; otherwise the result
  says clearly that only the port was tested.

Tests: error mapping, queries, AX command/parsing, runners against local TCP and
HTTP(S) servers with a self-signed certificate, the CIM source against this
computer, and the SQL check against the test instance.

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

93 lines
4.1 KiB
C#

using SQLInsight.Core.Servers;
using SQLInsight.Servers;
namespace SQLInsight.Servers.Tests;
/// <summary>
/// The CIM implementation against this computer (a local CIM session, as for the agent's own server). Remote access over
/// WS-Man/DCOM with least privilege cannot be tested here; it needs a domain with a second server.
/// </summary>
[Trait("Category", "Windows")]
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
public class LocalCimTests
{
private static async Task<IWindowsServerSession?> ConnectAsync()
{
if (!OperatingSystem.IsWindows())
{
return null;
}
return await new CimWindowsServerSource(new ServerConnectionOptions()).ConnectAsync(Environment.MachineName, CancellationToken.None);
}
[Fact]
public async Task Reads_os_performance_disks_services_events_and_tasks()
{
using var session = await ConnectAsync();
if (session is null)
{
return;
}
var os = await session.GetOperatingSystemAsync(CancellationToken.None);
var first = await session.GetPerformanceAsync(DateTimeOffset.UtcNow, CancellationToken.None);
await Task.Delay(1500);
var second = await session.GetPerformanceAsync(DateTimeOffset.UtcNow, CancellationToken.None);
var sample = ServerPerformanceMath.Sample(first, second, os);
var disks = await session.GetDisksAsync(CancellationToken.None);
var services = await session.GetServicesAsync(CancellationToken.None);
var service = await session.GetServiceAsync(services[0].Name, CancellationToken.None);
var events = await session.GetEventsAsync(DateTimeOffset.UtcNow.AddDays(-7), 200, CancellationToken.None);
var tasks = await session.GetTasksAsync(name => !TaskResults.IsMicrosoftTask(name), 3, CancellationToken.None);
Assert.Equal("lokal", session.Protocol);
Assert.Contains("Windows", os.Caption, StringComparison.OrdinalIgnoreCase);
Assert.True(os.LastBootUpTime < DateTimeOffset.UtcNow);
Assert.True(os.TotalMemoryMb > 0);
Assert.True(os.LogicalProcessors > 0);
Assert.InRange(sample.CpuPercent!.Value, 0, 100);
Assert.True(sample.AvailableMb > 0);
Assert.InRange(sample.CommitPercent!.Value, 0, 100);
Assert.NotEmpty(disks);
Assert.All(disks, d => Assert.False(d.Volume.StartsWith(@"\\?\", StringComparison.Ordinal)));
Assert.All(disks, d => Assert.InRange(d.FreeGb, 0, d.SizeGb));
Assert.Contains(services, s => s.IsRunning && s.IsAutomatic);
Assert.Equal(services[0].Name, service!.Name);
Assert.Null(await session.GetServiceAsync("SQLInsight-findes-ikke", CancellationToken.None));
Assert.Equal("Event Log (RPC)", events.Method);
Assert.All(events.Entries, e => Assert.InRange(e.Level, 1, 2));
Assert.True(tasks.Visible > 0);
Assert.All(tasks.Watched, t => Assert.False(TaskResults.IsMicrosoftTask(t.FullName)));
}
[Fact]
public async Task The_test_reports_every_area()
{
if (!OperatingSystem.IsWindows())
{
return;
}
var result = await WindowsServerTester.TestAsync(new CimWindowsServerSource(new ServerConnectionOptions()), "localhost", "test", DateTimeOffset.UtcNow, CancellationToken.None);
Assert.True(result.Reachable, result.Error);
Assert.Equal(ServerArea.All, result.Areas.Select(a => a.Area));
Assert.All(result.Areas, a => Assert.True(a.Ok, a.Detail));
}
[Fact]
public async Task An_unknown_host_is_unreachable_with_a_reason()
{
if (!OperatingSystem.IsWindows())
{
return;
}
var source = new CimWindowsServerSource(new ServerConnectionOptions { OperationTimeout = TimeSpan.FromSeconds(5) });
var error = await Assert.ThrowsAsync<ServerAccessException>(() => source.ConnectAsync("sqlinsight-findes-ikke.invalid", CancellationToken.None));
Assert.Equal(ServerAccessProblem.Unreachable, error.Problem);
Assert.Contains("sqlinsight-findes-ikke.invalid", error.Message, StringComparison.Ordinal);
}
}