Fixed passing common test modules path to unelevated Powershell (#4313)
- Fixed the way common test modules are passed to elevated and unelevated powershell. Earlier, only elevated powershell got those through inheritance as a child process. Now we add them to the startup of the process. - Fixed error reported by PSScriptAnalyzer about ? / Where-Object - Converted all the parameters passed to powershell.exe to be a base64 encoded string to avoid complications with quotes. - Removed code which was updated $env:PSModulePath as we do it in startup args for powershell process instead. - Added a way to disable -Quiet for Pester. - Opencover.console.exe gets confused when the base64 encoded parameter is given with '&' invoke. Writing to a ps1 file and invoking the script works around the issue. This also makes it similar to how unelevated tests are invoked.
This commit is contained in:
parent
fc77c7981a
commit
5cd0e85d12
|
@ -1,7 +1,8 @@
|
|||
param(
|
||||
[Parameter(Mandatory = $true, Position = 0)] $coverallsToken,
|
||||
[Parameter(Mandatory = $true, Position = 1)] $codecovToken,
|
||||
[Parameter(Position = 2)] $azureLogDrive = "L:\"
|
||||
[Parameter(Position = 2)] $azureLogDrive = "L:\",
|
||||
[switch] $SuppressQuiet
|
||||
)
|
||||
|
||||
# Read the XML and create a dictionary for FileUID -> file full path.
|
||||
|
@ -168,7 +169,7 @@ try
|
|||
Install-OpenCover -TargetDirectory $openCoverTargetDirectory -force
|
||||
Write-LogPassThru -Message "OpenCover installed."
|
||||
|
||||
Write-LogPassThru -Message "TestDirectory : $testPath"
|
||||
Write-LogPassThru -Message "TestPath : $testPath"
|
||||
Write-LogPassThru -Message "openCoverPath : $openCoverTargetDirectory\OpenCover"
|
||||
Write-LogPassThru -Message "psbinpath : $psBinPath"
|
||||
Write-LogPassThru -Message "elevatedLog : $elevatedLogs"
|
||||
|
@ -176,7 +177,7 @@ try
|
|||
Write-LogPassThru -Message "TestToolsPath : $testToolsPath"
|
||||
|
||||
$openCoverParams = @{outputlog = $outputLog;
|
||||
TestDirectory = $testPath;
|
||||
TestPath = $testPath;
|
||||
OpenCoverPath = "$openCoverTargetDirectory\OpenCover";
|
||||
PowerShellExeDirectory = "$psBinPath";
|
||||
PesterLogElevated = $elevatedLogs;
|
||||
|
@ -184,6 +185,11 @@ try
|
|||
TestToolsModulesPath = "$testToolsPath\Modules";
|
||||
}
|
||||
|
||||
if($SuppressQuiet)
|
||||
{
|
||||
$openCoverParams.Add('SuppressQuiet', $true)
|
||||
}
|
||||
|
||||
$openCoverParams | Out-String | Write-LogPassThru
|
||||
Write-LogPassThru -Message "Starting test run."
|
||||
|
||||
|
|
|
@ -413,21 +413,22 @@ function Install-OpenCover
|
|||
.Description
|
||||
Invoke-OpenCover runs tests under OpenCover by executing tests on PowerShell.exe located at $PowerShellExeDirectory.
|
||||
.EXAMPLE
|
||||
Invoke-OpenCover -TestDirectory $pwd/test/powershell -PowerShellExeDirectory $pwd/src/powershell-win-core/bin/CodeCoverage/netcoreapp1.0/win10-x64
|
||||
Invoke-OpenCover -TestPath $pwd/test/powershell -PowerShellExeDirectory $pwd/src/powershell-win-core/bin/CodeCoverage/netcoreapp1.0/win10-x64
|
||||
#>
|
||||
function Invoke-OpenCover
|
||||
{
|
||||
[CmdletBinding(SupportsShouldProcess=$true)]
|
||||
param (
|
||||
[parameter()]$OutputLog = "$home/Documents/OpenCover.xml",
|
||||
[parameter()]$TestDirectory = "${script:psRepoPath}/test/powershell",
|
||||
[parameter()]$TestPath = "${script:psRepoPath}/test/powershell",
|
||||
[parameter()]$OpenCoverPath = "$home/OpenCover",
|
||||
[parameter()]$PowerShellExeDirectory = "${script:psRepoPath}/src/powershell-win-core/bin/CodeCoverage/netcoreapp2.0/win10-x64/publish",
|
||||
[parameter()]$PesterLogElevated = "$pwd/TestResultsElevated.xml",
|
||||
[parameter()]$PesterLogUnelevated = "$pwd/TestResultsUnelevated.xml",
|
||||
[parameter()]$PesterLogFormat = "NUnitXml",
|
||||
[parameter()]$TestToolsModulesPath = "${script:psRepoPath}/test/tools/Modules",
|
||||
[switch]$CIOnly
|
||||
[switch]$CIOnly,
|
||||
[switch]$SuppressQuiet
|
||||
)
|
||||
|
||||
# check for elevation
|
||||
|
@ -462,8 +463,10 @@ function Invoke-OpenCover
|
|||
|
||||
# create the arguments for OpenCover
|
||||
|
||||
$startupArgs = 'Set-ExecutionPolicy Bypass -Force -Scope Process;'
|
||||
$targetArgs = "-c","${startupArgs}", "Invoke-Pester","${TestDirectory}"
|
||||
$updatedEnvPath = "${PowerShellExeDirectory}\Modules;$TestToolsModulesPath"
|
||||
|
||||
$startupArgs = "Set-ExecutionPolicy Bypass -Force -Scope Process; `$env:PSModulePath = '${updatedEnvPath}';"
|
||||
$targetArgs = "${startupArgs}", "Invoke-Pester","${TestPath}","-OutputFormat $PesterLogFormat"
|
||||
|
||||
if ( $CIOnly )
|
||||
{
|
||||
|
@ -476,46 +479,40 @@ function Invoke-OpenCover
|
|||
$targetArgsUnelevated = $targetArgs + @("-excludeTag @('RequireAdminOnWindows')")
|
||||
}
|
||||
|
||||
$targetArgsElevated += @("-OutputFile $PesterLogElevated", "-OutputFormat $PesterLogFormat", "-Quiet")
|
||||
$targetArgsUnelevated += @("-OutputFile $PesterLogUnelevated", "-OutputFormat $PesterLogFormat", "-Quiet")
|
||||
$targetArgsElevated += @("-OutputFile $PesterLogElevated")
|
||||
$targetArgsUnelevated += @("-OutputFile $PesterLogUnelevated")
|
||||
|
||||
$targetArgStringElevated = $targetArgsElevated -join " "
|
||||
$targetArgStringUnelevated = $targetArgsUnelevated -join " "
|
||||
# the order seems to be important. Always keep -targetargs as the last parameter.
|
||||
$openCoverArgsElevated = "-target:$target","-register:user","-output:${outputLog}","-nodefaultfilters","-oldstyle","-hideskipped:all","-mergeoutput", "-filter:`"+[*]* -[Microsoft.PowerShell.PSReadLine]*`"", "-targetargs:`"$targetArgStringElevated`""
|
||||
$openCoverArgsUnelevated = "-target:$target","-register:user","-output:${outputLog}","-nodefaultfilters","-oldstyle","-hideskipped:all", "-mergeoutput", "-filter:`"+[*]* -[Microsoft.PowerShell.PSReadLine]*`"", "-targetargs:`"$targetArgStringUnelevated`""
|
||||
$openCoverArgsUnelevatedString = $openCoverArgsUnelevated -join " "
|
||||
if(-not $SuppressQuiet)
|
||||
{
|
||||
$targetArgsElevated += @("-Quiet")
|
||||
$targetArgsUnelevated += @("-Quiet")
|
||||
}
|
||||
|
||||
if ( $PSCmdlet.ShouldProcess("$OpenCoverBin $openCoverArgsUnelevated") )
|
||||
$cmdlineElevated = CreateOpenCoverCmdline -target $target -outputLog $OutputLog -targetArgs $targetArgsElevated
|
||||
$cmdlineUnelevated = CreateOpenCoverCmdline -target $target -outputLog $OutputLog -targetArgs $targetArgsUnelevated
|
||||
|
||||
if ( $PSCmdlet.ShouldProcess("$OpenCoverBin $cmdlineUnelevated") )
|
||||
{
|
||||
try
|
||||
{
|
||||
# check to be sure that the module path is present
|
||||
# this isn't done earlier because there's no need to change env:PSModulePath unless we're going to really run tests
|
||||
$saveModPath = $env:PSModulePath
|
||||
$env:PSModulePath = "${PowerShellExeDirectory}\Modules;$TestToolsModulesPath"
|
||||
|
||||
$modulePathParts = $env:PSModulePath -split ';'
|
||||
|
||||
foreach($part in $modulePathParts)
|
||||
{
|
||||
if ( ! (test-path $part) )
|
||||
{
|
||||
throw "${part} does not exist"
|
||||
}
|
||||
}
|
||||
|
||||
# invoke OpenCover elevated
|
||||
& $OpenCoverBin $openCoverArgsElevated
|
||||
# Write the command line to a file and then invoke file.
|
||||
# '&' invoke caused issues with cmdline parameters for opencover.console.exe
|
||||
$elevatedFile = "$env:temp\elevated.ps1"
|
||||
"$OpenCoverBin $cmdlineElevated" | Out-File -FilePath $elevatedFile -force
|
||||
powershell.exe -file $elevatedFile
|
||||
|
||||
# invoke OpenCover unelevated and poll for completion
|
||||
"$openCoverBin $openCoverArgsUnelevatedString" | Out-File -FilePath "$env:temp\unelevated.ps1" -Force
|
||||
runas.exe /trustlevel:0x20000 "powershell.exe -file $env:temp\unelevated.ps1"
|
||||
# wait for process to start
|
||||
Start-Sleep -Seconds 5
|
||||
$unelevatedFile = "$env:temp\unelevated.ps1"
|
||||
"$openCoverBin $cmdlineUnelevated" | Out-File -FilePath $unelevatedFile -Force
|
||||
runas.exe /trustlevel:0x20000 "powershell.exe -file $unelevatedFile"
|
||||
# poll for process exit every 60 seconds
|
||||
# timeout of 6 hours
|
||||
# Runs currently take about 2.5 - 3 hours, we picked 6 hours to be substantially larger.
|
||||
$timeOut = ([datetime]::Now).AddHours(6)
|
||||
|
||||
$openCoverExited = $false
|
||||
|
||||
while([datetime]::Now -lt $timeOut)
|
||||
{
|
||||
Start-Sleep -Seconds 60
|
||||
|
@ -524,15 +521,44 @@ function Invoke-OpenCover
|
|||
if(-not $openCoverProcess)
|
||||
{
|
||||
#run must have completed.
|
||||
$openCoverExited = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if(-not $openCoverExited)
|
||||
{
|
||||
throw "Opencover has not exited in 6 hours"
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
# set it back
|
||||
$env:PSModulePath = $saveModPath
|
||||
Remove-Item "$env:temp\unelevated.ps1" -force -ErrorAction SilentlyContinue
|
||||
Remove-Item $elevatedFile -force -ErrorAction SilentlyContinue
|
||||
Remove-Item $unelevatedFile -force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function CreateOpenCoverCmdline($target, $outputLog, $targetArgs)
|
||||
{
|
||||
$targetArgString = $targetArgs -join " "
|
||||
|
||||
$bytes = [System.Text.Encoding]::Unicode.GetBytes($targetArgString)
|
||||
$base64targetArgs = [convert]::ToBase64String($bytes)
|
||||
|
||||
# the order seems to be important. Always keep -targetargs as the last parameter.
|
||||
$cmdline = "-target:$target",
|
||||
"-register:user",
|
||||
"-output:${outputLog}",
|
||||
"-nodefaultfilters",
|
||||
"-oldstyle",
|
||||
"-hideskipped:all",
|
||||
"-mergeoutput",
|
||||
"-filter:`"+[*]* -[Microsoft.PowerShell.PSReadLine]*`"",
|
||||
"-targetargs:`"-EncodedCommand $base64targetArgs`""
|
||||
|
||||
$cmdlineAsString = $cmdline -join " "
|
||||
|
||||
return $cmdlineAsString
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue