Skip to content

Commit

Permalink
Make CodeCoverage tests work with CodeCov.io and related fixes (#4050)
Browse files Browse the repository at this point in the history
* Fixed OpenCover module and CodeCoverage launcher script

* Changes to layout of package caused some changes to package path.
* Added Test modules from tests\tools\modules
* Fixed Get-ChildItem test
* Added convertor for converting OpenCover output file to JSON.
* Updated how the file is uploaded to CodeCov.io

* Addressed code review comments
  • Loading branch information
adityapatwardhan authored and TravisEz13 committed Jun 22, 2017
1 parent 18cddc9 commit c7b959b
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 30 deletions.
Expand Up @@ -60,11 +60,11 @@ Describe "Get-ChildItem" -Tags "CI" {
$files.Count | Should be 1
$files[0].Name | Should Be $item_F
}
It "Should give .sys file if the fullpath is specified with hidden and force parameter" -Skip:(!$IsWindows){
$file = Get-ChildItem -path "$env:SystemDrive\\pagefile.sys" -Hidden
$file | Should not be $null
It "Should find the hidden file if specified with hidden switch" {
$file = Get-ChildItem -Path (Join-Path $TestDrive $item_F) -Hidden
$file | Should Not BeNullOrEmpty
$file.Count | Should be 1
$file.Name | Should be "pagefile.sys"
$file.Name | Should be $item_F
}
It "Should continue enumerating a directory when a contained item is deleted" {
$Error.Clear()
Expand Down
106 changes: 88 additions & 18 deletions test/tools/CodeCoverageAutomation/Start-CodeCoverageRun.ps1
Expand Up @@ -4,6 +4,81 @@
[Parameter(Position = 2)] $azureLogDrive = "L:\"
)

# Read the XML and create a dictionary for FileUID -> file full path.
function GetFileTable()
{
$files = $script:covData | Select-Xml './/File'
foreach($file in $files)
{
$script:fileTable[$file.Node.uid] = $file.Node.fullPath
}
}

# Get sequence points for a particular file
function GetSequencePointsForFile([string] $fileId)
{
$lineCoverage = [System.Collections.Generic.Dictionary[string,int]]::new()

$sequencePoints = $script:covData | Select-Xml ".//SequencePoint[@fileid = '$fileId']"

if($sequencePoints.Count -gt 0)
{
foreach($sp in $sequencePoints)
{
$visitedCount = [int]::Parse($sp.Node.vc)
$lineNumber = [int]::Parse($sp.Node.sl)
$lineCoverage[$lineNumber] += [int]::Parse($visitedCount)
}

return $lineCoverage
}
}

#### Convert the OpenCover XML output for CodeCov.io JSON format as it is smaller.
function ConvertTo-CodeCovJson
{
param(
[string] $Path,
[string] $DestinationPath
)

$Script:fileTable = [ordered]@{}
$Script:covData = [xml] (Get-Content -ReadCount 0 -Raw -Path $Path)
$totalCoverage = [PSCustomObject]::new()
$totalCoverage | Add-Member -MemberType NoteProperty -Name "coverage" -Value ([PSCustomObject]::new())

## Populate the dictionary with file uid and file names.
GetFileTable
$keys = $Script:fileTable.Keys
$progress=0
foreach($f in $keys)
{
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}

##Update the values for the lines in the file.
if($previousFileCoverage -ne $null)
{
foreach($lineNumber in $fileCoverage.Keys)
{
$previousFileCoverage[$lineNumber] += [int]::Parse($fileCoverage[$lineNumber])
}
}
else ## the file is new, so add the values as a new NoteProperty.
{
$totalCoverage.coverage | Add-Member -MemberType NoteProperty -Value $fileCoverage -Name $fileName
}

$progress++
}

Write-Progress -Id 1 -Completed -Activity "Converting to JSON"

$totalCoverage | ConvertTo-Json -Depth 5 -Compress | out-file $DestinationPath -Encoding ascii
}

function Write-LogPassThru
{
Param(
Expand All @@ -28,19 +103,9 @@ function Push-CodeCovData
$url="https://codecov.io"

$query = "package=bash-${VERSION}&token=${token}&branch=${Branch}&commit=${CommitID}&build=&build_url=&tag=&slug=&yaml=&service=&flags=&pr=&job="
$uri = "$url/upload/v2?${query}"
$response = Invoke-WebRequest -Method Post -InFile $file -Uri $uri

$CodeCovHeader = @{ Accept = "text/plain" }
$uri = "$url/upload/v4?${query}"
$response = Invoke-WebRequest -Method POST -Uri $uri -Headers $CodeCovHeader
if ( $response.StatusCode -ne 200 )
{
Write-LogPassThru -Message "Could not get upload url for request $uri"
throw "Could not get upload url"
}
$uploaduri = $response.content.split("`n")[-1]

$UploadHeader = @{ "Content-Type" = "text/plain"; "x-amz-acl" = "public-read"; "x-amz-storage-class" = "REDUCED_REDUNDANCY" }
$response = Invoke-WebRequest -Method Put -Uri $uploaduri -InFile $file -Headers $UploadHeader
if ( $response.StatusCode -ne 200 )
{
Write-LogPassThru -Message "Upload failed for upload uri: $uploaduri"
Expand All @@ -65,15 +130,15 @@ $outputBaseFolder = "$env:Temp\CC"
$null = New-Item -ItemType Directory -Path $outputBaseFolder -Force

$openCoverPath = "$outputBaseFolder\OpenCover"
$testPath = "$outputBaseFolder\tests"
$testRootPath = "$outputBaseFolder\tests"
$testPath = "$testRootPath\powershell"
$psBinPath = "$outputBaseFolder\PSCodeCoverage"
$openCoverTargetDirectory = "$outputBaseFolder\OpenCoverToolset"
$outputLog = "$outputBaseFolder\CodeCoverageOutput.xml"
$psCodeZip = "$outputBaseFolder\PSCode.zip"
$psCodePath = "$outputBaseFolder\PSCode"
$elevatedLogs = "$outputBaseFolder\TestResults_Elevated.xml"
$unelevatedLogs = "$outputBaseFolder\TestResults_Unelevated.xml"
$testToolsPath = "$testPath\tools"
$testToolsPath = "$testRootPath\tools"
$jsonFile = "$outputBaseFolder\CC.json"

try
{
Expand All @@ -86,7 +151,7 @@ try
Write-LogPassThru -Message "Downloads complete. Starting expansion"

Expand-Archive -path "$outputBaseFolder\PSCodeCoverage.zip" -destinationpath "$psBinPath" -Force
Expand-Archive -path "$outputBaseFolder\tests.zip" -destinationpath $testPath -Force
Expand-Archive -path "$outputBaseFolder\tests.zip" -destinationpath $testRootPath -Force
Expand-Archive -path "$outputBaseFolder\OpenCover.zip" -destinationpath $openCoverPath -Force

## Download Coveralls.net uploader
Expand Down Expand Up @@ -165,7 +230,8 @@ try
& $coverallsExe """$coverallsParams"""

Write-LogPassThru -Message "Uploading to CodeCov"
Push-CodeCovData -file $outputLog -CommitID $commitId -token $codecovToken -Branch 'master'
ConvertTo-CodeCovJson -Path $outputLog -DestinationPath $jsonFile
Push-CodeCovData -file $jsonFile -CommitID $commitId -token $codecovToken -Branch 'master'

Write-LogPassThru -Message "Upload complete."
}
Expand All @@ -192,5 +258,9 @@ finally

## Disable the cleanup till we stabilize.
#Remove-Item -recurse -force -path $outputBaseFolder

## This is required so we do not keep on merging coverage reports.
Remove-Item $outputLog -Force -ErrorAction SilentlyContinue

$ErrorActionPreference = $oldErrorActionPreference
}
32 changes: 24 additions & 8 deletions test/tools/OpenCover/OpenCover.psm1
Expand Up @@ -433,6 +433,16 @@ function Invoke-OpenCover
[switch]$CIOnly
)

# check for elevation
$identity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object System.Security.Principal.WindowsPrincipal($identity)
$isElevated = $principal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)

if(-not $isElevated)
{
throw 'Please run from an elevated PowerShell.'
}

# check to be sure that OpenCover is present

$OpenCoverBin = "$OpenCoverPath\opencover.console.exe"
Expand All @@ -455,7 +465,7 @@ function Invoke-OpenCover

# create the arguments for OpenCover

$startupArgs = '$env:PSModulePath = "${env:PSModulePath};$TestToolsPath";Set-ExecutionPolicy Bypass -Force -Scope Process;'
$startupArgs = 'Set-ExecutionPolicy Bypass -Force -Scope Process;'
$targetArgs = "-c","${startupArgs}", "Invoke-Pester","${TestDirectory}"

if ( $CIOnly )
Expand Down Expand Up @@ -486,10 +496,16 @@ function Invoke-OpenCover
# 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"
if ( ! (test-path $env:PSModulePath) )
$env:PSModulePath = "${PowerShellExeDirectory}\Modules;$TestToolsModulesPath"

$modulePathParts = $env:PSModulePath -split ';'

foreach($part in $modulePathParts)
{
throw "${env:PSModulePath} does not exist"
if ( ! (test-path $part) )
{
throw "${part} does not exist"
}
}

# invoke OpenCover elevated
Expand All @@ -500,12 +516,12 @@ function Invoke-OpenCover
runas.exe /trustlevel:0x20000 "powershell.exe -file $env:temp\unelevated.ps1"
# wait for process to start
Start-Sleep -Seconds 5
# poll for process exit every 30 seconds
# timeout of 3 hours
$timeOut = ([datetime]::Now).AddHours(3)
# poll for process exit every 60 seconds
# timeout of 6 hours
$timeOut = ([datetime]::Now).AddHours(6)
while([datetime]::Now -lt $timeOut)
{
Start-Sleep -Seconds 30
Start-Sleep -Seconds 60
$openCoverProcess = Get-Process "OpenCover.Console" -ErrorAction SilentlyContinue

if(-not $openCoverProcess)
Expand Down

0 comments on commit c7b959b

Please sign in to comment.