ci: expand Windows feature fixtures and test Server 2022 (#2503)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
This commit is contained in:
Jan-Otto Kröpke
2026-10-07 09:15:58 +02:00
committed by GitHub
co-authored by Claude Opus 5.5
parent 72e10af92d
commit 56137ffdc1
16 changed files with 862 additions and 356 deletions
+96
View File
@@ -0,0 +1,96 @@
# Install a real Database Engine instance; LocalDB does not expose server counters.
$ErrorActionPreference = "Stop"
$mediaDir = Join-Path $env:RUNNER_TEMP "sql-server"
New-Item -ItemType Directory -Force -Path $mediaDir | Out-Null
$setupDir = Join-Path $mediaDir "setup"
# CI caches the extracted setup files; download and extract only on a cache miss.
if (-not (Test-Path (Join-Path $setupDir "setup.exe"))) {
$installer = Join-Path $mediaDir "SQL2025-SSEI-Expr.exe"
# Microsoft download endpoints occasionally reset hosted runner connections.
curl.exe --fail --location --retry 5 --retry-all-errors --silent --show-error --output $installer `
"https://download.microsoft.com/download/ffd82b4c-9955-47c0-8efe-6290f7795cf6/SQL2025-SSEI-Expr.exe"
if ($LASTEXITCODE -ne 0) { throw "SQL Server bootstrapper download failed" }
$expectedHash = "fa7e1fabc9a2e9c9cdab0d1512bcb30d2949133147db057ac530f510e5270680"
if ((Get-FileHash $installer -Algorithm SHA256).Hash -ne $expectedHash) {
throw "SQL Server bootstrapper SHA256 mismatch"
}
$media = Join-Path $mediaDir "SQLEXPR_x64_ENU.exe"
foreach ($attempt in 1..3) {
$download = Start-Process $installer -Wait -PassThru `
-ArgumentList "/ACTION=Download", "/MEDIATYPE=Core", "/QUIET", "/MEDIAPATH=$mediaDir"
if ($download.ExitCode -eq 0 -and (Test-Path $media)) { break }
if ($attempt -eq 3) { throw "SQL Server media download failed: $($download.ExitCode)" }
Write-Warning "SQL Server media download attempt $attempt failed: $($download.ExitCode)"
Start-Sleep -Seconds 10
}
$extract = Start-Process $media -Wait -PassThru `
-ArgumentList "/Q", "/X:$setupDir"
if ($extract.ExitCode -ne 0) {
throw "SQL Server media extraction failed: $($extract.ExitCode)"
}
}
# Azure runners can expose sectors larger than SQL Server's supported 4 KB.
# Keep every instance file on a disk with a known, compatible sector size.
Import-Module Hyper-V
$diskPath = Join-Path $env:RUNNER_TEMP "sql-server.vhdx"
New-VHD -Path $diskPath -Dynamic -SizeBytes 8GB `
-LogicalSectorSizeBytes 512 -PhysicalSectorSizeBytes 4096 | Out-Null
. (Join-Path $PSScriptRoot "vhd-lock.ps1")
$volume = Invoke-WithVhdLock {
$disk = Mount-VHD -Path $diskPath -PassThru | Get-Disk
if ($disk.PhysicalSectorSize -gt 4096) {
throw "SQL Server fixture disk exposes unsupported physical sectors"
}
$disk | Initialize-Disk -PartitionStyle GPT -PassThru |
New-Partition -UseMaximumSize -AssignDriveLetter |
Format-Volume -FileSystem NTFS -NewFileSystemLabel CISQL -Confirm:$false
}
$instanceDir = "$($volume.DriveLetter):\SQLServer"
fsutil.exe fsinfo sectorinfo "$($volume.DriveLetter):"
$setup = Start-Process (Join-Path $setupDir "setup.exe") -Wait -PassThru -ArgumentList @(
"/Q"
"/IACCEPTSQLSERVERLICENSETERMS"
"/ACTION=Install"
"/FEATURES=SQLEngine"
"/INSTANCENAME=CISQL"
"/INSTANCEDIR=$instanceDir"
"/INSTALLSQLDATADIR=$instanceDir"
'/SQLSYSADMINACCOUNTS="BUILTIN\Administrators"'
"/UPDATEENABLED=False"
"/TCPENABLED=0"
"/NPENABLED=0"
)
$summaryLog = Join-Path $env:RUNNER_TEMP "sql-server-summary.txt"
Copy-Item "C:\Program Files\Microsoft SQL Server\170\Setup Bootstrap\Log\Summary.txt" `
$summaryLog -ErrorAction SilentlyContinue
if ($setup.ExitCode -ne 0) {
Get-Content $summaryLog -ErrorAction SilentlyContinue
throw "SQL Server setup failed or requires a restart: $($setup.ExitCode)"
}
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = "Data Source=lpc:.\CISQL;Integrated Security=True;Connect Timeout=30"
try {
$connection.Open()
$command = $connection.CreateCommand()
$command.CommandText = "CREATE DATABASE CIWindowsExporter"
$command.ExecuteNonQuery() | Out-Null
# Express can close idle databases and remove their performance counter instances.
$command.CommandText = "ALTER DATABASE CIWindowsExporter SET AUTO_CLOSE OFF"
$command.ExecuteNonQuery() | Out-Null
$connection.ChangeDatabase("CIWindowsExporter")
$command.CommandText = @'
CREATE TABLE dbo.Fixture (ID int NOT NULL, Data char(8000) NOT NULL);
INSERT INTO dbo.Fixture SELECT TOP (1000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)), 'fixture' FROM sys.all_objects;
CHECKPOINT;
'@
$command.ExecuteNonQuery() | Out-Null
} finally {
$connection.Dispose()
}
Get-Service 'MSSQL$CISQL' | Format-Table Name, Status
+64
View File
@@ -0,0 +1,64 @@
param([int]$TestExitCode)
$ErrorActionPreference = "Stop"
$prefix = "github.com/prometheus-community/windows_exporter/internal/collector/"
$required = @($env:WINDOWS_EXPORTER_TEST_COLLECTORS.Split(','))
$results = @{}
$text = [System.Text.StringBuilder]::new()
$lines = if (Test-Path test-results.jsonl) { Get-Content test-results.jsonl } else { @() }
foreach ($line in $lines) {
try {
$event = $line | ConvertFrom-Json -ErrorAction Stop
} catch {
[void]$text.AppendLine($line)
continue
}
if ($event.Output) { [void]$text.Append($event.Output) }
if (-not $event.Package -or -not $event.Package.StartsWith($prefix) -or $event.Test -ne "TestCollector") {
continue
}
$name = $event.Package.Substring($prefix.Length)
if (-not $results.ContainsKey($name)) {
$results[$name] = @{ State = "not completed"; Notes = @() }
}
if ($event.Action -in @("pass", "skip", "fail")) {
$results[$name].State = $event.Action
}
if ($event.Output -match 'collector \S+ (?:is not supported|has empty optional instance groups): (.+)') {
$results[$name].Notes += $Matches[1].Trim()
}
}
$text.ToString() | Set-Content test-output.txt -NoNewline -Encoding utf8
# Aborted tests must leave required fixtures visible as not run.
foreach ($name in $required) {
if (-not $results.ContainsKey($name)) {
$results[$name] = @{ State = "not run"; Notes = @() }
}
}
$testState = if (-not $lines) { "not run" } elseif ($TestExitCode -eq 0) { "passed" } else { "failed" }
$summary = @(
"### Windows feature tests: $env:WINDOWS_TEST_OS"
""
"Go suite: **$testState**. Required fixtures cannot skip. Empty optional instance groups remain listed below."
""
"| Collector | Required | Live test | Unavailable features / notes |"
"| --- | --- | --- | --- |"
)
foreach ($name in $results.Keys | Sort-Object) {
$fixture = if ($name -in $required) { "yes" } else { "no" }
$state = switch ($results[$name].State) {
"pass" { "passed" }
"skip" { "unavailable" }
"fail" { "failed" }
default { $results[$name].State }
}
$notes = ($results[$name].Notes | Sort-Object -Unique) -join '; '
$notes = $notes.Replace('|', '\|')
$summary += "| $name | $fixture | $state | $notes |"
}
$summary | Set-Content feature-summary.md -Encoding utf8
if ($env:GITHUB_STEP_SUMMARY) {
$summary | Add-Content $env:GITHUB_STEP_SUMMARY
}
+20
View File
@@ -0,0 +1,20 @@
# Background CI steps attach virtual disks at the same time, which makes
# Mount-VHD fail with 0x800703E3. Serialize attaching and formatting them.
function Invoke-WithVhdLock([scriptblock]$ScriptBlock) {
$mutex = [System.Threading.Mutex]::new($false, "Global\windows-exporter-ci-vhd")
try {
try {
[void]$mutex.WaitOne()
} catch [System.Threading.AbandonedMutexException] {
# The previous owner exited without releasing; the lock is ours now.
}
try {
& $ScriptBlock
} finally {
$mutex.ReleaseMutex()
}
} finally {
$mutex.Dispose()
}
}