Files
management-scripts/tests/Download-File.Tests.ps1

96 lines
5.4 KiB
PowerShell

#Requires -Version 5.0
# Offline regression tests. BITS and URL resolution are mocked.
$ErrorActionPreference = 'Stop'
$DownloadToolsPath = Join-Path (Split-Path $PSScriptRoot -Parent) 'Tools.ps1'
$DownloadTokens = $null
$DownloadParseErrors = $null
$DownloadAst = [Management.Automation.Language.Parser]::ParseFile($DownloadToolsPath, [ref]$DownloadTokens, [ref]$DownloadParseErrors)
If ($DownloadParseErrors.Count) { Throw ($DownloadParseErrors | Out-String) }
Foreach ($DownloadFunctionName in @('Download-File','Download-FileDirectly')) {
$DownloadDefinition = $DownloadAst.Find({
param($Node)
$Node -is [Management.Automation.Language.FunctionDefinitionAst] -and $Node.Name -eq $DownloadFunctionName
}, $true)
If (!$DownloadDefinition) { Throw "Missing helper: $DownloadFunctionName" }
. ([scriptblock]::Create($DownloadDefinition.Extent.Text))
}
Function Get-AbsoluteURI {
param($URL)
If ($script:DownloadRejectPreflight) { Throw 'Direct download must not resolve the URL first.' }
Return $URL
}
Function IsURLValid { Throw 'Direct download must not make a preliminary validation request.' }
Function Get-TempPath { Return ($script:DownloadTestRoot + '\') }
Function Start-BitsTransfer {
[CmdletBinding()]
param($Source, $Destination)
$script:DownloadRecordedSource = $Source
If ($script:DownloadTestMode -eq 'success') {
[IO.File]::WriteAllText($Destination, 'Synthetic download.')
Return
}
[IO.File]::WriteAllBytes($Destination, [byte[]]@())
If ($script:DownloadTestMode -eq 'terminating-error') { Throw 'Synthetic BITS connection failure.' }
Microsoft.PowerShell.Utility\Write-Error 'Synthetic BITS TLS failure.'
}
$DownloadTestRoot = Join-Path ([IO.Path]::GetTempPath()) ('download-file-tests-' + [guid]::NewGuid().ToString('N'))
$null = New-Item -Path $DownloadTestRoot -ItemType Directory
Try {
Foreach ($DownloadFunctionName in @('Download-File','Download-FileDirectly')) {
$script:DownloadRejectPreflight = ($DownloadFunctionName -eq 'Download-FileDirectly')
$DownloadTestFile = Join-Path $DownloadTestRoot 'collector $test.exe'
[IO.File]::WriteAllBytes($DownloadTestFile, [byte[]]@())
$script:DownloadTestMode = 'success'
$DownloadTestUrl = 'https://example.invalid/collector.exe?token=original'
$DownloadResult = @(& $DownloadFunctionName -URL $DownloadTestUrl -File $DownloadTestFile)
If ($DownloadResult.Count -ne 1 -or $DownloadResult[0] -cne $DownloadTestFile -or
[IO.File]::ReadAllText($DownloadResult[0]) -cne 'Synthetic download.' -or
$script:DownloadRecordedSource -cne $DownloadTestUrl) {
Throw 'Successful download must pass the source URL intact, replace an empty file, and return exactly one completed path.'
}
Write-Host "PASS: ${DownloadFunctionName}: URL forwarding, empty destination overwrite, and one completed path."
$DownloadAutomaticFile = Join-Path $DownloadTestRoot 'collector.msi'
Foreach ($DownloadBinding in @('positional','pipeline')) {
$DownloadResult = @(If ($DownloadBinding -eq 'positional') {
& $DownloadFunctionName 'https://example.invalid/collector.msi'
} Else {
'https://example.invalid/collector.msi' | & $DownloadFunctionName
})
If ($DownloadResult.Count -ne 1 -or $DownloadResult[0] -cne $DownloadAutomaticFile -or
[IO.File]::ReadAllText($DownloadAutomaticFile) -cne 'Synthetic download.') {
Throw "Automatic filename or $DownloadBinding URL binding failed."
}
}
Write-Host "PASS: ${DownloadFunctionName}: positional/pipeline URL and automatic filename with extension."
Foreach ($script:DownloadTestMode in @('nonterminating-error','terminating-error')) {
# Match an RMM that uses the normal Continue preference and does not pass -ErrorAction.
$ErrorActionPreference = 'Continue'
$DownloadCaught = $null
$DownloadReturnedPaths = @()
Try {
& $DownloadFunctionName -URL 'https://example.invalid/collector.exe' -File $DownloadTestFile |
ForEach-Object { $DownloadReturnedPaths += $_ }
}
Catch { $DownloadCaught = $_ }
Finally { $ErrorActionPreference = 'Stop' }
If ($null -eq $DownloadCaught -or $DownloadCaught.Exception.Message -notlike '*Synthetic BITS*failure*') {
Throw 'Failed transfer must throw and preserve the BITS error.'
}
If ($DownloadReturnedPaths.Count -ne 0) { Throw 'Failed transfer returned a success path.' }
Write-Host "PASS: ${DownloadFunctionName}: $script:DownloadTestMode stops the caller and preserves the transfer error."
}
}
Write-Host "All download helper tests passed on PowerShell $($PSVersionTable.PSVersion), $([IntPtr]::Size * 8)-bit."
}
Finally {
$DownloadResolvedRoot = (Resolve-Path -LiteralPath $DownloadTestRoot).Path
$DownloadTempRoot = [IO.Path]::GetFullPath([IO.Path]::GetTempPath()).TrimEnd('\') + '\'
If (!$DownloadResolvedRoot.StartsWith($DownloadTempRoot, [StringComparison]::OrdinalIgnoreCase) -or
(Split-Path $DownloadResolvedRoot -Leaf) -notlike 'download-file-tests-*') { Throw 'Unexpected cleanup directory.' }
Remove-Item -LiteralPath $DownloadResolvedRoot -Recurse -Force
}