From 486fb9712354d7b5489c2da27a9fa2a245b915e2 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 13 Oct 2017 13:54:43 -0700 Subject: [PATCH] Test fixes and code coverage automation fixes. (#5046) * Test fixes and updates to code coverage automation * Fixed UpdatableHelpSystem tests and tab completion tests * Fixed tab completion tests to better disambiguate root/interop namespace. * Skip SSH test if ssh.exe is not present --- .../TabCompletion/TabCompletion.Tests.ps1 | 17 +-- .../Get-Process.Tests.ps1 | 2 +- .../CredSSP.Tests.ps1 | 4 +- .../engine/Api/ProxyCommand.Tests.ps1 | 20 +++- .../engine/Help/HelpSystem.Tests.ps1 | 4 + .../engine/Help/UpdatableHelpSystem.Tests.ps1 | 2 +- .../engine/Remoting/SSHRemotingAPI.Tests.ps1 | 13 ++- .../Start-CodeCoverageRun.ps1 | 109 +++++++++++------- test/tools/OpenCover/OpenCover.psm1 | 4 +- 9 files changed, 114 insertions(+), 61 deletions(-) diff --git a/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 b/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 index fee88feeab..ca77821df8 100644 --- a/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 +++ b/test/powershell/Host/TabCompletion/TabCompletion.Tests.ps1 @@ -433,7 +433,8 @@ Describe "TabCompletion" -Tags CI { @{ inputStr = '$global:max'; expected = '$global:MaximumHistoryCount'; setup = $null } @{ inputStr = '$PSMod'; expected = '$PSModuleAutoLoadingPreference'; setup = $null } ## tab completion for variable in path - @{ inputStr = 'cd $pshome\Modu'; expected = Join-Path $PSHOME 'Modules'; setup = $null } + ## if $PSHOME contains a space tabcompletion adds ' around the path + @{ inputStr = 'cd $pshome\Modu'; expected = if($PSHOME.Contains(' ')) { "'$(Join-Path $PSHOME 'Modules')'" } else { Join-Path $PSHOME 'Modules' }; setup = $null } @{ inputStr = 'cd "$pshome\Modu"'; expected = "`"$(Join-Path $PSHOME 'Modules')`""; setup = $null } @{ inputStr = '$PSHOME\System.Management.Au'; expected = Join-Path $PSHOME 'System.Management.Automation.dll'; setup = $null } @{ inputStr = '"$PSHOME\System.Management.Au"'; expected = "`"$(Join-Path $PSHOME 'System.Management.Automation.dll')`""; setup = $null } @@ -467,7 +468,7 @@ Describe "TabCompletion" -Tags CI { $beforeTab = "\\localhost\$homeDrive\wind" $afterTab = "& '\\localhost\$homeDrive\Windows'" $res = TabExpansion2 -inputScript $beforeTab -cursorColumn $beforeTab.Length - $res.CompletionMatches.Count | Should BeExactly 1 + $res.CompletionMatches.Count | Should BeGreaterThan 0 $res.CompletionMatches[0].CompletionText | Should Be $afterTab } @@ -496,7 +497,7 @@ Describe "TabCompletion" -Tags CI { $afterTab = 'filesystem::/usr' -f $env:SystemDrive } $res = TabExpansion2 -inputScript $beforeTab -cursorColumn $beforeTab.Length - $res.CompletionMatches.Count | Should BeExactly 1 + $res.CompletionMatches.Count | Should BeGreaterThan 0 $res.CompletionMatches[0].CompletionText | Should Be $afterTab } @@ -914,13 +915,13 @@ dir -Recurse ` @{ inputStr = 'Get-CimInstance Win32_Process | ?{ $_.ProcessId -eq $Pid } | Get-CimAssociatedInstance -ResultClassName Win32_ComputerS'; expected = 'Win32_ComputerSystem' } @{ inputStr = 'Get-CimInstance -Namespace root/Interop -ClassName Win32_PowerSupplyP'; expected = 'Win32_PowerSupplyProfile' } @{ inputStr = 'Get-CimInstance __NAMESP'; expected = '__NAMESPACE' } - @{ inputStr = 'Get-CimInstance -Namespace root/Int'; expected = 'root/Interop' } + @{ inputStr = 'Get-CimInstance -Namespace root/Inter'; expected = 'root/Interop' } @{ inputStr = 'Get-CimInstance -Namespace root/Int*ro'; expected = 'root/Interop' } @{ inputStr = 'Get-CimInstance -Namespace root/Interop/'; expected = 'root/Interop/ms_409' } - @{ inputStr = 'New-CimInstance -Namespace root/Int'; expected = 'root/Interop' } - @{ inputStr = 'Invoke-CimMethod -Namespace root/Int'; expected = 'root/Interop' } - @{ inputStr = 'Get-CimClass -Namespace root/Int'; expected = 'root/Interop' } - @{ inputStr = 'Register-CimIndicationEvent -Namespace root/Int'; expected = 'root/Interop' } + @{ inputStr = 'New-CimInstance -Namespace root/Inter'; expected = 'root/Interop' } + @{ inputStr = 'Invoke-CimMethod -Namespace root/Inter'; expected = 'root/Interop' } + @{ inputStr = 'Get-CimClass -Namespace root/Inter'; expected = 'root/Interop' } + @{ inputStr = 'Register-CimIndicationEvent -Namespace root/Inter'; expected = 'root/Interop' } @{ inputStr = '[Microsoft.Management.Infrastructure.CimClass]$c = $null; $c.CimClassNam'; expected = 'CimClassName' } @{ inputStr = '[Microsoft.Management.Infrastructure.CimClass]$c = $null; $c.CimClassName.Substrin'; expected = 'Substring(' } @{ inputStr = 'Get-CimInstance -ClassName Win32_Process | %{ $_.ExecutableP'; expected = 'ExecutablePath' } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Get-Process.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Get-Process.Tests.ps1 index 7be9a80631..1b4cd9221a 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Get-Process.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Get-Process.Tests.ps1 @@ -1,6 +1,6 @@ Describe "Get-Process for admin" -Tags @('CI', 'RequireAdminOnWindows') { It "Should support -IncludeUserName" { - (Get-Process powershell -IncludeUserName | Select-Object -First 1).UserName | Should Match $env:USERNAME + (Get-Process -Id $pid -IncludeUserName).UserName | Should Match $env:USERNAME } } diff --git a/test/powershell/Modules/Microsoft.WSMan.Management/CredSSP.Tests.ps1 b/test/powershell/Modules/Microsoft.WSMan.Management/CredSSP.Tests.ps1 index d588609541..5d6c310aef 100644 --- a/test/powershell/Modules/Microsoft.WSMan.Management/CredSSP.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.WSMan.Management/CredSSP.Tests.ps1 @@ -10,7 +10,7 @@ Describe "CredSSP cmdlet tests" -Tags 'Feature','RequireAdminOnWindows' { { $PSDefaultParameterValues["it:skip"] = $true } - else + else { if ([System.Globalization.CultureInfo]::CurrentCulture.Name -ne "en-US") { @@ -18,7 +18,7 @@ Describe "CredSSP cmdlet tests" -Tags 'Feature','RequireAdminOnWindows' { } } } - + AfterAll { $global:PSDefaultParameterValues = $originalDefaultParameterValues } diff --git a/test/powershell/engine/Api/ProxyCommand.Tests.ps1 b/test/powershell/engine/Api/ProxyCommand.Tests.ps1 index 05fdbc5532..9abb8717f4 100644 --- a/test/powershell/engine/Api/ProxyCommand.Tests.ps1 +++ b/test/powershell/engine/Api/ProxyCommand.Tests.ps1 @@ -3,6 +3,21 @@ using namespace System.Collections.ObjectModel Describe 'ProxyCommand Tests' -Tags "CI" { BeforeAll { + function NormalizeCRLF { + param ($helpObj) + + if($helpObj.Synopsis.Contains("`r`n")) + { + $helpObjText = ($helpObj.Synopsis).replace("`r`n", [System.Environment]::NewLine).trim() + } + else + { + $helpObjText = ($helpObj.Synopsis).replace("`n", [System.Environment]::NewLine).trim() + } + + return $helpObjText + } + function GetSectionText { param ($object) $texts = $object | Out-String -Stream | ForEach-Object { @@ -82,7 +97,10 @@ Describe 'ProxyCommand Tests' -Tags "CI" { Set-Item -Path function:\TestHelpComment -Value $bodySB $newHelpObj = Get-Help TestHelpComment -Full - $helpObj.Synopsis | Should Be $newHelpObj.Synopsis + $helpObjText = NormalizeCRLF -helpObj $helpObj + $newHelpObjText = NormalizeCRLF -helpObj $newHelpObj + + $helpObjText | Should Be $newHelpObjText $oldDespText = GetSectionText $helpObj.description $newDespText = GetSectionText $newHelpObj.description $oldDespText | Should Be $newDespText diff --git a/test/powershell/engine/Help/HelpSystem.Tests.ps1 b/test/powershell/engine/Help/HelpSystem.Tests.ps1 index e7770e0ff5..c872b7a5d1 100644 --- a/test/powershell/engine/Help/HelpSystem.Tests.ps1 +++ b/test/powershell/engine/Help/HelpSystem.Tests.ps1 @@ -188,10 +188,14 @@ Describe "Validate about_help.txt under culture specific folder works" -Tags @(' New-ModuleManifest -Path $modulePath\test.psd1 -RootModule test.psm1 Set-Content -Path $modulePath\test.psm1 -Value "function foo{}" Set-Content -Path $modulePath\en-US\about_testhelp.help.txt -Value "Hello" -NoNewline + ## This is needed for getting about topics. We use -Force, so we always update. + Update-Help -Force } AfterAll { Remove-Item $modulePath -Recurse -Force + # Remove all the help content. + Get-ChildItem -Path $PSHOME -Include @('about_*.txt', "*help.xml") -Recurse | Remove-Item -Force -ErrorAction SilentlyContinue } It "Get-Help should return help text and not multiple HelpInfo objects when help is under `$pshome path" { diff --git a/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 b/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 index 6f257fd6cb..0f38be9a5e 100644 --- a/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 +++ b/test/powershell/engine/Help/UpdatableHelpSystem.Tests.ps1 @@ -178,7 +178,7 @@ function RunUpdateHelpTests It "Validate Update-Help for module '$moduleName'" -Pending:$Pending { # If the help file is already installed, delete it. - Get-ChildItem $testCases[$moduleName].HelpInstallationPath -Include @("about_*.txt","*help.xml") -Recurse -ea SilentlyContinue | + Get-ChildItem $testCases[$moduleName].HelpInstallationPath -Include @("*help.xml") -Recurse -ea SilentlyContinue | Remove-Item -Force -ErrorAction SilentlyContinue if ((Get-UICulture).Name -ne "en-Us") diff --git a/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 b/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 index 22e7af6107..1b041d3e8c 100644 --- a/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 +++ b/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 @@ -2,6 +2,11 @@ Describe "SSH Remoting API Tests" -Tags "Feature" { Context "SSHConnectionInfo Class Tests" { + BeforeAll { + ## Skip the test if ssh is not present. + $skipTest = (Get-Command 'ssh' -CommandType Application -ErrorAction SilentlyContinue) -eq $null + } + AfterEach { if ($null -ne $rs) { $rs.Dispose() @@ -17,7 +22,7 @@ Describe "SSH Remoting API Tests" -Tags "Feature" { 0) } | ShouldBeErrorId "PSArgumentNullException" } - It "SSHConnectionInfo should throw file not found exception for invalid key file path" { + It "SSHConnectionInfo should throw file not found exception for invalid key file path" -Skip:$skipTest { try { @@ -29,7 +34,7 @@ Describe "SSH Remoting API Tests" -Tags "Feature" { $rs = [runspacefactory]::CreateRunspace($sshConnectionInfo) $rs.Open() - + throw "No Exception!" } catch @@ -39,7 +44,7 @@ Describe "SSH Remoting API Tests" -Tags "Feature" { } It "SSHConnectionInfo should throw argument exception for invalid port (non 16bit uint)" { - try + try { $sshConnectionInfo = [System.Management.Automation.Runspaces.SSHConnectionInfo]::new( "UserName", @@ -49,7 +54,7 @@ Describe "SSH Remoting API Tests" -Tags "Feature" { $rs = [runspacefactory]::CreateRunspace($sshConnectionInfo) $rs.Open() - + throw "No Exception!" } catch diff --git a/test/tools/CodeCoverageAutomation/Start-CodeCoverageRun.ps1 b/test/tools/CodeCoverageAutomation/Start-CodeCoverageRun.ps1 index 349d644f96..566e007c8f 100644 --- a/test/tools/CodeCoverageAutomation/Start-CodeCoverageRun.ps1 +++ b/test/tools/CodeCoverageAutomation/Start-CodeCoverageRun.ps1 @@ -54,7 +54,7 @@ function ConvertTo-CodeCovJson $progress=0 foreach($f in $keys) { - Write-Progress -Id 1 -Activity "Converting to JSON" -Status 'Converting' -PercentComplete ($progress * 100 / $keys.Count) + Write-Progress -Id 1 -Activity "Converting to JSON" -Status 'Converting' -PercentComplete ($progress * 100 / $keys.Count) $fileCoverage = GetSequencePointsForFile -fileId $f $fileName = $Script:fileTable[$f] $previousFileCoverage = $totalCoverage.coverage.${fileName} @@ -77,7 +77,7 @@ function ConvertTo-CodeCovJson Write-Progress -Id 1 -Completed -Activity "Converting to JSON" - $totalCoverage | ConvertTo-Json -Depth 5 -Compress | out-file $DestinationPath -Encoding ascii + $totalCoverage | ConvertTo-Json -Depth 5 -Compress | Out-File $DestinationPath -Encoding ascii } function Write-LogPassThru @@ -151,26 +151,67 @@ try $oldErrorActionPreference = $ErrorActionPreference $ErrorActionPreference = 'Stop' + $oldProgressPreference = $ProgressPreference + $ProgressPreference = 'SilentlyContinue' Write-LogPassThru -Message "Starting downloads." + + $CoverageZipFilePath = "$outputBaseFolder\PSCodeCoverage.zip" + if(Test-Path $CoverageZipFilePath) + { + Remove-Item $CoverageZipFilePath -Force + } Invoke-WebRequest -uri $codeCoverageZip -outfile "$outputBaseFolder\PSCodeCoverage.zip" - Invoke-WebRequest -uri $testContentZip -outfile "$outputBaseFolder\tests.zip" - Invoke-WebRequest -uri $openCoverZip -outfile "$outputBaseFolder\OpenCover.zip" + + $TestsZipFilePath = "$outputBaseFolder\tests.zip" + if(Test-Path $TestsZipFilePath) + { + Remove-Item $TestsZipFilePath -Force + } + Invoke-WebRequest -uri $testContentZip -outfile $TestsZipFilePath + + $OpenCoverZipFilePath = "$outputBaseFolder\OpenCover.zip" + if(Test-Path $OpenCoverZipFilePath) + { + Remove-Item $OpenCoverZipFilePath -Force + } + Invoke-WebRequest -uri $openCoverZip -outfile $OpenCoverZipFilePath + Write-LogPassThru -Message "Downloads complete. Starting expansion" - Expand-Archive -path "$outputBaseFolder\PSCodeCoverage.zip" -destinationpath "$psBinPath" -Force - Expand-Archive -path "$outputBaseFolder\tests.zip" -destinationpath $testRootPath -Force - Expand-Archive -path "$outputBaseFolder\OpenCover.zip" -destinationpath $openCoverPath -Force + if(Test-Path $psBinPath) + { + Remove-Item -Force -Recurse $psBinPath + } + Expand-Archive -path $CoverageZipFilePath -destinationpath "$psBinPath" -Force - ## Download Coveralls.net uploader - $coverallsToolsUrl = 'https://github.com/csMACnz/coveralls.net/releases/download/0.7.0/coveralls.net.0.7.0.nupkg' - $coverallsPath = "$outputBaseFolder\coveralls" - - ## Saving the nupkg as zip so we can expand it. - Invoke-WebRequest -uri $coverallsToolsUrl -outfile "$outputBaseFolder\coveralls.zip" - Expand-Archive -Path "$outputBaseFolder\coveralls.zip" -DestinationPath $coverallsPath -Force + if(Test-Path $testRootPath) + { + Remove-Item -Force -Recurse $testRootPath + } + Expand-Archive -path $TestsZipFilePath -destinationpath $testRootPath -Force + if(Test-Path $openCoverPath) + { + Remove-Item -Force -Recurse $openCoverPath + } + Expand-Archive -path $OpenCoverZipFilePath -destinationpath $openCoverPath -Force Write-LogPassThru -Message "Expansion complete." + if(Test-Path $elevatedLogs) + { + Remove-Item -Force -Recurse $elevatedLogs + } + + if(Test-Path $unelevatedLogs) + { + Remove-Item -Force -Recurse $unelevatedLogs + } + + if(Test-Path $outputLog) + { + Remove-Item $outputLog -Force -ErrorAction SilentlyContinue + } + Import-Module "$openCoverPath\OpenCover" -Force Install-OpenCover -TargetDirectory $openCoverTargetDirectory -force Write-LogPassThru -Message "OpenCover installed." @@ -210,11 +251,15 @@ try # clean up partial repo clone before starting if ( Test-Path "$outputBaseFolder/.git" ) { - remove-item -force -recurse "${outputBaseFolder}/.git" + Remove-Item -Force -Recurse "${outputBaseFolder}/.git" } if ( Test-Path "$outputBaseFolder/src" ) { - remove-item -force -recurse "${outputBaseFolder}/src" + Remove-Item -Force -Recurse "${outputBaseFolder}/src" + } + if ( Test-Path "$outputBaseFolder/assests" ) + { + Remove-Item -Force -Recurse "${outputBaseFolder}/assets" } Write-LogPassThru -Message "initializing repo in $outputBaseFolder" & $gitexe init @@ -229,7 +274,8 @@ try Write-LogPassThru -Message "git operation 'set sparse-checkout' returned $LASTEXITCODE" Write-LogPassThru -Message "pulling sparse repo" - "src" | out-file -encoding ascii .git\info\sparse-checkout + "src" | Out-File -Encoding ascii .git\info\sparse-checkout -Force + "assets" | Out-File -Encoding ascii .git\info\sparse-checkout -Append & $gitexe pull origin master Write-LogPassThru -Message "git operation 'pull' returned $LASTEXITCODE" @@ -245,10 +291,6 @@ try $openCoverParams | Out-String | Write-LogPassThru Write-LogPassThru -Message "Starting test run." - if(Test-Path $outputLog) - { - Remove-Item $outputLog -Force -ErrorAction SilentlyContinue - } # now invoke opencover Invoke-OpenCover @openCoverParams @@ -261,31 +303,11 @@ try Write-LogPassThru -Message $commitId - $coverallsPath = "$outputBaseFolder\coveralls" - $commitInfo = Invoke-RestMethod -Method Get "https://api.github.com/repos/powershell/powershell/git/commits/$commitId" $message = ($commitInfo.message).replace("`n", " ") - $author = $commitInfo.author.name - $email = $commitInfo.author.email - - $coverallsExe = Join-Path $coverallsPath "tools\csmacnz.Coveralls.exe" - $coverallsParams = @("--opencover", - "-i $outputLog", - "--repoToken $coverallsToken", - "--commitId $commitId", - "--commitBranch master", - "--commitAuthor `"$author`"", - "--commitEmail $email", - "--commitMessage `"$message`"" - ) - - $coverallsParams | ForEach-Object { Write-LogPassThru -Message $_ } - - Write-LogPassThru -Message "Uploading to CoverAlls" - & $coverallsExe """$coverallsParams""" Write-LogPassThru -Message "Uploading to CodeCov" - if ( test-path $outputLog ) { + if ( Test-Path $outputLog ) { ConvertTo-CodeCovJson -Path $outputLog -DestinationPath $jsonFile Push-CodeCovData -file $jsonFile -CommitID $commitId -token $codecovToken -Branch 'master' @@ -303,7 +325,7 @@ finally { # the powershell execution should be done, be sure that there are no PowerShell test executables running because # they will cause subsequent coverage runs to behave poorly. Make sure that the path is properly formatted, and - # we need to use like rather than match because on Windows, there will be "\" as path separators which would need + # we need to use like rather than match because on Windows, there will be "\" as path separators which would need # escaping for -match $ResolvedPSBinPath = (Resolve-Path ${psbinpath}).Path Get-Process PowerShell | Where-Object { $_.Path -like "*${ResolvedPSBinPath}*" } | Stop-Process -Force -ErrorAction Continue @@ -328,4 +350,5 @@ finally ## Disable the cleanup till we stabilize. #Remove-Item -recurse -force -path $outputBaseFolder $ErrorActionPreference = $oldErrorActionPreference + $ProgressPreference = $oldProgressPreference } diff --git a/test/tools/OpenCover/OpenCover.psm1 b/test/tools/OpenCover/OpenCover.psm1 index d7cd0468a2..9c765677a8 100644 --- a/test/tools/OpenCover/OpenCover.psm1 +++ b/test/tools/OpenCover/OpenCover.psm1 @@ -664,8 +664,10 @@ function Invoke-OpenCover # create the arguments for OpenCover $updatedEnvPath = "${PowerShellExeDirectory}\Modules;$TestToolsModulesPath" + $testToolsExePath = (Resolve-Path(Join-Path $TestPath -ChildPath "..\tools\TestExe\bin")).Path + $updatedProcessEnvPath = "${testToolsExePath};${env:PATH}" - $startupArgs = "Set-ExecutionPolicy Bypass -Force -Scope Process; `$env:PSModulePath = '${updatedEnvPath}';" + $startupArgs = "Set-ExecutionPolicy Bypass -Force -Scope Process; `$env:PSModulePath = '${updatedEnvPath}'; `$env:Path = '${updatedProcessEnvPath}'" $targetArgs = "${startupArgs}", "Invoke-Pester","${TestPath}","-OutputFormat $PesterLogFormat" if ( $CIOnly )