| 1 | #Requires -RunAsAdministrator |
| 2 | |
| 3 | <# |
| 4 | .SYNOPSIS |
| 5 | Runs all WSL tests; optionally sets-up a WSL distribution and environment prior to running the tests. |
| 6 | .PARAMETER Version |
| 7 | The version of WSL to run the tests in. Defaults to "2". |
| 8 | .PARAMETER SetupScript |
| 9 | Path to a setup script to be run prior to running the tests. Defaults to ".\test-setup.ps1". |
| 10 | .PARAMETER DistroPath |
| 11 | Path to a .tar/.tar.gz file of the distro to be imported to run the tests with. Defaults to ".\test_distro.tar.gz". |
| 12 | .PARAMETER TestDataPath |
| 13 | Path to test data folder. Defaults to ".\test_data". |
| 14 | .PARAMETER Package |
| 15 | Path to the wsl.msix package to install. Defaults to ".\installer.msix". |
| 16 | .PARAMETER UnitTestsPath |
| 17 | Path to the linux/unit_tests directory to copy and install the unit tests. |
| 18 | .PARAMETER PullRequest |
| 19 | Switch for whether or not this test pass is being run as a part of a pull request; skips certain tests if present. Defaults to $false. |
| 20 | .PARAMETER TestDllPath |
| 21 | Path to the TAEF test DLL. Defaults to ".\wsltests.dll". |
| 22 | .PARAMETER Fast |
| 23 | Handy flag to skip package and distro installation to make tests run faster during development. |
| 24 | .PARAMETER TeArgs |
| 25 | Additional arguments for TE.exe. |
| 26 | #> |
| 27 | |
| 28 | [cmdletbinding(PositionalBinding = $false)] |
| 29 | param ( |
| 30 | [string]$Version = 2, |
| 31 | [string]$SetupScript = ".\test-setup.ps1", |
| 32 | [string]$DistroPath = ".\test_distro.tar.gz", |
| 33 | [string]$TestDataPath = ".\test_data", |
| 34 | [string]$Package = ".\installer.msix", |
| 35 | [string]$UnitTestsPath = ".\unit_tests", |
| 36 | [switch]$PullRequest = $false, |
| 37 | [string]$TestDllPath = ".\wsltests.dll", |
| 38 | [switch]$Fast = $false, |
| 39 | [parameter(ValueFromRemainingArguments = $true)] |
| 40 | [string[]]$TeArgs |
| 41 | ) |
| 42 | |
| 43 | Set-StrictMode -Version Latest |
| 44 | $ErrorActionPreference = "Stop" |
| 45 | |
| 46 | if ($Fast) |
| 47 | { |
| 48 | $SetupScript = $null |
| 49 | } |
| 50 | |
| 51 | $Verifier = $false |
| 52 | $VerifierTargets = @( |
| 53 | "wsl.exe", |
| 54 | "wslc.exe", |
| 55 | "wslhost.exe", |
| 56 | "wslrelay.exe", |
| 57 | "wslservice.exe", |
| 58 | "wslg.exe", |
| 59 | "wslcsession.exe", |
| 60 | "dllhost.exe", |
| 61 | "te.exe", |
| 62 | "TE.ProcessHost.exe" |
| 63 | ) |
| 64 | |
| 65 | if ($TeArgs -and ($TeArgs -icontains '/verifier')) |
| 66 | { |
| 67 | $TeArgs = @($TeArgs | Where-Object { $_ -ine '/verifier' }) |
| 68 | $Verifier = $true |
| 69 | } |
| 70 | |
| 71 | # Handle /attachdebugger: verify WinDbgX is available, then add /waitfordebugger so we can find and attach to the test host. |
| 72 | $AttachDebugger = $false |
| 73 | if ($TeArgs -and ($TeArgs -icontains '/attachdebugger')) |
| 74 | { |
| 75 | $TeArgs = @($TeArgs | Where-Object { $_ -ine '/attachdebugger' }) |
| 76 | if (Get-Command "WinDbgX.exe" -ErrorAction SilentlyContinue) |
| 77 | { |
| 78 | $AttachDebugger = $true |
| 79 | $TeArgs += '/waitfordebugger' |
| 80 | # Run in-process so WinDbgX can attach directly to TE.exe without |
| 81 | # polling for a TE.ProcessHost.exe child process. |
| 82 | if (-not ($TeArgs -icontains '/inproc')) |
| 83 | { |
| 84 | $TeArgs += '/inproc' |
| 85 | } |
| 86 | } |
| 87 | else |
| 88 | { |
| 89 | Write-Warning "/attachdebugger was requested, but WinDbgX.exe was not found. Continuing without debugger." |
| 90 | } |
| 91 | } |
| 92 | |
| 93 | $teArgList = @($TestDllPath, "/p:SetupScript=$SetupScript", "/p:Version=$Version", "/p:DistroPath=$DistroPath", "/p:TestDataPath=$TestDataPath", |
| 94 | "/p:Package=$Package", "/p:UnitTestsPath=$UnitTestsPath", "/p:PullRequest=$PullRequest", "/p:AllowUnsigned=1") + $TeArgs |
| 95 | |
| 96 | $verifierTargetsEnabled = @() |
| 97 | $testExitCode = 0 |
| 98 | try |
| 99 | { |
| 100 | if ($Verifier) |
| 101 | { |
| 102 | foreach ($target in $VerifierTargets) |
| 103 | { |
| 104 | & appverif.exe -verify $target |
| 105 | if ($LASTEXITCODE -ne 0) |
| 106 | { |
| 107 | throw "Failed to enable Application Verifier for $target (exit code: $LASTEXITCODE)." |
| 108 | } |
| 109 | |
| 110 | $verifierTargetsEnabled += $target |
| 111 | |
| 112 | # Required otherwise calls like std::chrono::current_zone() are reported as leaks |
| 113 | & appverif.exe -enable Leak -for $target -with "Leak.ExcludeUCRT=true" |
| 114 | if ($LASTEXITCODE -ne 0) |
| 115 | { |
| 116 | throw "Failed to exclude UCRT allocations from leak detection for $target (exit code: $LASTEXITCODE)." |
| 117 | } |
| 118 | |
| 119 | & appverif.exe -enable Handles -for $target -with "Handles.Traces=65536" |
| 120 | if ($LASTEXITCODE -ne 0) |
| 121 | { |
| 122 | throw "Failed to configure handle tracing for $target (exit code: $LASTEXITCODE)." |
| 123 | } |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | if ($AttachDebugger) |
| 128 | { |
| 129 | $teProcess = Start-Process -FilePath "te.exe" -ArgumentList $teArgList -PassThru -NoNewWindow |
| 130 | |
| 131 | # /inproc is always added above, so attach directly to TE.exe. |
| 132 | Write-Host "Launching WinDbgX attached to TE.exe (PID: $($teProcess.Id))..." |
| 133 | Start-Process "WinDbgX.exe" -ArgumentList "-p $($teProcess.Id)" |
| 134 | |
| 135 | $teProcess | Wait-Process |
| 136 | $testExitCode = $teProcess.ExitCode |
| 137 | } |
| 138 | else |
| 139 | { |
| 140 | te.exe $teArgList |
| 141 | $testExitCode = $LASTEXITCODE |
| 142 | } |
| 143 | } |
| 144 | finally |
| 145 | { |
| 146 | $cleanupFailures = @() |
| 147 | foreach ($target in $verifierTargetsEnabled) |
| 148 | { |
| 149 | & appverif.exe -delete settings -for $target |
| 150 | if ($LASTEXITCODE -ne 0) |
| 151 | { |
| 152 | $cleanupFailures += $target |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | if ($cleanupFailures.Count -ne 0) |
| 157 | { |
| 158 | Write-Error "Failed to disable Application Verifier for: $($cleanupFailures -join ', ')." |
| 159 | } |
| 160 | } |
| 161 | |
| 162 | exit $testExitCode |