From 82068b8ba1e32b0ee140ee42904f6b87117ddcbc Mon Sep 17 00:00:00 2001 From: stevenebutler Date: Wed, 19 Apr 2023 09:26:58 +1000 Subject: [PATCH 1/6] Improve reliability of CTRL-C tests Lengthen the race window from milliseconds to seconds. Don't sleep any longer than necessary if a task has already completed. --- .../Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index 5deb9308bd2..c01f1126dd8 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -4218,14 +4218,15 @@ Describe 'Invoke-WebRequest and Invoke-RestMethod support Cancellation through C [string]$Command = 'Invoke-WebRequest', [string]$Arguments = '', [uri]$Uri, - [int]$DelayMs = 100, + [int]$DelayMs = 1000, [switch]$WillComplete ) $pwsh = [PowerShell]::Create() $invoke = "`$result = $Command -Uri `"$Uri`" $Arguments" $task = $pwsh.AddScript($invoke).InvokeAsync() - Start-Sleep -Milliseconds $DelayMs + $delay = [System.Threading.Tasks.Task]::Delay($DelayMs) + $null = [System.Threading.Tasks.Task]::WhenAny($task, $delay).GetAwaiter().GetResult() $task.IsCompleted | Should -Be $WillComplete.ToBool() $pwsh.Stop() Wait-UntilTrue { [bool]($Task.IsCompleted) } | Should -BeTrue @@ -4281,7 +4282,7 @@ Describe 'Invoke-WebRequest and Invoke-RestMethod support Cancellation through C It 'Invoke-WebRequest: CTRL-C after stalled file download completes gives entire file' { $uri = Get-WebListenerUrl -test Stall -TestValue '1' $outFile = Join-Path $TestDrive "output.txt" - RunWithCancellation -Uri $uri -Arguments "-OutFile $outFile" -DelayMs 1200 -WillComplete + RunWithCancellation -Uri $uri -Arguments "-OutFile $outFile" -DelayMs 5000 -WillComplete Get-content -Path $outFile | should -be 'Hello worldHello world' Remove-Item -Path $outFile } @@ -4298,7 +4299,7 @@ Describe 'Invoke-WebRequest and Invoke-RestMethod support Cancellation through C It 'Invoke-RestMethod: CTRL-C after stalled JSON download processes JSON response' { $uri = Get-WebListenerUrl -test Stall -TestValue '1/application%2fjson' - $result = RunWithCancellation -Command 'Invoke-RestMethod' -Uri $uri -DelayMs 1200 -WillComplete + $result = RunWithCancellation -Command 'Invoke-RestMethod' -Uri $uri -DelayMs 5000 -WillComplete $result.name3 | should -be 'value3' } @@ -4309,7 +4310,7 @@ Describe 'Invoke-WebRequest and Invoke-RestMethod support Cancellation through C It 'Invoke-RestMethod: CTRL-C after stalled atom feed download processes atom response' { $uri = Get-WebListenerUrl -test Stall -TestValue '1/application%2fxml' - $result = RunWithCancellation -Command 'Invoke-RestMethod' -Uri $uri -DelayMs 1200 -WillComplete + $result = RunWithCancellation -Command 'Invoke-RestMethod' -Uri $uri -DelayMs 5000 -WillComplete $result.title | should -be 'Atom-Powered Robots Run Amok' } From 81dcda2454c1f0763796c07f18bae5a93c4b59ad Mon Sep 17 00:00:00 2001 From: stevenebutler Date: Wed, 19 Apr 2023 15:46:12 +1000 Subject: [PATCH 2/6] Tidy code --- .../Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index c01f1126dd8..1e5934fa5d7 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -4226,13 +4226,14 @@ Describe 'Invoke-WebRequest and Invoke-RestMethod support Cancellation through C $invoke = "`$result = $Command -Uri `"$Uri`" $Arguments" $task = $pwsh.AddScript($invoke).InvokeAsync() $delay = [System.Threading.Tasks.Task]::Delay($DelayMs) + + # Stop sleeping as soon as the main task ends or vice versa $null = [System.Threading.Tasks.Task]::WhenAny($task, $delay).GetAwaiter().GetResult() $task.IsCompleted | Should -Be $WillComplete.ToBool() $pwsh.Stop() Wait-UntilTrue { [bool]($Task.IsCompleted) } | Should -BeTrue $result = $pwsh.Runspace.SessionStateProxy.GetVariable('result') $pwsh.Dispose() - return $result } From 30fd06034abb86985e98043dab5f32f4caba8abf Mon Sep 17 00:00:00 2001 From: stevenebutler Date: Thu, 20 Apr 2023 07:52:25 +1000 Subject: [PATCH 3/6] Changes suggested in review by @daxian-dbw --- .../WebCmdlets.Tests.ps1 | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index 1e5934fa5d7..7264d55da71 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -4218,17 +4218,17 @@ Describe 'Invoke-WebRequest and Invoke-RestMethod support Cancellation through C [string]$Command = 'Invoke-WebRequest', [string]$Arguments = '', [uri]$Uri, - [int]$DelayMs = 1000, + [int]$TimeoutMS = 10000, [switch]$WillComplete ) $pwsh = [PowerShell]::Create() $invoke = "`$result = $Command -Uri `"$Uri`" $Arguments" $task = $pwsh.AddScript($invoke).InvokeAsync() - $delay = [System.Threading.Tasks.Task]::Delay($DelayMs) + $delay = [System.Threading.Tasks.Task]::Delay($TimeoutMS) - # Stop sleeping as soon as the main task ends or vice versa - $null = [System.Threading.Tasks.Task]::WhenAny($task, $delay).GetAwaiter().GetResult() + # Simulate CTRL-C as soon as the timeout expires or the main task ends + $null = [System.Threading.Tasks.Task]::WaitAny($task, $delay) $task.IsCompleted | Should -Be $WillComplete.ToBool() $pwsh.Stop() Wait-UntilTrue { [bool]($Task.IsCompleted) } | Should -BeTrue @@ -4239,7 +4239,7 @@ Describe 'Invoke-WebRequest and Invoke-RestMethod support Cancellation through C It 'Invoke-WebRequest: CTRL-C Cancels request before request headers received' { $uri = Get-WebListenerUrl -test Delay -TestValue 30 - RunWithCancellation -Uri $uri -DelayMs 0 + RunWithCancellation -Uri $uri } It 'Invoke-WebRequest: CTRL-C Cancels request after request headers received' { @@ -4252,20 +4252,32 @@ Describe 'Invoke-WebRequest and Invoke-RestMethod support Cancellation through C RunWithCancellation -Uri $uri -Arguments "-SkipCertificateCheck" } - It 'Invoke-WebRequest: Compression CTRL-C Cancels request after request headers' { + It 'Invoke-WebRequest: Brotli Compression CTRL-C Cancels request after request headers' { $uri = Get-WebListenerUrl -Test StallBrotli -TestValue '30/application%2fjson' RunWithCancellation -Uri $uri + } + + It 'Invoke-WebRequest: Gzip Compression CTRL-C Cancels request after request headers' { $uri = Get-WebListenerUrl -Test StallGzip -TestValue '30/application%2fjson' RunWithCancellation -Uri $uri + } + + It 'Invoke-WebRequest: Defalate Compression CTRL-C Cancels request after request headers' { $uri = Get-WebListenerUrl -Test StallDeflate -TestValue '30/application%2fjson' RunWithCancellation -Uri $uri } - It 'Invoke-WebRequest: HTTPS with compression CTRL-C Cancels request after request headers' { + It 'Invoke-WebRequest: HTTPS with Brotli compression CTRL-C Cancels request after request headers' { $uri = Get-WebListenerUrl -Https -Test StallBrotli -TestValue '30/application%2fjson' RunWithCancellation -Uri $uri -Arguments '-SkipCertificateCheck' + } + + It 'Invoke-WebRequest: HTTPS with Gzip compression CTRL-C Cancels request after request headers' { $uri = Get-WebListenerUrl -Https -Test StallGzip -TestValue '30/application%2fjson' RunWithCancellation -Uri $uri -Arguments '-SkipCertificateCheck' + } + + It 'Invoke-WebRequest: HTTPS with Defalte compression CTRL-C Cancels request after request headers' { $uri = Get-WebListenerUrl -Https -Test StallDeflate -TestValue '30/application%2fjson' RunWithCancellation -Uri $uri -Arguments '-SkipCertificateCheck' } @@ -4273,7 +4285,7 @@ Describe 'Invoke-WebRequest and Invoke-RestMethod support Cancellation through C It 'Invoke-WebRequest: CTRL-C Cancels file download request after request headers received' { $uri = Get-WebListenerUrl -Test Stall -TestValue '30' $outFile = Join-Path $TestDrive "output.txt" - RunWithCancellation -Uri $uri -Arguments "-OutFile $outFile" -DelayMs 300 + RunWithCancellation -Uri $uri -Arguments "-OutFile $outFile" # No guarantee the file will be present since the D/L is interrupted if (Test-Path -Path $outFile) { Remove-Item -Path $outFile @@ -4283,14 +4295,14 @@ Describe 'Invoke-WebRequest and Invoke-RestMethod support Cancellation through C It 'Invoke-WebRequest: CTRL-C after stalled file download completes gives entire file' { $uri = Get-WebListenerUrl -test Stall -TestValue '1' $outFile = Join-Path $TestDrive "output.txt" - RunWithCancellation -Uri $uri -Arguments "-OutFile $outFile" -DelayMs 5000 -WillComplete + RunWithCancellation -Uri $uri -Arguments "-OutFile $outFile" -WillComplete Get-content -Path $outFile | should -be 'Hello worldHello world' Remove-Item -Path $outFile } It 'Invoke-RestMethod: CTRL-C Cancels request before request headers received' { $uri = Get-WebListenerUrl -test Delay -TestValue 30 - RunWithCancellation -Command 'Invoke-RestMethod' -Uri $uri -DelayMs 0 + RunWithCancellation -Command 'Invoke-RestMethod' -Uri $uri } It 'Invoke-RestMethod: CTRL-C Cancels request after JSON request headers received' { @@ -4300,7 +4312,7 @@ Describe 'Invoke-WebRequest and Invoke-RestMethod support Cancellation through C It 'Invoke-RestMethod: CTRL-C after stalled JSON download processes JSON response' { $uri = Get-WebListenerUrl -test Stall -TestValue '1/application%2fjson' - $result = RunWithCancellation -Command 'Invoke-RestMethod' -Uri $uri -DelayMs 5000 -WillComplete + $result = RunWithCancellation -Command 'Invoke-RestMethod' -Uri $uri -WillComplete $result.name3 | should -be 'value3' } @@ -4311,7 +4323,7 @@ Describe 'Invoke-WebRequest and Invoke-RestMethod support Cancellation through C It 'Invoke-RestMethod: CTRL-C after stalled atom feed download processes atom response' { $uri = Get-WebListenerUrl -test Stall -TestValue '1/application%2fxml' - $result = RunWithCancellation -Command 'Invoke-RestMethod' -Uri $uri -DelayMs 5000 -WillComplete + $result = RunWithCancellation -Command 'Invoke-RestMethod' -Uri $uri -WillComplete $result.title | should -be 'Atom-Powered Robots Run Amok' } From 33af002bbb2791f0b509ad26a69c163c2169d43c Mon Sep 17 00:00:00 2001 From: stevenebutler Date: Thu, 20 Apr 2023 10:57:26 +1000 Subject: [PATCH 4/6] Reduce the delay before pressing CTRL-C --- .../Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index 7264d55da71..321bb63da7e 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -4218,7 +4218,7 @@ Describe 'Invoke-WebRequest and Invoke-RestMethod support Cancellation through C [string]$Command = 'Invoke-WebRequest', [string]$Arguments = '', [uri]$Uri, - [int]$TimeoutMS = 10000, + [int]$TimeoutMS = 5000, [switch]$WillComplete ) From a7e727913c37c2073e1105167971a4b33ef54fd1 Mon Sep 17 00:00:00 2001 From: stevenebutler Date: Thu, 20 Apr 2023 11:03:58 +1000 Subject: [PATCH 5/6] Rename parameter to avoid confusion as to purpose --- .../Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index 321bb63da7e..51cbe6e4caa 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -4218,14 +4218,14 @@ Describe 'Invoke-WebRequest and Invoke-RestMethod support Cancellation through C [string]$Command = 'Invoke-WebRequest', [string]$Arguments = '', [uri]$Uri, - [int]$TimeoutMS = 5000, + [int]$DelayBeforeStopSimulationMs = 5000, [switch]$WillComplete ) $pwsh = [PowerShell]::Create() $invoke = "`$result = $Command -Uri `"$Uri`" $Arguments" $task = $pwsh.AddScript($invoke).InvokeAsync() - $delay = [System.Threading.Tasks.Task]::Delay($TimeoutMS) + $delay = [System.Threading.Tasks.Task]::Delay($DelayBeforeStopSimulationMs) # Simulate CTRL-C as soon as the timeout expires or the main task ends $null = [System.Threading.Tasks.Task]::WaitAny($task, $delay) @@ -4239,7 +4239,7 @@ Describe 'Invoke-WebRequest and Invoke-RestMethod support Cancellation through C It 'Invoke-WebRequest: CTRL-C Cancels request before request headers received' { $uri = Get-WebListenerUrl -test Delay -TestValue 30 - RunWithCancellation -Uri $uri + RunWithCancellation -Uri $uri -DelayBeforeStopSimulationMs 1000 } It 'Invoke-WebRequest: CTRL-C Cancels request after request headers received' { @@ -4302,7 +4302,7 @@ Describe 'Invoke-WebRequest and Invoke-RestMethod support Cancellation through C It 'Invoke-RestMethod: CTRL-C Cancels request before request headers received' { $uri = Get-WebListenerUrl -test Delay -TestValue 30 - RunWithCancellation -Command 'Invoke-RestMethod' -Uri $uri + RunWithCancellation -Command 'Invoke-RestMethod' -Uri $uri -DelayBeforeStopSimulationMs 1000 } It 'Invoke-RestMethod: CTRL-C Cancels request after JSON request headers received' { From 943508af93f5e5b45a96c3deb42c75f71a5361e9 Mon Sep 17 00:00:00 2001 From: stevenebutler Date: Thu, 20 Apr 2023 15:09:35 +1000 Subject: [PATCH 6/6] Add comment around stall time --- .../Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index 51cbe6e4caa..2b2968ea3da 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -4231,6 +4231,10 @@ Describe 'Invoke-WebRequest and Invoke-RestMethod support Cancellation through C $null = [System.Threading.Tasks.Task]::WaitAny($task, $delay) $task.IsCompleted | Should -Be $WillComplete.ToBool() $pwsh.Stop() + + # The download stall is normally 30 seconds from the web listener based + # on the first slash separated parameter in the -TestValue provided to + # Get-WebListenerUrl -test Stall -TestValue duration/content-type. Wait-UntilTrue { [bool]($Task.IsCompleted) } | Should -BeTrue $result = $pwsh.Runspace.SessionStateProxy.GetVariable('result') $pwsh.Dispose()