Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 40 additions & 23 deletions tests/Integration/Private/FileDownload.Integration.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -43,29 +43,20 @@ BeforeAll {
return $port
}

# Helper function to wait for server to be ready with polling
# Helper function to wait for server to be ready by polling for a signal file
function Wait-ServerReady {
param(
[int]$Port,
[Parameter(Mandatory)]
Comment thread
tablackburn marked this conversation as resolved.
[ValidateNotNullOrEmpty()]
[string]$SignalFile,
[int]$TimeoutMs = 5000,
[int]$PollIntervalMs = 50
)

$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
while ($stopwatch.ElapsedMilliseconds -lt $TimeoutMs) {
try {
$client = [System.Net.Sockets.TcpClient]::new()
$result = $client.BeginConnect('localhost', $Port, $null, $null)
$success = $result.AsyncWaitHandle.WaitOne(100)
if ($success) {
$client.EndConnect($result)
$client.Close()
return $true
}
$client.Close()
}
catch {
# Server not ready yet
if (Test-Path -Path $SignalFile) {
return $true
}
Start-Sleep -Milliseconds $PollIntervalMs
}
Expand All @@ -82,8 +73,11 @@ BeforeAll {
[switch]$CaptureHeaders
)

$signalId = [guid]::NewGuid().ToString('N')
$readySignalFile = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath "pat-test-ready-$signalId.signal"

$job = Start-Job -ScriptBlock {
param($port, $data, $statusCode, $captureHeaders)
param($port, $data, $statusCode, $captureHeaders, $readySignalFile)

$result = @{
ReceivedHeaders = @{}
Expand All @@ -96,8 +90,13 @@ BeforeAll {
try {
$listener.Start()

# Use async with timeout to prevent hanging
# Begin async wait before signaling readiness so the
# listener is in GetContextAsync() when the test fires
$contextTask = $listener.GetContextAsync()

# Signal that the listener is ready to accept requests
[System.IO.File]::WriteAllText($readySignalFile, 'ready')

if (-not $contextTask.Wait(30000)) {
throw "Timeout waiting for request"
}
Expand Down Expand Up @@ -132,12 +131,30 @@ BeforeAll {
}

return $result
} -ArgumentList $Port, $ResponseData, $StatusCode, $CaptureHeaders.IsPresent

# Wait for server to be ready with polling
$ready = Wait-ServerReady -Port $Port -TimeoutMs 5000
if (-not $ready) {
Write-Warning "Server may not be ready on port $Port"
} -ArgumentList $Port, $ResponseData, $StatusCode, $CaptureHeaders.IsPresent, $readySignalFile

# Wait for server to signal it is ready to accept HTTP requests. Wrap the
# wait so a failed startup always stops the background job and removes the
# readiness signal file instead of leaking them.
try {
$ready = Wait-ServerReady -SignalFile $readySignalFile -TimeoutMs 5000
if (-not $ready) {
throw "Server failed to become ready on port $Port within timeout"
}
}
Comment thread
tablackburn marked this conversation as resolved.
catch {
$startupError = $_
# Stop and remove the background job so a failed startup does not leak
# the HttpListener and its 30-second GetContextAsync wait.
$job | Stop-Job -ErrorAction 'SilentlyContinue'
$job | Remove-Job -Force -ErrorAction 'SilentlyContinue'
throw $startupError
}
finally {
# Always remove the readiness signal file, even when readiness times out.
if (Test-Path -Path $readySignalFile) {
Remove-Item -Path $readySignalFile -Force
}
}

return $job
Expand Down
Loading