102 lines
5.5 KiB
PowerShell
102 lines
5.5 KiB
PowerShell
[CmdletBinding()]
|
|
param()
|
|
$ErrorActionPreference='Stop'
|
|
$root=Split-Path -Parent $PSScriptRoot
|
|
. (Join-Path $root 'scripts\Project.Common.ps1')
|
|
Assert-PowerShell51
|
|
$fixture=Join-Path $root ('local\guest software tests '+[guid]::NewGuid().ToString('N').Substring(0,8))
|
|
New-Item -ItemType Directory -Path $fixture -Force|Out-Null
|
|
foreach ($file in @('Software.Selection.ps1','Package.Validation.ps1')) {
|
|
Copy-Item -LiteralPath (Join-Path $root ('scripts\'+$file)) -Destination (Join-Path $fixture $file)
|
|
}
|
|
foreach ($file in @('chrome-enterprise64.msi','VSCodeSetup-x64.exe','virtio-win-guest-tools.exe')) {
|
|
[IO.File]::WriteAllText((Join-Path $fixture $file),'Fixture; never executed.')
|
|
}
|
|
# Redirect resources and return exit codes to the test caller. All operating-system
|
|
# operations below are mocked; this test never installs software or changes services.
|
|
$hook=[IO.File]::ReadAllText((Join-Path $root 'hooks\RunBeforeCloudbaseInitInstall.ps1'))
|
|
$hook=$hook.Replace("'C:\UnattendResources\CustomResources'",("'"+$fixture+"'"))
|
|
$hook=$hook.Replace('exit 1005','return 1005').Replace('exit 0','return 0').Replace('exit 1','return 1')
|
|
$guestHook=[scriptblock]::Create($hook)
|
|
& {
|
|
$script:guestState=@{}
|
|
$script:installerCalls=New-Object 'System.Collections.Generic.List[string]'
|
|
$script:signatureStatus='Valid'
|
|
$script:installedChrome=Join-Path $env:ProgramFiles 'Google\Chrome\Application\chrome.exe'
|
|
$script:installedCode=Join-Path $env:ProgramFiles 'Microsoft VS Code\Code.exe'
|
|
function Test-Path {
|
|
param($LiteralPath,$PathType)
|
|
if ($LiteralPath -eq 'C:\UnattendResources\config.ini') { return $true }
|
|
if ($LiteralPath -eq $script:installedChrome) { return [bool]$script:guestState.Chrome }
|
|
if ($LiteralPath -eq $script:installedCode) { return [bool]$script:guestState.VSCode }
|
|
Microsoft.PowerShell.Management\Test-Path -LiteralPath $LiteralPath -PathType Leaf
|
|
}
|
|
function Get-Item {
|
|
param($LiteralPath)
|
|
if ($LiteralPath -in @($script:installedChrome,$script:installedCode)) {
|
|
return [PSCustomObject]@{VersionInfo=[PSCustomObject]@{ProductVersion='999.0.0'}}
|
|
}
|
|
Microsoft.PowerShell.Management\Get-Item -LiteralPath $LiteralPath
|
|
}
|
|
function Get-ItemProperty {
|
|
param($Path,$ErrorAction)
|
|
if ($script:guestState.VirtIO) { [PSCustomObject]@{DisplayName='Virtio-win-guest-tools';DisplayVersion='999.0.0'} }
|
|
}
|
|
function Get-AuthenticodeSignature {
|
|
param($LiteralPath)
|
|
$publisher='Microsoft Corporation'
|
|
if ([IO.Path]::GetExtension($LiteralPath) -eq '.msi') { $publisher='Google LLC' }
|
|
$certificate=[PSCustomObject]@{Publisher=$publisher}
|
|
$certificate | Add-Member -MemberType ScriptMethod -Name GetNameInfo -Value {param($Type,$ForIssuer) $this.Publisher}
|
|
[PSCustomObject]@{Status=$script:signatureStatus;SignerCertificate=$certificate}
|
|
}
|
|
function Start-Process {
|
|
param($FilePath,$ArgumentList,$WindowStyle,[switch]$PassThru)
|
|
if ($WindowStyle -ne 'Hidden') { throw 'Unexpected visible installer.' }
|
|
$name='Chrome'
|
|
if ($FilePath -like '*VSCodeSetup-*') { $name='VSCode' }
|
|
elseif ($FilePath -like '*virtio-win-guest-tools.exe') { $name='VirtIO' }
|
|
elseif ($FilePath -ne 'msiexec.exe') { throw 'Unexpected process in guest test.' }
|
|
$script:installerCalls.Add($name)
|
|
$script:guestState[$name]=$true
|
|
$exitCode=0
|
|
if ($name -eq 'VirtIO') { $exitCode=3010 }
|
|
$process=[PSCustomObject]@{Handle=[IntPtr]::Zero;ExitCode=$exitCode}
|
|
$process | Add-Member -MemberType ScriptMethod -Name WaitForExit -Value {}
|
|
return $process
|
|
}
|
|
function Get-Service {
|
|
param($Name,$ErrorAction)
|
|
if ($Name -ne 'qemu-ga') { throw 'Unexpected service query.' }
|
|
if ($script:guestState.VirtIO) { [PSCustomObject]@{Name=$Name} }
|
|
}
|
|
function Set-Service {
|
|
param($Name,$StartupType)
|
|
if ($Name -ne 'qemu-ga' -or $StartupType -ne 'Automatic') { throw 'Unexpected service mutation.' }
|
|
}
|
|
$checked=0
|
|
foreach ($chrome in @($false,$true)) {
|
|
foreach ($code in @($false,$true)) {
|
|
$selection=@{SchemaVersion=1;InstallChrome=$chrome;InstallVSCode=$code}
|
|
[IO.File]::WriteAllText((Join-Path $fixture 'software-selection.json'),($selection|ConvertTo-Json))
|
|
$script:guestState=@{}
|
|
$script:installerCalls.Clear()
|
|
$first=& $guestHook
|
|
if ($first -ne 1005) { throw 'First pass did not request the installer reboot.' }
|
|
$expected=1+[int]$chrome+[int]$code
|
|
if ($script:installerCalls.Count -ne $expected -or
|
|
($script:installerCalls.Contains('Chrome') -ne $chrome) -or
|
|
($script:installerCalls.Contains('VSCode') -ne $code)) { throw 'Guest installed an incorrect software selection.' }
|
|
$resumed=& $guestHook
|
|
if ($resumed -ne 0 -or $script:installerCalls.Count -ne $expected) { throw 'Guest reinstalled software or requested another reboot on resume.' }
|
|
$checked++
|
|
}
|
|
}
|
|
$script:guestState=@{}
|
|
$script:installerCalls.Clear()
|
|
$script:signatureStatus='HashMismatch'
|
|
$failed=& $guestHook 2>$null
|
|
if ($failed -ne 1 -or $script:installerCalls.Count) { throw 'Guest did not stop before installing an invalidly signed package.' }
|
|
[PSCustomObject]@{GuestSoftwareCombinations=$checked;RebootResume='passed; no repeat installation';InvalidSignature='stopped before installation';SystemOperations='mocked'}
|
|
}
|