142 lines
9.4 KiB
PowerShell
142 lines
9.4 KiB
PowerShell
$ErrorActionPreference = 'Stop'
|
|
$repo = Split-Path -Parent $PSScriptRoot
|
|
. (Join-Path $repo 'scripts\Project.Common.ps1')
|
|
Assert-PowerShell51
|
|
function Assert-ActivationTest { param([bool]$Condition,[string]$Message) if (-not $Condition) { throw $Message } }
|
|
|
|
$fixture = Join-Path $repo ('local\windows activation tests ' + [guid]::NewGuid().ToString('N').Substring(0,8))
|
|
New-Item -ItemType Directory -Path $fixture -Force | Out-Null
|
|
$scriptPath = Join-Path $fixture '30-WindowsActivation.ps1'
|
|
$settingsPath = Join-Path $fixture 'kms-settings.json'
|
|
Copy-Item -LiteralPath (Join-Path $repo 'resources\Activate-Windows.ps1') -Destination $scriptPath
|
|
$previousProgramData = $env:ProgramData
|
|
try {
|
|
$env:ProgramData = Join-Path $fixture 'ProgramData'
|
|
$reportPath = Join-Path $env:ProgramData 'PveImageBuilder\windows-activation.json'
|
|
& {
|
|
function New-TestLicense {
|
|
param([int]$Status=0,[string]$Description='Windows Operating System, VOLUME_KMSCLIENT channel',[bool]$Addon=$false)
|
|
[PSCustomObject]@{ID='00000000-0000-0000-0000-000000000001';Description=$Description;LicenseIsAddon=$Addon;LicenseStatus=$Status;LicenseStatusReason=0;PartialProductKey='ABCDE'}
|
|
}
|
|
function Reset-ActivationTest {
|
|
$global:PveActivationTest = @{
|
|
Products=@(New-TestLicense);CurrentProducts=@(New-TestLicense -Status 1)
|
|
Reads=0;Calls=(New-Object 'System.Collections.Generic.List[object]')
|
|
ReturnMode='Object';ReturnCode=0;MethodFailure=$false;ReadbackFailure=$false
|
|
Host='kms.example.com';Port=1689;DiagnosticFailure=$false
|
|
}
|
|
[IO.File]::WriteAllText($settingsPath,(@{SchemaVersion=1;Host='kms.example.com';Port=1689} | ConvertTo-Json))
|
|
}
|
|
function Get-CimInstance {
|
|
param($ClassName,$Filter,$ErrorAction)
|
|
if ($ClassName -eq 'SoftwareLicensingService') {
|
|
return [PSCustomObject]@{KeyManagementServiceMachine=$global:PveActivationTest.Host;KeyManagementServicePort=$global:PveActivationTest.Port}
|
|
}
|
|
Assert-ActivationTest ($ClassName -eq 'SoftwareLicensingProduct') 'Unexpected licensing query.'
|
|
Assert-ActivationTest ($Filter -eq "ApplicationID='55c92734-d682-4d71-983e-d6ec3f16059f' AND PartialProductKey IS NOT NULL") 'Activation query did not restrict installed Windows licenses.'
|
|
$global:PveActivationTest.Reads++
|
|
if ($global:PveActivationTest.Reads -eq 1) { return $global:PveActivationTest.Products }
|
|
if ($global:PveActivationTest.ReadbackFailure) { throw 'Mocked license readback failure.' }
|
|
$global:PveActivationTest.CurrentProducts
|
|
}
|
|
function Invoke-CimMethod {
|
|
param($InputObject,$MethodName,$OperationTimeoutSec,$ErrorAction)
|
|
Assert-ActivationTest ($MethodName -eq 'Activate' -and $OperationTimeoutSec -eq 30) 'Activation was not bounded or used an unexpected method.'
|
|
Assert-ActivationTest ($InputObject.Description -match '\bVOLUME_KMSCLIENT\b' -and -not $InputObject.LicenseIsAddon) 'Activation targeted a non-KMS or addon license.'
|
|
$global:PveActivationTest.Calls.Add($InputObject.ID)
|
|
if ($global:PveActivationTest.MethodFailure) { throw 'Mocked unavailable KMS server or network timeout.' }
|
|
switch ($global:PveActivationTest.ReturnMode) {
|
|
'Object' { [PSCustomObject]@{ReturnValue=$global:PveActivationTest.ReturnCode} }
|
|
'Scalar' { [uint32]$global:PveActivationTest.ReturnCode }
|
|
'Missing' { [PSCustomObject]@{} }
|
|
'NullValue' { [PSCustomObject]@{ReturnValue=$null} }
|
|
'Null' { $null }
|
|
}
|
|
}
|
|
function New-Item {
|
|
param($ItemType,$Path,[switch]$Force)
|
|
if ($global:PveActivationTest.DiagnosticFailure) { throw 'Mocked diagnostics write failure.' }
|
|
Microsoft.PowerShell.Management\New-Item -ItemType $ItemType -Path $Path -Force:$Force
|
|
}
|
|
function Invoke-ActivationTest {
|
|
& $scriptPath | Out-Null
|
|
Assert-ActivationTest ($LASTEXITCODE -eq 0) 'Activation failure blocked Cloudbase-Init or requested a reboot.'
|
|
$raw = Get-Content -Raw -LiteralPath $reportPath
|
|
Assert-ActivationTest ($raw -notmatch 'ABCDE' -and $raw -notmatch 'PartialProductKey') 'Activation diagnostics disclosed product key information.'
|
|
$report = $raw | ConvertFrom-Json
|
|
Assert-ActivationTest ($report.CompletedUtc -and $report.StartedUtc -and $report.KmsHost -eq 'kms.example.com' -and $report.KmsPort -eq 1689) 'Activation diagnostics are incomplete.'
|
|
$report
|
|
}
|
|
|
|
foreach ($mode in @('Object','Scalar','Missing','NullValue','Null')) {
|
|
Reset-ActivationTest
|
|
$global:PveActivationTest.ReturnMode = $mode
|
|
$report = Invoke-ActivationTest
|
|
Assert-ActivationTest ($report.Outcome -eq 'Activated' -and $report.Attempted -and $report.LicenseStatus -eq 1 -and $global:PveActivationTest.Calls.Count -eq 1) 'A licensed readback was not accepted after activation.'
|
|
}
|
|
Reset-ActivationTest
|
|
$global:PveActivationTest.Products = @(New-TestLicense -Status 1)
|
|
$report = Invoke-ActivationTest
|
|
Assert-ActivationTest ($report.Outcome -eq 'AlreadyActivated' -and -not $report.Attempted -and $global:PveActivationTest.Calls.Count -eq 0) 'An already activated license received another request.'
|
|
|
|
foreach ($products in @(@(),@(New-TestLicense -Description 'Windows Operating System, RETAIL channel'),@(New-TestLicense -Addon $true))) {
|
|
Reset-ActivationTest
|
|
$global:PveActivationTest.Products = $products
|
|
$report = Invoke-ActivationTest
|
|
Assert-ActivationTest ($report.Outcome -eq 'Skipped' -and -not $report.Attempted -and $global:PveActivationTest.Calls.Count -eq 0) 'An absent, retail, or addon license was activated.'
|
|
}
|
|
Reset-ActivationTest
|
|
$global:PveActivationTest.Products = @((New-TestLicense),(New-TestLicense))
|
|
$report = Invoke-ActivationTest
|
|
Assert-ActivationTest ($report.Outcome -eq 'Failed' -and -not $report.Attempted -and $global:PveActivationTest.Calls.Count -eq 0) 'Ambiguous KMS licenses were activated.'
|
|
|
|
foreach ($mode in @('Object','Scalar')) {
|
|
Reset-ActivationTest
|
|
$global:PveActivationTest.ReturnMode = $mode
|
|
$global:PveActivationTest.ReturnCode = 5
|
|
$report = Invoke-ActivationTest
|
|
Assert-ActivationTest ($report.Outcome -eq 'Failed' -and $report.ReturnValue -eq 5 -and $report.Message -match 'error 5') 'A CIM failure code was reported as successful activation.'
|
|
}
|
|
Reset-ActivationTest
|
|
$global:PveActivationTest.CurrentProducts = @(New-TestLicense -Status 5)
|
|
$global:PveActivationTest.CurrentProducts[0].LicenseStatusReason = 3221549092
|
|
$report = Invoke-ActivationTest
|
|
Assert-ActivationTest ($report.Outcome -eq 'Failed' -and $report.LicenseStatus -eq 5 -and $report.LicenseStatusReason -eq 3221549092) 'An unlicensed readback was reported as activation success.'
|
|
|
|
foreach ($failure in @('MethodFailure','ReadbackFailure')) {
|
|
Reset-ActivationTest
|
|
$global:PveActivationTest[$failure] = $true
|
|
$report = Invoke-ActivationTest
|
|
Assert-ActivationTest ($report.Outcome -eq 'Failed' -and $report.Attempted -and $report.Message -match 'Mocked' -and $global:PveActivationTest.Calls.Count -eq 1) 'Licensing/network errors were lost or caused another attempt.'
|
|
}
|
|
foreach ($field in @('Host','Port')) {
|
|
Reset-ActivationTest
|
|
if ($field -eq 'Host') { $global:PveActivationTest.Host = 'stale.example.com' }
|
|
else { $global:PveActivationTest.Port = 1688 }
|
|
$report = Invoke-ActivationTest
|
|
Assert-ActivationTest ($report.Outcome -eq 'Failed' -and -not $report.Attempted -and $global:PveActivationTest.Calls.Count -eq 0) 'A stale KMS endpoint received activation.'
|
|
}
|
|
foreach ($invalid in @('missing','malformed','invalid')) {
|
|
Reset-ActivationTest
|
|
switch ($invalid) {
|
|
'missing' { Remove-Item -LiteralPath $settingsPath }
|
|
'malformed' { [IO.File]::WriteAllText($settingsPath,'{broken') }
|
|
'invalid' { [IO.File]::WriteAllText($settingsPath,(@{SchemaVersion=1;Host='https://invalid';Port=1689} | ConvertTo-Json)) }
|
|
}
|
|
& $scriptPath | Out-Null
|
|
$report = Get-Content -Raw -LiteralPath $reportPath | ConvertFrom-Json
|
|
Assert-ActivationTest ($LASTEXITCODE -eq 0 -and $report.Outcome -eq 'Failed' -and -not $report.Attempted -and $global:PveActivationTest.Calls.Count -eq 0) 'Invalid settings blocked initialization or reached activation.'
|
|
}
|
|
Reset-ActivationTest
|
|
$global:PveActivationTest.MethodFailure = $true
|
|
$global:PveActivationTest.DiagnosticFailure = $true
|
|
& $scriptPath | Out-Null
|
|
Assert-ActivationTest ($LASTEXITCODE -eq 0) 'An unwritable diagnostic directory blocked Cloudbase-Init.'
|
|
}
|
|
}
|
|
finally {
|
|
$env:ProgramData = $previousProgramData
|
|
Remove-Variable -Name PveActivationTest -Scope Global -ErrorAction SilentlyContinue
|
|
}
|
|
[PSCustomObject]@{Activation='mocked; host never activated';SuccessfulReadback='passed';NetworkAndLicensingErrors='nonblocking';MissingOrOtherLicense='skipped';RequestTimeoutSeconds=30;RequestsPerRun=1;Diagnostics='passed';CloudbaseExitCode=0}
|