Tests/VSAModule.Multipart.Tests.ps1
|
BeforeAll { $script:ModuleRoot = Split-Path -Path (Split-Path -Parent $PSCommandPath) Import-Module (Join-Path $script:ModuleRoot 'VSAModule.psd1') -Force # A 256-byte payload covering every possible byte value, including bytes that are not valid # UTF-8 on their own (e.g. 0x80-0xFF) - this is exactly the data a naive byte->string->byte # round trip would corrupt. $script:PayloadBytes = [byte[]](0..255) $script:TempFile = Join-Path ([System.IO.Path]::GetTempPath()) "vsamodule-multipart-test-$([guid]::NewGuid()).bin" [System.IO.File]::WriteAllBytes($script:TempFile, $script:PayloadBytes) } AfterAll { Remove-Item -Path $script:TempFile -Force -ErrorAction SilentlyContinue } Describe "Multipart uploads build a byte[] body without corrupting binary data (T-6.5 / F-37)" { It "Publish-VSADocument embeds the file bytes verbatim" { InModuleScope VSAModule -Parameters @{ TempFile = $script:TempFile; PayloadBytes = $script:PayloadBytes } { param($TempFile, $PayloadBytes) $script:capturedBody = $null $script:capturedContentType = $null Mock Invoke-VSARestMethod { $script:capturedBody = $Body $script:capturedContentType = $ContentType } Publish-VSADocument -AgentId 10001 -SourceFilePath $TempFile | Out-Null # Note: never pipe an array into Should - PowerShell unrolls it and Should sees # individual elements instead of the array itself. ,$script:capturedBody | Should -BeOfType [byte[]] $script:capturedContentType | Should -Match 'multipart/form-data' [bool]$found = $false for ($i = 0; $i -le ($script:capturedBody.Length - $PayloadBytes.Length); $i++) { if ($script:capturedBody[$i] -ne $PayloadBytes[0]) { continue } [bool]$match = $true for ($j = 1; $j -lt $PayloadBytes.Length; $j++) { if ($script:capturedBody[$i + $j] -ne $PayloadBytes[$j]) { $match = $false; break } } if ($match) { $found = $true; break } } $found | Should -BeTrue } } It "Publish-VSACustomExtensionFile embeds the file bytes verbatim" { InModuleScope VSAModule -Parameters @{ TempFile = $script:TempFile; PayloadBytes = $script:PayloadBytes } { param($TempFile, $PayloadBytes) $script:capturedBody = $null $script:capturedContentType = $null Mock Invoke-VSARestMethod { $script:capturedBody = $Body $script:capturedContentType = $ContentType } Publish-VSACustomExtensionFile -AgentId 10001 -SourceFilePath $TempFile | Out-Null ,$script:capturedBody | Should -BeOfType [byte[]] $script:capturedContentType | Should -Match 'multipart/form-data' [bool]$found = $false for ($i = 0; $i -le ($script:capturedBody.Length - $PayloadBytes.Length); $i++) { if ($script:capturedBody[$i] -ne $PayloadBytes[0]) { continue } [bool]$match = $true for ($j = 1; $j -lt $PayloadBytes.Length; $j++) { if ($script:capturedBody[$i + $j] -ne $PayloadBytes[$j]) { $match = $false; break } } if ($match) { $found = $true; break } } $found | Should -BeTrue } } It "The transport (Invoke-VSARestMethod -> Get-RequestData) accepts a byte[] Body without coercing it to a string" { InModuleScope VSAModule -Parameters @{ PayloadBytes = $script:PayloadBytes } { param($PayloadBytes) $script:capturedBody = $null Mock Update-VSAConnection {} Mock Get-RequestData { $script:capturedBody = $Body [pscustomobject]@{ Result = @(); ResponseCode = 0; Status = 'OK' } } $conn = [VSAConnection]::new('https://vsa.example.com', 'u', 'tok', 'pat', [datetime]::Now.AddHours(1), $false, $false) Invoke-VSARestMethod -VSAConnection $conn -URISuffix 'api/v1.0/x' -Method PUT -Body $PayloadBytes -ContentType 'application/octet-stream' | Out-Null ,$script:capturedBody | Should -BeOfType [byte[]] $script:capturedBody.Length | Should -Be $PayloadBytes.Length [System.Convert]::ToBase64String($script:capturedBody) | Should -Be ([System.Convert]::ToBase64String($PayloadBytes)) } } } |