Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AutomatedTest - Run Pester Tests in parallel #198

Open
6 tasks
ddemeyer opened this issue Jul 5, 2024 · 0 comments
Open
6 tasks

AutomatedTest - Run Pester Tests in parallel #198

ddemeyer opened this issue Jul 5, 2024 · 0 comments

Comments

@ddemeyer
Copy link
Contributor

ddemeyer commented Jul 5, 2024

Since ISHRemote v7.0 the Pesters tests are running on Windows PowerShell 5.1 and on PowerShell 7.4+, depending the remote system they are connecting to (scaled, network, latency,...) it can take between 600s up to 1800s for a single run. In turn 1 hour on the testing alone.

Most *.Tests.ps1 Pester tests are written that they build their test data, test and remove the test data. However, some tests are on central CMS features like Xml Settings, List-of-Values, UserGroups, etc ... changing these values could cause other tests to fail sometimes.

Inspiration on

  • Add a \Source\ISHRemote\Trisoft.ISHRemote\ISHRemote.PesterSetup.Run.ps1
  • Run Serial Tests
  • Run Parallel Tests
  • Verify and adapt tests that create objects with hardcoded LogicalIds (MYOWNGENERATEDLOGICALIDMAP instead of GUIDs) should be unique per *.Tests.ps1
  • Adapt Github Actions and make sure Github Actions detects broken test results and fails the CI/CD process ... experiment by changing the 2nd (Windows PowerShell 5.1) run to AsParallel
  • Confirm that it is Faster, it does not make sense to complicate the logging and tracking if it is not 50% or more faster (imho)

Example \Source\ISHRemote\Trisoft.ISHRemote\ISHRemote.PesterSetup.Run.ps1 could be

# RWS/20240703
#Requires -Modules Pester
#Main function parameters must be the first script statement (not counting comments)
param(
    [Parameter()]
    [switch]$AsParallel,
    [Parameter()]
    [switch]$Transcript,
    [Parameter()]
    [string]$TranscriptFilePath
)
try {
    $scriptFolderPath = Split-Path -Path $PSCommandPath -Parent
    $scriptFileName = Split-Path -Path $PSCommandPath -Leaf
    if ($Transcript) {
        if (-not $TranscriptFilePath)
        { $TranscriptFilePath = Join-Path -Path $scriptFolderPath -ChildPath "$scriptFileName.log" }
        Start-Transcript -Append -Path $TranscriptFilePath
    }

    if (!$AsParallel) {
        # regular serial run
        Invoke-Pester -Output Detailed 
    } else {
        $fileInfos = Get-ChildItem *.Tests.ps1 -Recurse
        $transcript = $true
        $transcriptFolderPath = "C:\GITHUB\ISHRemote\Log"
        
        Write-Host ("Filtering out serial tests...")
        $parallelFileInfos = @()
        $serialFileInfos = @()
        foreach ($fileInfo in $fileInfos)
        {
            if ($fileInfo.Name -eq "TestPrerequisite.Tests.ps1") { <# $serialFileInfos += $fileInfo  #tests for empty __ISHRemote folder #> }
            elseif ($fileInfo.Name -like "*IshOutputFormat*") { $serialFileInfos += $fileInfo }
            elseif ($fileInfo.Name -like "*IshLovValue*") { $serialFileInfos += $fileInfo }
            elseif ($fileInfo.Name -like "*IshBackgroundTask*") { $serialFileInfos += $fileInfo }
            elseif ($fileInfo.Name -like "*IshEvent*") { $serialFileInfos += $fileInfo }
            elseif ($fileInfo.Name -like "*IshUserRole*") { $serialFileInfos += $fileInfo }
            else { $parallelFileInfos += $fileInfo }
        }
        
        # some Xml Settings tests cannot be run in parallel, so some serial some in parallel
        Write-Host ("Launching serial tests...")
        $serialResults = @()
        foreach ($fileInfo in $serialFileInfos)
        {
            $serialResults += Invoke-Pester -Output Detailed -Path ($fileInfo.FullName)
        }
        
        Write-Host ("Launching parallel test jobs...")
        foreach ($fileInfo in $parallelFileInfos)
        {
            $transcriptFilePath = Join-Path -Path $transcriptFolderPath -ChildPath ($fileInfo.Name + ".joblog")
            # Create the job, be sure to pass argument in from the ArgumentList 
            Start-Job -ArgumentList $fileInfo,$transcript,$transcriptFilePath -Name $fileInfo.Name -ScriptBlock {
            param(
                [Parameter()]
                $localFileInfo, 
                [Parameter()]
                [bool]$Transcript,
                [Parameter()]
                [string]$TranscriptFilePath
            )
                if ($Transcript) {
                    Start-Transcript -Path $TranscriptFilePath
                }
                # Run the test file
                Write-Host ("Invoke-Pester on localFileInfo.FullName["+($localFileInfo.FullName)+"]")
                $result = Invoke-Pester -Output Detailed -Path ($localFileInfo.FullName)
                if ($result.FailedCount -gt 0) {
                    throw "Start-Job calling Invoke-Pester ended with 1 or more assertions failed!"
                }
            } 
        }
        Write-Host ("Awaiting  parallel test jobs...")  # DEBUG whole poll block can be written cleaner
        # Poll to give insight into which jobs are still running so you can spot long running ones       
        do {
            Write-Host ("Polling for running jobs at["+(Get-Date -Format 'yyyyMMddHHmmss')+"]")
            Get-Job | Where-Object { $_.State -eq "Running" } | Format-Table -AutoSize 
            Start-Sleep -Seconds 5  #DEBUG
        } while ((get-job | Where-Object { $_.State -eq "Running" } | Measure-Object).Count -gt 1)
        # Catch edge cases by wait for all of them to finish
        Get-Job | Wait-Job
        
        Write-Host ("Uncompleted parallel test jobs...")
        $parallelFailedJobs = Get-Job | Where-Object { -not ($_.State -eq "Completed")}
        
        Write-Host ("Results of parallel test jobs...")
        # Receive the results of all the jobs, don't stop at errors
        Get-Job | Receive-Job -AutoRemoveJob -Wait -ErrorAction 'Continue'
        
        Write-Host ("Uncompleted parallel test jobs so throwing...")
        if ($parallelFailedJobs.Count -gt 0) {
            $parallelFailedJobs
            throw "One or more Jobs failed"
        }
        
    }

}
finally {
    if ($Transcript)
    { try { Stop-Transcript | out-null } catch {} }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant