implement new Download-FileDirectly function to handle downloads
This commit is contained in:
@@ -6,16 +6,26 @@ $DownloadTokens = $null
|
||||
$DownloadParseErrors = $null
|
||||
$DownloadAst = [Management.Automation.Language.Parser]::ParseFile($DownloadToolsPath, [ref]$DownloadTokens, [ref]$DownloadParseErrors)
|
||||
If ($DownloadParseErrors.Count) { Throw ($DownloadParseErrors | Out-String) }
|
||||
$DownloadDefinition = $DownloadAst.Find({
|
||||
param($Node)
|
||||
$Node -is [Management.Automation.Language.FunctionDefinitionAst] -and $Node.Name -eq 'Download-File'
|
||||
}, $true)
|
||||
. ([scriptblock]::Create($DownloadDefinition.Extent.Text))
|
||||
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) Return $URL }
|
||||
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
|
||||
@@ -28,32 +38,53 @@ Function Start-BitsTransfer {
|
||||
$DownloadTestRoot = Join-Path ([IO.Path]::GetTempPath()) ('download-file-tests-' + [guid]::NewGuid().ToString('N'))
|
||||
$null = New-Item -Path $DownloadTestRoot -ItemType Directory
|
||||
Try {
|
||||
$DownloadTestFile = Join-Path $DownloadTestRoot 'collector $test.exe'
|
||||
$script:DownloadTestMode = 'success'
|
||||
$DownloadResult = Download-File -URL 'https://example.invalid/collector.exe' -File $DownloadTestFile
|
||||
If ($DownloadResult -cne $DownloadTestFile -or [IO.File]::ReadAllText($DownloadResult) -cne 'Synthetic download.') {
|
||||
Throw 'Successful download did not return the completed file.'
|
||||
}
|
||||
Write-Host 'PASS: successful download returns its destination.'
|
||||
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."
|
||||
|
||||
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 {
|
||||
Download-File -URL 'https://example.invalid/collector.exe' -File $DownloadTestFile |
|
||||
ForEach-Object { $DownloadReturnedPaths += $_ }
|
||||
$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."
|
||||
}
|
||||
}
|
||||
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.'
|
||||
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."
|
||||
}
|
||||
If ($DownloadReturnedPaths.Count -ne 0) { Throw 'Failed transfer returned a success path.' }
|
||||
Write-Host "PASS: $script:DownloadTestMode stops the caller and preserves the transfer error."
|
||||
}
|
||||
Write-Host "All Download-File tests passed on PowerShell $($PSVersionTable.PSVersion), $([IntPtr]::Size * 8)-bit."
|
||||
Write-Host "All download helper tests passed on PowerShell $($PSVersionTable.PSVersion), $([IntPtr]::Size * 8)-bit."
|
||||
}
|
||||
Finally {
|
||||
$DownloadResolvedRoot = (Resolve-Path -LiteralPath $DownloadTestRoot).Path
|
||||
|
||||
@@ -9,7 +9,8 @@ $null = [Management.Automation.Language.Parser]::ParseFile($DsaScriptUnderTest,
|
||||
If ($DsaErrors.Count) { Throw ($DsaErrors | Out-String) }
|
||||
|
||||
Function Assert-Dsa { param([bool]$Condition, [string]$Description) If (!$Condition) { Throw $Description } }
|
||||
Function Download-File {
|
||||
Function Download-File { Throw 'DSA must use Download-FileDirectly.' }
|
||||
Function Download-FileDirectly {
|
||||
[CmdletBinding()]
|
||||
param($URL, $File)
|
||||
$script:DsaDownloadCalls++
|
||||
@@ -80,6 +81,7 @@ Function Invoke-DsaCase {
|
||||
Assert-Dsa ($script:DsaDownloadCalls -eq 0) 'Invalid flag must fail before downloading.'
|
||||
Return
|
||||
}
|
||||
Assert-Dsa ($script:DsaDownloadCalls -eq 1) 'Expected one direct download.'
|
||||
If ($Mode -in @('empty-download','download-failure')) {
|
||||
Assert-Dsa ($null -ne $DsaCaught) 'Download failure must stop collection.'
|
||||
Assert-Dsa ($script:DsaProcessCalls -eq 0 -and $script:DsaRecordedUploads.Count -eq 0) 'Download failure must prevent execution and upload.'
|
||||
|
||||
Reference in New Issue
Block a user